OSDN Git Service

Import libFLAC
authorStarg <starg@users.osdn.me>
Mon, 8 Jan 2018 07:09:39 +0000 (16:09 +0900)
committerStarg <starg@users.osdn.me>
Mon, 8 Jan 2018 07:43:13 +0000 (16:43 +0900)
87 files changed:
FLAC/AUTHORS [new file with mode: 0644]
FLAC/COPYING.FDL [new file with mode: 0644]
FLAC/COPYING.GPL [new file with mode: 0644]
FLAC/COPYING.LGPL [new file with mode: 0644]
FLAC/COPYING.Xiph [new file with mode: 0644]
FLAC/README [new file with mode: 0644]
FLAC/file_decoder.h [deleted file]
FLAC/file_encoder.h [deleted file]
FLAC/include/FLAC/all.h [moved from FLAC/all.h with 99% similarity]
FLAC/include/FLAC/assert.h [moved from FLAC/assert.h with 97% similarity]
FLAC/include/FLAC/callback.h [moved from FLAC/callback.h with 99% similarity]
FLAC/include/FLAC/export.h [moved from FLAC/export.h with 96% similarity]
FLAC/include/FLAC/format.h [moved from FLAC/format.h with 99% similarity]
FLAC/include/FLAC/metadata.h [moved from FLAC/metadata.h with 99% similarity]
FLAC/include/FLAC/ordinals.h [moved from FLAC/ordinals.h with 98% similarity]
FLAC/include/FLAC/stream_decoder.h [moved from FLAC/stream_decoder.h with 99% similarity]
FLAC/include/FLAC/stream_encoder.h [moved from FLAC/stream_encoder.h with 95% similarity]
FLAC/seekable_stream_decoder.h [deleted file]
FLAC/seekable_stream_encoder.h [deleted file]
FLAC/src/bitmath.c [new file with mode: 0644]
FLAC/src/bitreader.c [new file with mode: 0644]
FLAC/src/bitwriter.c [new file with mode: 0644]
FLAC/src/cpu.c [new file with mode: 0644]
FLAC/src/crc.c [new file with mode: 0644]
FLAC/src/fixed.c [new file with mode: 0644]
FLAC/src/fixed_intrin_sse2.c [new file with mode: 0644]
FLAC/src/fixed_intrin_ssse3.c [new file with mode: 0644]
FLAC/src/float.c [new file with mode: 0644]
FLAC/src/format.c [new file with mode: 0644]
FLAC/src/lpc.c [new file with mode: 0644]
FLAC/src/lpc_intrin_avx2.c [new file with mode: 0644]
FLAC/src/lpc_intrin_sse.c [new file with mode: 0644]
FLAC/src/lpc_intrin_sse2.c [new file with mode: 0644]
FLAC/src/lpc_intrin_sse41.c [new file with mode: 0644]
FLAC/src/md5.c [new file with mode: 0644]
FLAC/src/memory.c [new file with mode: 0644]
FLAC/src/metadata_iterators.c [new file with mode: 0644]
FLAC/src/metadata_object.c [new file with mode: 0644]
FLAC/src/ogg_decoder_aspect.c [new file with mode: 0644]
FLAC/src/ogg_encoder_aspect.c [new file with mode: 0644]
FLAC/src/ogg_helper.c [new file with mode: 0644]
FLAC/src/ogg_mapping.c [new file with mode: 0644]
FLAC/src/private/all.h [new file with mode: 0644]
FLAC/src/private/bitmath.h [new file with mode: 0644]
FLAC/src/private/bitreader.h [new file with mode: 0644]
FLAC/src/private/bitwriter.h [new file with mode: 0644]
FLAC/src/private/cpu.h [new file with mode: 0644]
FLAC/src/private/crc.h [new file with mode: 0644]
FLAC/src/private/fixed.h [new file with mode: 0644]
FLAC/src/private/float.h [new file with mode: 0644]
FLAC/src/private/format.h [new file with mode: 0644]
FLAC/src/private/lpc.h [new file with mode: 0644]
FLAC/src/private/macros.h [new file with mode: 0644]
FLAC/src/private/md5.h [new file with mode: 0644]
FLAC/src/private/memory.h [new file with mode: 0644]
FLAC/src/private/metadata.h [new file with mode: 0644]
FLAC/src/private/ogg_decoder_aspect.h [new file with mode: 0644]
FLAC/src/private/ogg_encoder_aspect.h [new file with mode: 0644]
FLAC/src/private/ogg_helper.h [new file with mode: 0644]
FLAC/src/private/ogg_mapping.h [new file with mode: 0644]
FLAC/src/private/stream_encoder.h [new file with mode: 0644]
FLAC/src/private/stream_encoder_framing.h [new file with mode: 0644]
FLAC/src/private/window.h [new file with mode: 0644]
FLAC/src/protected/all.h [new file with mode: 0644]
FLAC/src/protected/stream_decoder.h [new file with mode: 0644]
FLAC/src/protected/stream_encoder.h [new file with mode: 0644]
FLAC/src/share/alloc.h [new file with mode: 0644]
FLAC/src/share/compat.h [new file with mode: 0644]
FLAC/src/share/endswap.h [new file with mode: 0644]
FLAC/src/share/getopt.h [new file with mode: 0644]
FLAC/src/share/grabbag.h [new file with mode: 0644]
FLAC/src/share/macros.h [new file with mode: 0644]
FLAC/src/share/private.h [new file with mode: 0644]
FLAC/src/share/replaygain_analysis.h [new file with mode: 0644]
FLAC/src/share/replaygain_synthesis.h [new file with mode: 0644]
FLAC/src/share/safe_str.h [new file with mode: 0644]
FLAC/src/share/utf8.h [new file with mode: 0644]
FLAC/src/share/win_utf8_io.h [new file with mode: 0644]
FLAC/src/share/windows_unicode_filenames.h [new file with mode: 0644]
FLAC/src/stream_decoder.c [new file with mode: 0644]
FLAC/src/stream_encoder.c [new file with mode: 0644]
FLAC/src/stream_encoder_framing.c [new file with mode: 0644]
FLAC/src/stream_encoder_intrin_avx2.c [new file with mode: 0644]
FLAC/src/stream_encoder_intrin_sse2.c [new file with mode: 0644]
FLAC/src/stream_encoder_intrin_ssse3.c [new file with mode: 0644]
FLAC/src/window.c [new file with mode: 0644]
FLAC/src/windows_unicode_filenames.c [new file with mode: 0644]

diff --git a/FLAC/AUTHORS b/FLAC/AUTHORS
new file mode 100644 (file)
index 0000000..8fe9092
--- /dev/null
@@ -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/FLAC/COPYING.FDL b/FLAC/COPYING.FDL
new file mode 100644 (file)
index 0000000..4a0fe1c
--- /dev/null
@@ -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/FLAC/COPYING.GPL b/FLAC/COPYING.GPL
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -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/FLAC/COPYING.LGPL b/FLAC/COPYING.LGPL
new file mode 100644 (file)
index 0000000..5ab7695
--- /dev/null
@@ -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.
+\f
+  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.
+\f
+                 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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           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/FLAC/COPYING.Xiph b/FLAC/COPYING.Xiph
new file mode 100644 (file)
index 0000000..d8295f0
--- /dev/null
@@ -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/README b/FLAC/README
new file mode 100644 (file)
index 0000000..dd5e6e7
--- /dev/null
@@ -0,0 +1,254 @@
+/* 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.2 - Contents
+===============================================================================
+
+- Introduction
+- Prerequisites
+- Note to embedded developers
+- Building in a GNU environment
+- Building with Makefile.lite
+- Building with MSVC
+- Building on Mac OS X
+
+
+===============================================================================
+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.
diff --git a/FLAC/file_decoder.h b/FLAC/file_decoder.h
deleted file mode 100644 (file)
index 3e5c721..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003  Josh Coalson
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
-
-#ifndef FLAC__FILE_DECODER_H
-#define FLAC__FILE_DECODER_H
-
-#include "export.h"
-#include "seekable_stream_decoder.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/** \file include/FLAC/file_decoder.h
- *
- *  \brief
- *  This module contains the functions which implement the file
- *  decoder.
- *
- *  See the detailed documentation in the
- *  \link flac_file_decoder file decoder \endlink module.
- */
-
-/** \defgroup flac_file_decoder FLAC/file_decoder.h: file decoder interface
- *  \ingroup flac_decoder
- *
- *  \brief
- *  This module contains the functions which implement the file
- *  decoder.
- *
- * The basic usage of this decoder is as follows:
- * - The program creates an instance of a decoder using
- *   FLAC__file_decoder_new().
- * - The program overrides the default settings and sets callbacks for
- *   writing, error reporting, and metadata reporting using
- *   FLAC__file_decoder_set_*() functions.
- * - The program initializes the instance to validate the settings and
- *   prepare for decoding using FLAC__file_decoder_init().
- * - The program calls the FLAC__file_decoder_process_*() functions
- *   to decode data, which subsequently calls the callbacks.
- * - The program finishes the decoding with FLAC__file_decoder_finish(),
- *   which flushes the input and output and resets the decoder to the
- *   uninitialized state.
- * - The instance may be used again or deleted with
- *   FLAC__file_decoder_delete().
- *
- * The file decoder is a trivial wrapper around the
- * \link flac_seekable_stream_decoder seekable stream decoder \endlink
- * meant to simplfy the process of decoding from a standard file.  The
- * file decoder supplies all but the Write/Metadata/Error callbacks.
- * The user needs only to provide the path to the file and the file
- * decoder handles the rest.
- *
- * Like the seekable stream decoder, seeking is exposed through the
- * FLAC__file_decoder_seek_absolute() method.  At any point after the file
- * decoder has been initialized, the user can call this function to seek to
- * an exact sample within the file.  Subsequently, the first time the write
- * callback is called it will be passed a (possibly partial) block starting
- * at that sample.
- *
- * The file decoder also inherits MD5 signature checking from the seekable
- * stream decoder.  If this is turned on before initialization,
- * FLAC__file_decoder_finish() will report when the decoded MD5 signature
- * does not match the one stored in the STREAMINFO block.  MD5 checking is
- * automatically turned off if there is no signature in the STREAMINFO
- * block or when a seek is attempted.
- *
- * Make sure to read the detailed descriptions of the
- * \link flac_seekable_stream_decoder seekable stream decoder module \endlink
- * and \link flac_stream_decoder stream decoder module \endlink
- * since the file decoder inherits much of its behavior from them.
- *
- * \note
- * The "set" functions may only be called when the decoder is in the
- * state FLAC__FILE_DECODER_UNINITIALIZED, i.e. after
- * FLAC__file_decoder_new() or FLAC__file_decoder_finish(), but
- * before FLAC__file_decoder_init().  If this is the case they will
- * return \c true, otherwise \c false.
- *
- * \note
- * FLAC__file_decoder_finish() resets all settings to the constructor
- * defaults, including the callbacks.
- *
- * \{
- */
-
-
-/** State values for a FLAC__FileDecoder
- *
- *  The decoder's state can be obtained by calling FLAC__file_decoder_get_state().
- */
-typedef enum {
-
-       FLAC__FILE_DECODER_OK = 0,
-       /**< The decoder is in the normal OK state. */
-
-       FLAC__FILE_DECODER_END_OF_FILE,
-       /**< The decoder has reached the end of the file. */
-
-       FLAC__FILE_DECODER_ERROR_OPENING_FILE,
-       /**< An error occurred opening the input file. */
-
-       FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR,
-       /**< An error occurred allocating memory. */
-
-       FLAC__FILE_DECODER_SEEK_ERROR,
-       /**< An error occurred while seeking. */
-
-       FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR,
-       /**< An error occurred in the underlying seekable stream decoder. */
-
-       FLAC__FILE_DECODER_ALREADY_INITIALIZED,
-       /**< FLAC__file_decoder_init() was called when the decoder was already
-        * initialized, usually because FLAC__file_decoder_finish() was not
-        * called.
-        */
-
-       FLAC__FILE_DECODER_INVALID_CALLBACK,
-       /**< FLAC__file_decoder_init() was called without all callbacks
-        * being set.
-        */
-
-       FLAC__FILE_DECODER_UNINITIALIZED
-       /**< The decoder is in the uninitialized state. */
-
-} FLAC__FileDecoderState;
-
-/** Maps a FLAC__FileDecoderState to a C string.
- *
- *  Using a FLAC__FileDecoderState as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__FileDecoderStateString[];
-
-
-/***********************************************************************
- *
- * class FLAC__FileDecoder : public FLAC__StreamDecoder
- *
- ***********************************************************************/
-
-struct FLAC__FileDecoderProtected;
-struct FLAC__FileDecoderPrivate;
-/** The opaque structure definition for the file decoder type.  See the
- *  \link flac_file_decoder file decoder module \endlink for a detailed
- *  description.
- */
-typedef struct {
-       struct FLAC__FileDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
-       struct FLAC__FileDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
-} FLAC__FileDecoder;
-
-/** Signature for the write callback.
- *  See FLAC__file_decoder_set_write_callback()
- *  and FLAC__SeekableStreamDecoderWriteCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  frame    The description of the decoded frame.
- * \param  buffer   An array of pointers to decoded channels of data.
- * \param  client_data  The callee's client data set through
- *                      FLAC__file_decoder_set_client_data().
- * \retval FLAC__StreamDecoderWriteStatus
- *    The callee's return status.
- */
-typedef FLAC__StreamDecoderWriteStatus (*FLAC__FileDecoderWriteCallback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
-
-/** Signature for the metadata callback.
- *  See FLAC__file_decoder_set_metadata_callback()
- *  and FLAC__SeekableStreamDecoderMetadataCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  metadata The decoded metadata block.
- * \param  client_data  The callee's client data set through
- *                      FLAC__file_decoder_set_client_data().
- */
-typedef void (*FLAC__FileDecoderMetadataCallback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
-
-/** Signature for the error callback.
- *  See FLAC__file_decoder_set_error_callback()
- *  and FLAC__SeekableStreamDecoderErrorCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  status   The error encountered by the decoder.
- * \param  client_data  The callee's client data set through
- *                      FLAC__file_decoder_set_client_data().
- */
-typedef void (*FLAC__FileDecoderErrorCallback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
-
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-/** Create a new file decoder instance.  The instance is created with
- *  default settings; see the individual FLAC__file_decoder_set_*()
- *  functions for each setting's default.
- *
- * \retval FLAC__FileDecoder*
- *    \c NULL if there was an error allocating memory, else the new instance.
- */
-FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new();
-
-/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
- *
- * \param decoder  A pointer to an existing decoder.
- * \assert
- *    \code decoder != NULL \endcode
- */
-FLAC_API void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder);
-
-
-/***********************************************************************
- *
- * Public class method prototypes
- *
- ***********************************************************************/
-
-/** Set the "MD5 signature checking" flag.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_md5_checking().
- *
- * \default \c false
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value);
-
-/** Set the input file name to decode.
- *
- * \default \c "-"
- * \param  decoder  A decoder instance to set.
- * \param  value    The input file name, or "-" for \c stdin.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, or there was a memory
- *    allocation error, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value);
-
-/** Set the write callback.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_write_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value);
-
-/** Set the metadata callback.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value);
-
-/** Set the error callback.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_error_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value);
-
-/** Set the client data to be passed back to callbacks.
- *  This value will be supplied to callbacks in their \a client_data
- *  argument.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_respond().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  type     See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \a type is valid
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_respond_application().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  id       See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code id != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_respond_all().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_ignore().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  type     See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \a type is valid
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_ignore_application().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  id       See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code id != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_set_metadata_ignore_all().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder);
-
-/** Get the current decoder state.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__FileDecoderState
- *    The current decoder state.
- */
-FLAC_API FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder);
-
-/** Get the state of the underlying seekable stream decoder.
- *  Useful when the file decoder state is
- *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__SeekableStreamDecoderState
- *    The seekable stream decoder state.
- */
-FLAC_API FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder);
-
-/** Get the state of the underlying stream decoder.
- *  Useful when the file decoder state is
- *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR and the seekable stream
- *  decoder state is \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__StreamDecoderState
- *    The seekable stream decoder state.
- */
-FLAC_API FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder);
-
-/** Get the current decoder state as a C string.
- *  This version automatically resolves
- *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR by getting the
- *  seekable stream decoder's state.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval const char *
- *    The decoder state as a C string.  Do not modify the contents.
- */
-FLAC_API const char *FLAC__file_decoder_get_resolved_state_string(const FLAC__FileDecoder *decoder);
-
-/** Get the "MD5 signature checking" flag.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_md5_checking().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_channels().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_channel_assignment().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__ChannelAssignment
- *    See above.
- */
-FLAC_API FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_bits_per_sample().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_sample_rate().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_blocksize().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_get_decode_position().
- *
- * \param  decoder   A decoder instance to query.
- * \param  position  Address at which to return the desired position.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code position != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, \c false if there was an error from
- *    the 'tell' callback.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position);
-
-/** Initialize the decoder instance.
- *  Should be called after FLAC__file_decoder_new() and
- *  FLAC__file_decoder_set_*() but before any of the
- *  FLAC__file_decoder_process_*() functions.  Will set and return
- *  the decoder state, which will be FLAC__FILE_DECODER_OK if
- *  initialization succeeded.
- *
- * \param  decoder  An uninitialized decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__FileDecoderState
- *    \c FLAC__FILE_DECODER_OK if initialization was successful; see
- *    FLAC__FileDecoderState for the meanings of other return values.
- */
-FLAC_API FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder);
-
-/** Finish the decoding process.
- *  Flushes the decoding buffer, releases resources, resets the decoder
- *  settings to their defaults, and returns the decoder state to
- *  FLAC__FILE_DECODER_UNINITIALIZED.
- *
- *  In the event of a prematurely-terminated decode, it is not strictly
- *  necessary to call this immediately before FLAC__file_decoder_delete()
- *  but it is good practice to match every FLAC__file_decoder_init() with
- *  a FLAC__file_decoder_finish().
- *
- * \param  decoder  An uninitialized decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if MD5 checking is on AND a STREAMINFO block was available
- *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
- *    signature does not match the one computed by the decoder; else
- *    \c true.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_process_single().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_process_until_end_of_metadata().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_process_until_end_of_stream().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder);
-
-/** This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_process_remaining_frames().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder);
-
-/** Flush the input and seek to an absolute sample.
- *  This is inherited from FLAC__SeekableStreamDecoder; see
- *  FLAC__seekable_stream_decoder_seek_absolute().
- *
- * \param  decoder  A decoder instance.
- * \param  sample   The target sample number to seek to.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false.
- */
-FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample);
-
-/* \} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/FLAC/file_encoder.h b/FLAC/file_encoder.h
deleted file mode 100644 (file)
index ac222fe..0000000
+++ /dev/null
@@ -1,859 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2002,2003  Josh Coalson
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
-
-#ifndef FLAC__FILE_ENCODER_H
-#define FLAC__FILE_ENCODER_H
-
-#include "export.h"
-#include "seekable_stream_encoder.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/** \file include/FLAC/file_encoder.h
- *
- *  \brief
- *  This module contains the functions which implement the file
- *  encoder.
- *
- *  See the detailed documentation in the
- *  \link flac_file_encoder file encoder \endlink module.
- */
-
-/** \defgroup flac_file_encoder FLAC/file_encoder.h: file encoder interface
- *  \ingroup flac_encoder
- *
- *  \brief
- *  This module contains the functions which implement the file
- *  encoder.
- *
- * The basic usage of this encoder is as follows:
- * - The program creates an instance of an encoder using
- *   FLAC__file_encoder_new().
- * - The program overrides the default settings using
- *   FLAC__file_encoder_set_*() functions.
- * - The program initializes the instance to validate the settings and
- *   prepare for encoding using FLAC__file_encoder_init().
- * - The program calls FLAC__file_encoder_process() or
- *   FLAC__file_encoder_process_interleaved() to encode data, which
- *   subsequently writes data to the output file.
- * - The program finishes the encoding with FLAC__file_encoder_finish(),
- *   which causes the encoder to encode any data still in its input pipe,
- *   rewind and write the STREAMINFO metadata to file, and finally reset
- *   the encoder to the uninitialized state.
- * - The instance may be used again or deleted with
- *   FLAC__file_encoder_delete().
- *
- * The file encoder is a wrapper around the
- * \link flac_seekable_stream_encoder seekable stream encoder \endlink which supplies all
- * callbacks internally; the user need specify only the filename.
- *
- * Make sure to read the detailed description of the
- * \link flac_seekable_stream_encoder seekable stream encoder module \endlink since the
- * \link flac_stream_encoder stream encoder module \endlink since the
- * file encoder inherits much of its behavior from them.
- *
- * \note
- * The "set" functions may only be called when the encoder is in the
- * state FLAC__FILE_ENCODER_UNINITIALIZED, i.e. after
- * FLAC__file_encoder_new() or FLAC__file_encoder_finish(), but
- * before FLAC__file_encoder_init().  If this is the case they will
- * return \c true, otherwise \c false.
- *
- * \note
- * FLAC__file_encoder_finish() resets all settings to the constructor
- * defaults.
- *
- * \{
- */
-
-
-/** State values for a FLAC__FileEncoder
- *
- *  The encoder's state can be obtained by calling FLAC__file_encoder_get_state().
- */
-typedef enum {
-
-       FLAC__FILE_ENCODER_OK = 0,
-       /**< The encoder is in the normal OK state. */
-
-       FLAC__FILE_ENCODER_NO_FILENAME,
-       /**< FLAC__file_encoder_init() was called without first calling
-        * FLAC__file_encoder_set_filename().
-        */
-
-       FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR,
-       /**< An error occurred in the underlying seekable stream encoder;
-        * check FLAC__file_encoder_get_seekable_stream_encoder_state().
-        */
-
-       FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING,
-       /**< A fatal error occurred while writing to the encoded file. */
-
-       FLAC__FILE_ENCODER_ERROR_OPENING_FILE,
-       /**< An error occurred opening the output file for writing. */
-
-       FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR,
-       /**< Memory allocation failed. */
-
-       FLAC__FILE_ENCODER_ALREADY_INITIALIZED,
-       /**< FLAC__file_encoder_init() was called when the encoder was
-        * already initialized, usually because
-        * FLAC__file_encoder_finish() was not called.
-        */
-
-       FLAC__FILE_ENCODER_UNINITIALIZED
-       /**< The encoder is in the uninitialized state. */
-
-} FLAC__FileEncoderState;
-
-/** Maps a FLAC__FileEncoderState to a C string.
- *
- *  Using a FLAC__FileEncoderState as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__FileEncoderStateString[];
-
-
-/***********************************************************************
- *
- * class FLAC__FileEncoder
- *
- ***********************************************************************/
-
-struct FLAC__FileEncoderProtected;
-struct FLAC__FileEncoderPrivate;
-/** The opaque structure definition for the file encoder type.
- *  See the \link flac_file_encoder file encoder module \endlink
- *  for a detailed description.
- */
-typedef struct {
-       struct FLAC__FileEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
-       struct FLAC__FileEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
-} FLAC__FileEncoder;
-
-/** Signature for the progress callback.
- *  See FLAC__file_encoder_set_progress_callback() for more info.
- *
- * \param  encoder          The encoder instance calling the callback.
- * \param  bytes_written    Bytes written so far.
- * \param  samples_written  Samples written so far.
- * \param  frames_written   Frames written so far.
- * \param  total_frames_estimate  The estimate of the total number of
- *                                frames to be written.
- * \param  client_data      The callee's client data set through
- *                          FLAC__file_encoder_set_client_data().
- */
-typedef void (*FLAC__FileEncoderProgressCallback)(const FLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
-
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-/** Create a new file encoder instance.  The instance is created with
- *  default settings; see the individual FLAC__file_encoder_set_*()
- *  functions for each setting's default.
- *
- * \retval FLAC__FileEncoder*
- *    \c NULL if there was an error allocating memory, else the new instance.
- */
-FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new();
-
-/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
- *
- * \param encoder  A pointer to an existing encoder.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder);
-
-/***********************************************************************
- *
- * Public class method prototypes
- *
- ***********************************************************************/
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_verify().
- *
- * \default \c true
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_streamable_subset().
- *
- * \default \c true
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_do_mid_side_stereo().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_channels().
- *
- * \default \c 2
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_bits_per_sample().
- *
- * \warning
- * Do not feed the encoder data that is wider than the value you
- * set here or you will generate an invalid stream.
- *
- * \default \c 16
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_sample_rate().
- *
- * \default \c 44100
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_blocksize().
- *
- * \default \c 1152
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_max_lpc_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_qlp_coeff_precision().
- *
- * \note
- * In the current implementation, qlp_coeff_precision + bits_per_sample must
- * be less than 32.
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_do_escape_coding().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_min_residual_partition_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_max_residual_partition_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_total_samples_estimate().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value);
-
-/** This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_set_metadata().
- *
- * \default \c NULL, 0
- * \param  encoder     An encoder instance to set.
- * \param  metadata    See above.
- * \param  num_blocks  See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
-
-/** Set the output file name encode to.
- *
- * \note
- * The filename is mandatory and must be set before initialization.
- *
- * \note
- * Unlike the FLAC__FileDecoder, the filename does not interpret "-" for
- * \c stdout; writing to \c stdout is not relevant in the file encoder.
- *
- * \default \c NULL
- * \param  encoder  A encoder instance to set.
- * \param  value    The output file name.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, or there was a memory
- *    allocation error, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value);
-
-/** Set the progress callback.
- *  The supplied function will be called when the encoder has finished
- *  writing a frame.  The \c total_frames_estimate argument to the callback
- *  will be based on the value from
- *  FLAC__file_encoder_set_total_samples_estimate().
- *
- * \note
- * Unlike most other callbacks, the progress callback is \b not mandatory
- * and need not be set before initialization.
- *
- * \default \c NULL
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value);
-
-/** Set the client data to be passed back to callbacks.
- *  This value will be supplied to callbacks in their \a client_data
- *  argument.
- *
- * \default \c NULL
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value);
-
-/** Get the current encoder state.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__FileEncoderState
- *    The current encoder state.
- */
-FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder);
-
-/** Get the state of the underlying seekable stream encoder.
- *  Useful when the file encoder state is
- *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__SeekableStreamEncoderState
- *    The seekable stream encoder state.
- */
-FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder);
-
-/** Get the state of the underlying stream encoder.
- *  Useful when the file encoder state is
- *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
- *  encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__StreamEncoderState
- *    The seekable stream encoder state.
- */
-FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder);
-
-/** Get the state of the underlying stream encoder's verify decoder.
- *  Useful when the file encoder state is
- *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
- *  encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and
- *  the stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__StreamDecoderState
- *    The stream encoder state.
- */
-FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder);
-
-/** Get the current encoder state as a C string.
- *  This version automatically resolves
- *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR by getting the
- *  seekable stream encoder's state.
- *
- * \param  encoder  A encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval const char *
- *    The encoder state as a C string.  Do not modify the contents.
- */
-FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder);
-
-/** Get relevant values about the nature of a verify decoder error.
- *  Inherited from FLAC__seekable_stream_encoder_get_verify_decoder_error_stats().
- *  Useful when the file encoder state is
- *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
- *  encoder state is
- *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
- *  stream encoder state is
- *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \param  absolute_sample  The absolute sample number of the mismatch.
- * \param  frame_number  The number of the frame in which the mismatch occurred.
- * \param  channel       The channel in which the mismatch occurred.
- * \param  sample        The number of the sample (relative to the frame) in
- *                       which the mismatch occurred.
- * \param  expected      The expected value for the sample in question.
- * \param  got           The actual value returned by the decoder.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
-
-/** Get the "verify" flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_verify().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_verify().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder);
-
-/** Get the "streamable subset" flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_streamable_subset().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_streamable_subset().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder);
-
-/** Get the "mid/side stereo coding" flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_do_mid_side_stereo().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_get_do_mid_side_stereo().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder);
-
-/** Get the "adaptive mid/side switching" flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_loose_mid_side_stereo().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_loose_mid_side_stereo().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder);
-
-/** Get the number of input channels being processed.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_channels().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_channels().
- */
-FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder);
-
-/** Get the input sample resolution setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_bits_per_sample().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_bits_per_sample().
- */
-FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder);
-
-/** Get the input sample rate setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_sample_rate().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_sample_rate().
- */
-FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder);
-
-/** Get the blocksize setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_blocksize().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_blocksize().
- */
-FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder);
-
-/** Get the maximum LPC order setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_max_lpc_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_max_lpc_order().
- */
-FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder);
-
-/** Get the quantized linear predictor coefficient precision setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_qlp_coeff_precision().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_qlp_coeff_precision().
- */
-FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder);
-
-/** Get the qlp coefficient precision search flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_do_qlp_coeff_prec_search().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder);
-
-/** Get the "escape coding" flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_do_escape_coding().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_do_escape_coding().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder);
-
-/** Get the exhaustive model search flag.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_do_exhaustive_model_search().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__file_encoder_set_do_exhaustive_model_search().
- */
-FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder);
-
-/** Get the minimum residual partition order setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_min_residual_partition_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_min_residual_partition_order().
- */
-FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder);
-
-/** Get maximum residual partition order setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_max_residual_partition_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_max_residual_partition_order().
- */
-FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder);
-
-/** Get the Rice parameter search distance setting.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_rice_parameter_search_dist().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__file_encoder_set_rice_parameter_search_dist().
- */
-FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder);
-
-/** Get the previously set estimate of the total samples to be encoded.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_get_total_samples_estimate().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__uint64
- *    See FLAC__file_encoder_set_total_samples_estimate().
- */
-FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder);
-
-/** Initialize the encoder instance.
- *  Should be called after FLAC__file_encoder_new() and
- *  FLAC__file_encoder_set_*() but before FLAC__file_encoder_process()
- *  or FLAC__file_encoder_process_interleaved().  Will set and return
- *  the encoder state, which will be FLAC__FILE_ENCODER_OK if
- *  initialization succeeded.
- *
- * \param  encoder  An uninitialized encoder instance.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__FileEncoderState
- *    \c FLAC__FILE_ENCODER_OK if initialization was successful; see
- *    FLAC__FileEncoderState for the meanings of other return values.
- */
-FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder);
-
-/** Finish the encoding process.
- *  Flushes the encoding buffer, releases resources, resets the encoder
- *  settings to their defaults, and returns the encoder state to
- *  FLAC__FILE_ENCODER_UNINITIALIZED.
- *
- *  In the event of a prematurely-terminated encode, it is not strictly
- *  necessary to call this immediately before FLAC__file_encoder_delete()
- *  but it is good practice to match every FLAC__file_encoder_init()
- *  with a FLAC__file_encoder_finish().
- *
- * \param  encoder  An uninitialized encoder instance.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder);
-
-/** Submit data for encoding.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_process().
- *
- * \param  encoder  An initialized encoder instance in the OK state.
- * \param  buffer   An array of pointers to each channel's signal.
- * \param  samples  The number of samples in one channel.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false; in this case, check the
- *    encoder state with FLAC__file_encoder_get_state() to see what
- *    went wrong.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
-
-/** Submit data for encoding.
- *  This is inherited from FLAC__SeekableStreamEncoder; see
- *  FLAC__seekable_stream_encoder_process_interleaved().
- *
- * \param  encoder  An initialized encoder instance in the OK state.
- * \param  buffer   An array of channel-interleaved data (see above).
- * \param  samples  The number of samples in one channel, the same as for
- *                  FLAC__file_encoder_process().  For example, if
- *                  encoding two channels, \c 1000 \a samples corresponds
- *                  to a \a buffer of 2000 values.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false; in this case, check the
- *    encoder state with FLAC__file_encoder_get_state() to see what
- *    went wrong.
- */
-FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
-
-/* \} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
similarity index 99%
rename from FLAC/all.h
rename to FLAC/include/FLAC/all.h
index 9e28852..11d47d7 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
  * #endif
  * \endcode
  *
- * The the source will work for multiple versions and the legacy code can
+ * The source will work for multiple versions and the legacy code can
  * easily be removed when the transition is complete.
  *
  * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
similarity index 97%
rename from FLAC/assert.h
rename to FLAC/include/FLAC/assert.h
index 787cea9..b546fd0 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
similarity index 99%
rename from FLAC/callback.h
rename to FLAC/include/FLAC/callback.h
index 71bbaec..f942dd2 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
similarity index 96%
rename from FLAC/export.h
rename to FLAC/include/FLAC/export.h
index 2232b41..d52f0bb 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
@@ -61,9 +61,9 @@
 
 #elif defined(_MSC_VER)
 #ifdef FLAC_API_EXPORTS
-#define        FLAC_API        _declspec(dllexport)
+#define        FLAC_API __declspec(dllexport)
 #else
-#define FLAC_API       _declspec(dllimport)
+#define FLAC_API __declspec(dllimport)
 #endif
 
 #elif defined(FLAC__USE_VISIBILITY_ATTR)
similarity index 99%
rename from FLAC/format.h
rename to FLAC/include/FLAC/format.h
index e4c1c1a..c087d4a 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
@@ -509,9 +509,11 @@ typedef enum {
        FLAC__METADATA_TYPE_PICTURE = 6,
        /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
 
-       FLAC__METADATA_TYPE_UNDEFINED = 7
+       FLAC__METADATA_TYPE_UNDEFINED = 7,
        /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
 
+       FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
+       /**< No type will ever be greater than this. There is not enough room in the protocol block. */
 } FLAC__MetadataType;
 
 /** Maps a FLAC__MetadataType to a C string.
similarity index 99%
rename from FLAC/metadata.h
rename to FLAC/include/FLAC/metadata.h
index fcc8ed9..4e18cd6 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
@@ -500,7 +500,7 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const
  * \retval unsigned
  *    The length of the metadata block at the current iterator position.
  *    The is same length as that in the
- *    <a href="http://flac.sourceforge.net/format.html#metadata_block_header">metadata block header</a>,
+ *    <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);
@@ -667,7 +667,7 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S
  *
  * - Create a new chain using FLAC__metadata_chain_new().  A chain is a
  *   linked list of FLAC metadata blocks.
- * - Read all metadata into the the chain from a FLAC file using
+ * - Read all metadata into the chain from a FLAC file using
  *   FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
  *   check the status.
  * - Optionally, consolidate the padding using
@@ -764,7 +764,7 @@ typedef enum {
        FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
        /**< FLAC__metadata_chain_write() was called on a chain read by
         *   FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
-        *   or 
+        *   or
         *   FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
         *   was called on a chain read by
         *   FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
@@ -1692,7 +1692,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__Str
  *  For convenience, a trailing NUL is added to the entry if it doesn't have
  *  one already.
  *
- *  Depending on the the value of \a all, either all or just the first comment
+ *  Depending on the value of \a all, either all or just the first comment
  *  whose field name(s) match the given entry's name will be replaced by the
  *  given entry.  If no comments match, \a entry will simply be appended.
  *
similarity index 98%
rename from FLAC/ordinals.h
rename to FLAC/include/FLAC/ordinals.h
index a057299..ea52ea6 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
similarity index 99%
rename from FLAC/stream_decoder.h
rename to FLAC/include/FLAC/stream_decoder.h
index 152643f..39c958d 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
@@ -228,7 +228,7 @@ typedef enum {
         */
 
        FLAC__STREAM_DECODER_ABORTED,
-       /**< The decoder was aborted by the read callback. */
+       /**< The decoder was aborted by the read or write callback. */
 
        FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
        /**< An error occurred allocating memory.  The decoder is in an invalid
similarity index 95%
rename from FLAC/stream_encoder.h
rename to FLAC/include/FLAC/stream_encoder.h
index 6f7796b..40a2fd3 100644 (file)
@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2013  Xiph.Org Foundation
+ * 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
@@ -830,28 +830,28 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en
  * The actual values set for each level are:
  * <table>
  * <tr>
- *  <td><b>level</b><td>
- *  <td>do mid-side stereo<td>
- *  <td>loose mid-side stereo<td>
- *  <td>apodization<td>
- *  <td>max lpc order<td>
- *  <td>qlp coeff precision<td>
- *  <td>qlp coeff prec search<td>
- *  <td>escape coding<td>
- *  <td>exhaustive model search<td>
- *  <td>min residual partition order<td>
- *  <td>max residual partition order<td>
- *  <td>rice parameter search dist<td>
+ *  <td><b>level</b></td>
+ *  <td>do mid-side stereo</td>
+ *  <td>loose mid-side stereo</td>
+ *  <td>apodization</td>
+ *  <td>max lpc order</td>
+ *  <td>qlp coeff precision</td>
+ *  <td>qlp coeff prec search</td>
+ *  <td>escape coding</td>
+ *  <td>exhaustive model search</td>
+ *  <td>min residual partition order</td>
+ *  <td>max residual partition order</td>
+ *  <td>rice parameter search dist</td>
  * </tr>
- * <tr>  <td><b>0</b><td>  <td>false<td>  <td>false<td>  <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
- * <tr>  <td><b>1</b><td>  <td>true<td>   <td>true<td>   <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
- * <tr>  <td><b>2</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>0<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>3<td>  <td>0<td>  </tr>
- * <tr>  <td><b>3</b><td>  <td>false<td>  <td>false<td>  <td>tukey(0.5)<td>  <td>6<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>4<td>  <td>0<td>  </tr>
- * <tr>  <td><b>4</b><td>  <td>true<td>   <td>true<td>   <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>4<td>  <td>0<td>  </tr>
- * <tr>  <td><b>5</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>5<td>  <td>0<td>  </tr>
- * <tr>  <td><b>6</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>false<td>  <td>0<td>  <td>6<td>  <td>0<td>  </tr>
- * <tr>  <td><b>7</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>8<td>   <td>0<td>  <td>false<td>  <td>false<td>  <td>true<td>   <td>0<td>  <td>6<td>  <td>0<td>  </tr>
- * <tr>  <td><b>8</b><td>  <td>true<td>   <td>false<td>  <td>tukey(0.5)<td>  <td>12<td>  <td>0<td>  <td>false<td>  <td>false<td>  <td>true<td>   <td>0<td>  <td>6<td>  <td>0<td>  </tr>
+ * <tr>  <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>1</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>2</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>6</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>4</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>5</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
+ * <tr>  <td><b>6</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>7</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>8</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
  * </table>
  *
  * \default \c 5
@@ -920,7 +920,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * The available functions are \c bartlett, \c bartlett_hann,
  * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
  * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
- * \c rectangle, \c triangle, \c tukey(P), \c welch.
+ * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]),
+ * \c punchout_tukey(n[/ov[/P]]), \c welch.
  *
  * For \c gauss(STDDEV), STDDEV specifies the standard deviation
  * (0<STDDEV<=0.5).
@@ -929,6 +930,24 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * tapered (0<=P<=1).  P=0 corresponds to \c rectangle and P=1
  * corresponds to \c hann.
  *
+ * Specifying \c partial_tukey or \c punchout_tukey works a little
+ * different. These do not specify a single apodization function, but
+ * a series of them with some overlap. partial_tukey specifies a series
+ * of small windows (all treated separately) while punchout_tukey
+ * specifies a series of windows that have a hole in them. In this way,
+ * the predictor is constructed with only a part of the block, which
+ * helps in case a block consists of dissimilar parts.
+ *
+ * The three parameters that can be specified for the functions are
+ * n, ov and P. n is the number of functions to add, ov is the overlap
+ * of the windows in case of partial_tukey and the overlap in the gaps
+ * in case of punchout_tukey. P is the fraction of the window that is
+ * tapered, like with a regular tukey window. The function can be
+ * specified with only a number, a number and an overlap, or a number
+ * an overlap and a P, for example, partial_tukey(3), partial_tukey(3/0.3)
+ * and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1
+ * and can be negative.
+ *
  * Example specifications are \c "blackman" or
  * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
  *
@@ -941,7 +960,9 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * results in the smallest compressed subframe.
  *
  * Note that each function specified causes the encoder to occupy a
- * floating point array in which to store the window.
+ * floating point array in which to store the window. Also note that the
+ * values of P, STDDEV and ov are locale-specific, so if the comma
+ * separator specified by the locale is a comma, a comma should be used.
  *
  * \default \c "tukey(0.5)"
  * \param  encoder        An encoder instance to set.
diff --git a/FLAC/seekable_stream_decoder.h b/FLAC/seekable_stream_decoder.h
deleted file mode 100644 (file)
index 864e9b6..0000000
+++ /dev/null
@@ -1,908 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003  Josh Coalson
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
-
-#ifndef FLAC__SEEKABLE_STREAM_DECODER_H
-#define FLAC__SEEKABLE_STREAM_DECODER_H
-
-#include "export.h"
-#include "stream_decoder.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/** \file include/FLAC/seekable_stream_decoder.h
- *
- *  \brief
- *  This module contains the functions which implement the seekable stream
- *  decoder.
- *
- *  See the detailed documentation in the
- *  \link flac_seekable_stream_decoder seekable stream decoder \endlink module.
- */
-
-/** \defgroup flac_seekable_stream_decoder FLAC/seekable_stream_decoder.h: seekable stream decoder interface
- *  \ingroup flac_decoder
- *
- *  \brief
- *  This module contains the functions which implement the seekable stream
- *  decoder.
- *
- * The basic usage of this decoder is as follows:
- * - The program creates an instance of a decoder using
- *   FLAC__seekable_stream_decoder_new().
- * - The program overrides the default settings and sets callbacks for
- *   reading, writing, seeking, error reporting, and metadata reporting
- *   using FLAC__seekable_stream_decoder_set_*() functions.
- * - The program initializes the instance to validate the settings and
- *   prepare for decoding using FLAC__seekable_stream_decoder_init().
- * - The program calls the FLAC__seekable_stream_decoder_process_*()
- *   functions to decode data, which subsequently calls the callbacks.
- * - The program finishes the decoding with
- *   FLAC__seekable_stream_decoder_finish(), which flushes the input and
- *   output and resets the decoder to the uninitialized state.
- * - The instance may be used again or deleted with
- *   FLAC__seekable_stream_decoder_delete().
- *
- * The seekable stream decoder is a wrapper around the
- * \link flac_stream_decoder stream decoder \endlink which also provides
- * seeking capability.  In addition to the Read/Write/Metadata/Error
- * callbacks of the stream decoder, the user must also provide the following:
- *
- * - Seek callback - This function will be called when the decoder wants to
- *   seek to an absolute position in the stream.
- * - Tell callback - This function will be called when the decoder wants to
- *   know the current absolute position of the stream.
- * - Length callback - This function will be called when the decoder wants
- *   to know length of the stream.  The seeking algorithm currently requires
- *   that the overall stream length be known.
- * - EOF callback - This function will be called when the decoder wants to
- *   know if it is at the end of the stream.  This could be synthesized from
- *   the tell and length callbacks but it may be more expensive that way, so
- *   there is a separate callback for it.
- *
- * Seeking is exposed through the
- * FLAC__seekable_stream_decoder_seek_absolute() method.  At any point after
- * the seekable stream decoder has been initialized, the user can call this
- * function to seek to an exact sample within the stream.  Subsequently, the
- * first time the write callback is called it will be passed a (possibly
- * partial) block starting at that sample.
- *
- * The seekable stream decoder also provides MD5 signature checking.  If
- * this is turned on before initialization,
- * FLAC__seekable_stream_decoder_finish() will report when the decoded MD5
- * signature does not match the one stored in the STREAMINFO block.  MD5
- * checking is automatically turned off (until the next
- * FLAC__seekable_stream_decoder_reset()) if there is no signature in the
- * STREAMINFO block or when a seek is attempted.
- *
- * Make sure to read the detailed description of the
- * \link flac_stream_decoder stream decoder module \endlink since the
- * seekable stream decoder inherits much of its behavior.
- *
- * \note
- * The "set" functions may only be called when the decoder is in the
- * state FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED, i.e. after
- * FLAC__seekable_stream_decoder_new() or
- * FLAC__seekable_stream_decoder_finish(), but before
- * FLAC__seekable_stream_decoder_init().  If this is the case they will
- * return \c true, otherwise \c false.
- *
- * \note
- * FLAC__stream_decoder_finish() resets all settings to the constructor
- * defaults, including the callbacks.
- *
- * \{
- */
-
-
-/** State values for a FLAC__SeekableStreamDecoder
- *
- *  The decoder's state can be obtained by calling FLAC__seekable_stream_decoder_get_state().
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_DECODER_OK = 0,
-       /**< The decoder is in the normal OK state. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_SEEKING,
-       /**< The decoder is in the process of seeking. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM,
-       /**< The decoder has reached the end of the stream. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
-       /**< An error occurred allocating memory. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR,
-       /**< An error occurred in the underlying stream decoder. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR,
-       /**< The read callback returned an error. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR,
-       /**< An error occurred while seeking or the seek or tell
-        * callback returned an error.
-        */
-
-       FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED,
-       /**< FLAC__seekable_stream_decoder_init() was called when the
-        * decoder was already initialized, usually because
-        * FLAC__seekable_stream_decoder_finish() was not called.
-        */
-
-       FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK,
-       /**< FLAC__seekable_stream_decoder_init() was called without all
-        * callbacks being set.
-        */
-
-       FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED
-       /**< The decoder is in the uninitialized state. */
-
-} FLAC__SeekableStreamDecoderState;
-
-/** Maps a FLAC__SeekableStreamDecoderState to a C string.
- *
- *  Using a FLAC__SeekableStreamDecoderState as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamDecoderStateString[];
-
-
-/** Return values for the FLAC__SeekableStreamDecoder read callback.
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK,
-       /**< The read was OK and decoding can continue. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR
-       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
-
-} FLAC__SeekableStreamDecoderReadStatus;
-
-/** Maps a FLAC__SeekableStreamDecoderReadStatus to a C string.
- *
- *  Using a FLAC__SeekableStreamDecoderReadStatus as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamDecoderReadStatusString[];
-
-
-/** Return values for the FLAC__SeekableStreamDecoder seek callback.
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK,
-       /**< The seek was OK and decoding can continue. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
-       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
-
-} FLAC__SeekableStreamDecoderSeekStatus;
-
-/** Maps a FLAC__SeekableStreamDecoderSeekStatus to a C string.
- *
- *  Using a FLAC__SeekableStreamDecoderSeekStatus as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamDecoderSeekStatusString[];
-
-
-/** Return values for the FLAC__SeekableStreamDecoder tell callback.
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK,
-       /**< The tell was OK and decoding can continue. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
-       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
-
-} FLAC__SeekableStreamDecoderTellStatus;
-
-/** Maps a FLAC__SeekableStreamDecoderTellStatus to a C string.
- *
- *  Using a FLAC__SeekableStreamDecoderTellStatus as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamDecoderTellStatusString[];
-
-
-/** Return values for the FLAC__SeekableStreamDecoder length callback.
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK,
-       /**< The length call was OK and decoding can continue. */
-
-       FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
-       /**< An unrecoverable error occurred.  The decoder will return from the process call. */
-
-} FLAC__SeekableStreamDecoderLengthStatus;
-
-/** Maps a FLAC__SeekableStreamDecoderLengthStatus to a C string.
- *
- *  Using a FLAC__SeekableStreamDecoderLengthStatus as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamDecoderLengthStatusString[];
-
-
-/***********************************************************************
- *
- * class FLAC__SeekableStreamDecoder : public FLAC__StreamDecoder
- *
- ***********************************************************************/
-
-struct FLAC__SeekableStreamDecoderProtected;
-struct FLAC__SeekableStreamDecoderPrivate;
-/** The opaque structure definition for the seekable stream decoder type.
- *  See the
- *  \link flac_seekable_stream_decoder seekable stream decoder module \endlink
- *  for a detailed description.
- */
-typedef struct {
-       struct FLAC__SeekableStreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
-       struct FLAC__SeekableStreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
-} FLAC__SeekableStreamDecoder;
-
-/** Signature for the read callback.
- *  See FLAC__seekable_stream_decoder_set_read_callback()
- *  and FLAC__StreamDecoderReadCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  buffer   A pointer to a location for the callee to store
- *                  data to be decoded.
- * \param  bytes    A pointer to the size of the buffer.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__SeekableStreamDecoderReadStatus
- *    The callee's return status.
- */
-typedef FLAC__SeekableStreamDecoderReadStatus (*FLAC__SeekableStreamDecoderReadCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
-
-/** Signature for the seek callback.
- *  See FLAC__seekable_stream_decoder_set_seek_callback() for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  absolute_byte_offset  The offset from the beginning of the stream
- *                               to seek to.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__SeekableStreamDecoderSeekStatus
- *    The callee's return status.
- */
-typedef FLAC__SeekableStreamDecoderSeekStatus (*FLAC__SeekableStreamDecoderSeekCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
-
-/** Signature for the tell callback.
- *  See FLAC__seekable_stream_decoder_set_tell_callback() for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  absolute_byte_offset  A pointer to storage for the current offset
- *                               from the beginning of the stream.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__SeekableStreamDecoderTellStatus
- *    The callee's return status.
- */
-typedef FLAC__SeekableStreamDecoderTellStatus (*FLAC__SeekableStreamDecoderTellCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
-
-/** Signature for the length callback.
- *  See FLAC__seekable_stream_decoder_set_length_callback() for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  stream_length  A pointer to storage for the length of the stream
- *                        in bytes.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__SeekableStreamDecoderLengthStatus
- *    The callee's return status.
- */
-typedef FLAC__SeekableStreamDecoderLengthStatus (*FLAC__SeekableStreamDecoderLengthCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
-
-/** Signature for the EOF callback.
- *  See FLAC__seekable_stream_decoder_set_eof_callback() for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__bool
- *    \c true if the currently at the end of the stream, else \c false.
- */
-typedef FLAC__bool (*FLAC__SeekableStreamDecoderEofCallback)(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
-
-/** Signature for the write callback.
- *  See FLAC__seekable_stream_decoder_set_write_callback()
- *  and FLAC__StreamDecoderWriteCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  frame    The description of the decoded frame.
- * \param  buffer   An array of pointers to decoded channels of data.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- * \retval FLAC__StreamDecoderWriteStatus
- *    The callee's return status.
- */
-typedef FLAC__StreamDecoderWriteStatus (*FLAC__SeekableStreamDecoderWriteCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
-
-/** Signature for the metadata callback.
- *  See FLAC__seekable_stream_decoder_set_metadata_callback()
- *  and FLAC__StreamDecoderMetadataCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  metadata The decoded metadata block.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- */
-typedef void (*FLAC__SeekableStreamDecoderMetadataCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
-
-/** Signature for the error callback.
- *  See FLAC__seekable_stream_decoder_set_error_callback()
- *  and FLAC__StreamDecoderErrorCallback for more info.
- *
- * \param  decoder  The decoder instance calling the callback.
- * \param  status   The error encountered by the decoder.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_decoder_set_client_data().
- */
-typedef void (*FLAC__SeekableStreamDecoderErrorCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
-
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-/** Create a new seekable stream decoder instance.  The instance is created
- *  with default settings; see the individual
- *  FLAC__seekable_stream_decoder_set_*() functions for each setting's
- *  default.
- *
- * \retval FLAC__SeekableStreamDecoder*
- *    \c NULL if there was an error allocating memory, else the new instance.
- */
-FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new();
-
-/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
- *
- * \param decoder  A pointer to an existing decoder.
- * \assert
- *    \code decoder != NULL \endcode
- */
-FLAC_API void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder);
-
-
-/***********************************************************************
- *
- * Public class method prototypes
- *
- ***********************************************************************/
-
-/** Set the "MD5 signature checking" flag.  If \c true, the decoder will
- *  compute the MD5 signature of the unencoded audio data while decoding
- *  and compare it to the signature from the STREAMINFO block, if it
- *  exists, during FLAC__seekable_stream_decoder_finish().
- *
- *  MD5 signature checking will be turned off (until the next
- *  FLAC__seekable_stream_decoder_reset()) if there is no signature in
- *  the STREAMINFO block or when a seek is attempted.
- *
- * \default \c false
- * \param  decoder  A decoder instance to set.
- * \param  value    Flag value (see above).
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value);
-
-/** Set the read callback.
- *  This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_read_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value);
-
-/** Set the seek callback.
- *  The supplied function will be called when the decoder needs to seek
- *  the input stream.  The decoder will pass the absolute byte offset
- *  to seek to, 0 meaning the beginning of the stream.
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value);
-
-/** Set the tell callback.
- *  The supplied function will be called when the decoder wants to know
- *  the current position of the stream.  The callback should return the
- *  byte offset from the beginning of the stream.
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value);
-
-/** Set the length callback.
- *  The supplied function will be called when the decoder wants to know
- *  the total length of the stream in bytes.
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value);
-
-/** Set the eof callback.
- *  The supplied function will be called when the decoder needs to know
- *  if the end of the stream has been reached.
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value);
-
-/** Set the write callback.
- *  This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_write_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value);
-
-/** Set the metadata callback.
- *  This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value);
-
-/** Set the error callback.
- *  This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_error_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value);
-
-/** Set the client data to be passed back to callbacks.
- *  This value will be supplied to callbacks in their \a client_data
- *  argument.
- *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_respond().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  type     See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \a type is valid
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_respond_application().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  id       See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code id != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_respond_all().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_ignore().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  type     See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \a type is valid
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_ignore_application().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \param  id       See above.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code id != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_set_metadata_ignore_all().
- *
- * \default By default, only the \c STREAMINFO block is returned via the
- *          metadata callback.
- * \param  decoder  A decoder instance to set.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the decoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder);
-
-/** Get the current decoder state.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__SeekableStreamDecoderState
- *    The current decoder state.
- */
-FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder);
-
-/** Get the state of the underlying stream decoder.
- *  Useful when the seekable stream decoder state is
- *  \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__StreamDecoderState
- *    The stream decoder state.
- */
-FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder);
-
-/** Get the current decoder state as a C string.
- *  This version automatically resolves
- *  \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR by getting the
- *  stream decoder's state.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval const char *
- *    The decoder state as a C string.  Do not modify the contents.
- */
-FLAC_API const char *FLAC__seekable_stream_decoder_get_resolved_state_string(const FLAC__SeekableStreamDecoder *decoder);
-
-/** Get the "MD5 signature checking" flag.
- *  This is the value of the setting, not whether or not the decoder is
- *  currently checking the MD5 (remember, it can be turned off automatically
- *  by a seek).  When the decoder is reset the flag will be restored to the
- *  value returned by this function.
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_get_channels().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_get_channel_assignment().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__ChannelAssignment
- *    See above.
- */
-FLAC_API FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_get_bits_per_sample().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_get_sample_rate().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_get_blocksize().
- *
- * \param  decoder  A decoder instance to query.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval unsigned
- *    See above.
- */
-FLAC_API unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder);
-
-/** Returns the decoder's current read position within the stream.
- *  The position is the byte offset from the start of the stream.
- *  Bytes before this position have been fully decoded.  Note that
- *  there may still be undecoded bytes in the decoder's read FIFO.
- *  The returned position is correct even after a seek.
- *
- * \param  decoder   A decoder instance to query.
- * \param  position  Address at which to return the desired position.
- * \assert
- *    \code decoder != NULL \endcode
- *    \code position != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, \c false if there was an error from
- *    the 'tell' callback.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_decode_position(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *position);
-
-/** Initialize the decoder instance.
- *  Should be called after FLAC__seekable_stream_decoder_new() and
- *  FLAC__seekable_stream_decoder_set_*() but before any of the
- *  FLAC__seekable_stream_decoder_process_*() functions.  Will set and return
- *  the decoder state, which will be FLAC__SEEKABLE_STREAM_DECODER_OK
- *  if initialization succeeded.
- *
- * \param  decoder  An uninitialized decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__SeekableStreamDecoderState
- *    \c FLAC__SEEKABLE_STREAM_DECODER_OK if initialization was
- *    successful; see FLAC__SeekableStreamDecoderState for the meanings
- *    of other return values.
- */
-FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder);
-
-/** Finish the decoding process.
- *  Flushes the decoding buffer, releases resources, resets the decoder
- *  settings to their defaults, and returns the decoder state to
- *  FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED.
- *
- *  In the event of a prematurely-terminated decode, it is not strictly
- *  necessary to call this immediately before
- *  FLAC__seekable_stream_decoder_delete() but it is good practice to match
- *  every FLAC__seekable_stream_decoder_init() with a
- *  FLAC__seekable_stream_decoder_finish().
- *
- * \param  decoder  An uninitialized decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if MD5 checking is on AND a STREAMINFO block was available
- *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
- *    signature does not match the one computed by the decoder; else
- *    \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder);
-
-/** Flush the stream input.
- *  The decoder's input buffer will be cleared and the state set to
- *  \c FLAC__SEEKABLE_STREAM_DECODER_OK.  This will also turn off MD5
- *  checking.
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false if a memory allocation
- *    or stream decoder error occurs.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder);
-
-/** Reset the decoding process.
- *  The decoder's input buffer will be cleared and the state set to
- *  \c FLAC__SEEKABLE_STREAM_DECODER_OK.  This is similar to
- *  FLAC__seekable_stream_decoder_finish() except that the settings are
- *  preserved; there is no need to call FLAC__seekable_stream_decoder_init()
- *  before decoding again.  MD5 checking will be restored to its original
- *  setting.
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false if a memory allocation
- *    or stream decoder error occurs.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_process_single().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_process_until_end_of_metadata().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder);
-
-/** This is inherited from FLAC__StreamDecoder; see
- *  FLAC__stream_decoder_process_until_end_of_stream().
- *
- * \param  decoder  A decoder instance.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    See above.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder);
-
-/** Flush the input and seek to an absolute sample.
- *  Decoding will resume at the given sample.  Note that because of
- *  this, the next write callback may contain a partial block.
- *
- * \param  decoder  A decoder instance.
- * \param  sample   The target sample number to seek to.
- * \assert
- *    \code decoder != NULL \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample);
-
-/* \} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/FLAC/seekable_stream_encoder.h b/FLAC/seekable_stream_encoder.h
deleted file mode 100644 (file)
index 2e77e00..0000000
+++ /dev/null
@@ -1,916 +0,0 @@
-/* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2002,2003  Josh Coalson
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
-
-#ifndef FLAC__SEEKABLE_STREAM_ENCODER_H
-#define FLAC__SEEKABLE_STREAM_ENCODER_H
-
-#include "export.h"
-#include "stream_encoder.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/** \file include/FLAC/seekable_stream_encoder.h
- *
- *  \brief
- *  This module contains the functions which implement the seekable stream
- *  encoder.
- *
- *  See the detailed documentation in the
- *  \link flac_seekable_stream_encoder seekable stream encoder \endlink module.
- */
-
-/** \defgroup flac_seekable_stream_encoder FLAC/seekable_stream_encoder.h: seekable stream encoder interface
- *  \ingroup flac_encoder
- *
- *  \brief
- *  This module contains the functions which implement the seekable stream
- *  encoder.
- *
- * The basic usage of this encoder is as follows:
- * - The program creates an instance of an encoder using
- *   FLAC__seekable_stream_encoder_new().
- * - The program overrides the default settings and sets callbacks using
- *   FLAC__seekable_stream_encoder_set_*() functions.
- * - The program initializes the instance to validate the settings and
- *   prepare for encoding using FLAC__seekable_stream_encoder_init().
- * - The program calls FLAC__seekable_stream_encoder_process() or
- *   FLAC__seekable_stream_encoder_process_interleaved() to encode data, which
- *   subsequently calls the callbacks when there is encoder data ready
- *   to be written.
- * - The program finishes the encoding with FLAC__seekable_stream_encoder_finish(),
- *   which causes the encoder to encode any data still in its input pipe,
- *   rewrite the metadata with the final encoding statistics, and finally
- *   reset the encoder to the uninitialized state.
- * - The instance may be used again or deleted with
- *   FLAC__seekable_stream_encoder_delete().
- *
- * The seekable stream encoder is a wrapper around the
- * \link flac_stream_encoder stream encoder \endlink with callbacks for
- * seeking the output.  This allows the encoder to go back and rewrite
- * some of the metadata after encoding if necessary, and provides the
- * metadata callback of the stream encoder internally.  However, you
- * must provide a seek callback (see
- * FLAC__seekable_stream_encoder_set_seek_callback()).
- *
- * Make sure to read the detailed description of the
- * \link flac_stream_encoder stream encoder module \endlink since the
- * seekable stream encoder inherits much of its behavior.
- *
- * \note
- * If you are writing the FLAC data to a file, make sure it is open
- * for update (e.g. mode "w+" for stdio streams).  This is because after
- * the first encoding pass, the encoder will try to seek back to the
- * beginning of the stream, to the STREAMINFO block, to write some data
- * there.
- *
- * \note
- * The "set" functions may only be called when the encoder is in the
- * state FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED, i.e. after
- * FLAC__seekable_stream_encoder_new() or FLAC__seekable_stream_encoder_finish(), but
- * before FLAC__seekable_stream_encoder_init().  If this is the case they will
- * return \c true, otherwise \c false.
- *
- * \note
- * FLAC__seekable_stream_encoder_finish() resets all settings to the constructor
- * defaults, including the callbacks.
- *
- * \{
- */
-
-
-/** State values for a FLAC__SeekableStreamEncoder
- *
- *  The encoder's state can be obtained by calling FLAC__seekable_stream_encoder_get_state().
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_ENCODER_OK = 0,
-       /**< The encoder is in the normal OK state. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR,
-       /**< An error occurred in the underlying stream encoder;
-        * check FLAC__seekable_stream_encoder_get_stream_encoder_state().
-        */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR,
-       /**< Memory allocation failed. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR,
-       /**< The write callback returned an error. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR,
-       /**< The read callback returned an error. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR,
-       /**< The seek callback returned an error. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED,
-       /**< FLAC__seekable_stream_encoder_init() was called when the encoder was
-        * already initialized, usually because
-        * FLAC__seekable_stream_encoder_finish() was not called.
-        */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK,
-       /**< FLAC__seekable_stream_encoder_init() was called without all
-        * callbacks being set.
-        */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE,
-       /**< An invalid seek table was passed is the metadata to
-        * FLAC__seekable_stream_encoder_set_metadata().
-        */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED
-       /**< The encoder is in the uninitialized state. */
-
-} FLAC__SeekableStreamEncoderState;
-
-/** Maps a FLAC__SeekableStreamEncoderState to a C string.
- *
- *  Using a FLAC__SeekableStreamEncoderState as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[];
-
-
-/** Return values for the FLAC__SeekableStreamEncoder seek callback.
- */
-typedef enum {
-
-       FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK,
-       /**< The seek was OK and encoding can continue. */
-
-       FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR
-       /**< An unrecoverable error occurred.  The encoder will return from the process call. */
-
-} FLAC__SeekableStreamEncoderSeekStatus;
-
-/** Maps a FLAC__SeekableStreamEncoderSeekStatus to a C string.
- *
- *  Using a FLAC__SeekableStreamEncoderSeekStatus as the index to this array
- *  will give the string equivalent.  The contents should not be modified.
- */
-extern FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[];
-
-
-/***********************************************************************
- *
- * class FLAC__SeekableStreamEncoder
- *
- ***********************************************************************/
-
-struct FLAC__SeekableStreamEncoderProtected;
-struct FLAC__SeekableStreamEncoderPrivate;
-/** The opaque structure definition for the seekable stream encoder type.
- *  See the \link flac_seekable_stream_encoder seekable stream encoder module \endlink
- *  for a detailed description.
- */
-typedef struct {
-       struct FLAC__SeekableStreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
-       struct FLAC__SeekableStreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
-} FLAC__SeekableStreamEncoder;
-
-/** Signature for the seek callback.
- *  See FLAC__seekable_stream_encoder_set_seek_callback() for more info.
- *
- * \param  encoder  The encoder instance calling the callback.
- * \param  absolute_byte_offset  The offset from the beginning of the stream
- *                               to seek to.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_encoder_set_client_data().
- * \retval FLAC__SeekableStreamEncoderSeekStatus
- *    The callee's return status.
- */
-typedef FLAC__SeekableStreamEncoderSeekStatus (*FLAC__SeekableStreamEncoderSeekCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
-
-/** Signature for the write callback.
- *  See FLAC__seekable_stream_encoder_set_write_callback()
- *  and FLAC__StreamEncoderWriteCallback for more info.
- *
- * \param  encoder  The encoder instance calling the callback.
- * \param  buffer   An array of encoded data of length \a bytes.
- * \param  bytes    The byte length of \a buffer.
- * \param  samples  The number of samples encoded by \a buffer.
- *                  \c 0 has a special meaning; see
- *                  FLAC__stream_encoder_set_write_callback().
- * \param  current_frame  The number of current frame being encoded.
- * \param  client_data  The callee's client data set through
- *                      FLAC__seekable_stream_encoder_set_client_data().
- * \retval FLAC__StreamEncoderWriteStatus
- *    The callee's return status.
- */
-typedef FLAC__StreamEncoderWriteStatus (*FLAC__SeekableStreamEncoderWriteCallback)(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
-
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-/** Create a new seekable stream encoder instance.  The instance is created with
- *  default settings; see the individual FLAC__seekable_stream_encoder_set_*()
- *  functions for each setting's default.
- *
- * \retval FLAC__SeekableStreamEncoder*
- *    \c NULL if there was an error allocating memory, else the new instance.
- */
-FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new();
-
-/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
- *
- * \param encoder  A pointer to an existing encoder.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__seekable_stream_encoder_delete(FLAC__SeekableStreamEncoder *encoder);
-
-/***********************************************************************
- *
- * Public class method prototypes
- *
- ***********************************************************************/
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_verify().
- *
- * \default \c true
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_verify(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_streamable_subset().
- *
- * \default \c true
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_streamable_subset(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_do_mid_side_stereo().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_loose_mid_side_stereo().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_channels().
- *
- * \default \c 2
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_channels(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_bits_per_sample().
- *
- * \warning
- * Do not feed the encoder data that is wider than the value you
- * set here or you will generate an invalid stream.
- *
- * \default \c 16
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_bits_per_sample(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_sample_rate().
- *
- * \default \c 44100
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_blocksize().
- *
- * \default \c 1152
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_max_lpc_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_qlp_coeff_precision().
- *
- * \note
- * In the current implementation, qlp_coeff_precision + bits_per_sample must
- * be less than 32.
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_qlp_coeff_precision(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_do_qlp_coeff_prec_search().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_do_escape_coding().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_escape_coding(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_do_exhaustive_model_search().
- *
- * \default \c false
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_min_residual_partition_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_min_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_max_residual_partition_order().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_rice_parameter_search_dist().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(FLAC__SeekableStreamEncoder *encoder, unsigned value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_total_samples_estimate().
- *
- * \default \c 0
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_total_samples_estimate(FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value);
-
-/** This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_metadata().
- *
- * \note
- * SEEKTABLE blocks are handled specially.  Since you will not know
- * the values for the seek point stream offsets, you should pass in
- * a SEEKTABLE 'template', that is, a SEEKTABLE object with the
- * required sample numbers (or placeholder points), with \c 0 for the
- * \a frame_samples and \a stream_offset fields for each point.  While
- * encoding, the encoder will fill them in for you and when encoding
- * is finished, it will seek back and write the real values into the
- * SEEKTABLE block in the stream.  There are helper routines for
- * manipulating seektable template blocks; see metadata.h:
- * FLAC__metadata_object_seektable_template_*().
- *
- * \note
- * The encoder instance \b will modify the first \c SEEKTABLE block
- * as it transforms the template to a valid seektable while encoding,
- * but it is still up to the caller to free all metadata blocks after
- * encoding.
- *
- * \default \c NULL, 0
- * \param  encoder     An encoder instance to set.
- * \param  metadata    See above.
- * \param  num_blocks  See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
-
-/** Set the seek callback.
- *  The supplied function will be called when the encoder needs to seek
- *  the output stream.  The encoder will pass the absolute byte offset
- *  to seek to, 0 meaning the beginning of the stream.
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value);
-
-/** Set the write callback.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_set_write_callback().
- *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code value != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value);
-
-/** Set the client data to be passed back to callbacks.
- *  This value will be supplied to callbacks in their \a client_data
- *  argument.
- *
- * \default \c NULL
- * \param  encoder  An encoder instance to set.
- * \param  value    See above.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    \c false if the encoder is already initialized, else \c true.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_client_data(FLAC__SeekableStreamEncoder *encoder, void *value);
-
-/** Get the current encoder state.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__SeekableStreamEncoderState
- *    The current encoder state.
- */
-FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_get_state(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the state of the underlying stream encoder.
- *  Useful when the seekable stream encoder state is
- *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__StreamEncoderState
- *    The stream encoder state.
- */
-FLAC_API FLAC__StreamEncoderState FLAC__seekable_stream_encoder_get_stream_encoder_state(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the state of the underlying stream encoder's verify decoder.
- *  Useful when the seekable stream encoder state is
- *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
- *  stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__StreamDecoderState
- *    The stream encoder state.
- */
-FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_encoder_get_verify_decoder_state(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the current encoder state as a C string.
- *  This version automatically resolves
- *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR by getting the
- *  stream encoder's state.
- *
- * \param  encoder  A encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval const char *
- *    The encoder state as a C string.  Do not modify the contents.
- */
-FLAC_API const char *FLAC__seekable_stream_encoder_get_resolved_state_string(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get relevant values about the nature of a verify decoder error.
- *  Inherited from FLAC__stream_encoder_get_verify_decoder_error_stats().
- *  Useful when the seekable stream encoder state is
- *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
- *  stream encoder state is
- *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
- *
- * \param  encoder  An encoder instance to query.
- * \param  absolute_sample  The absolute sample number of the mismatch.
- * \param  frame_number  The number of the frame in which the mismatch occurred.
- * \param  channel       The channel in which the mismatch occurred.
- * \param  sample        The number of the sample (relative to the frame) in
- *                       which the mismatch occurred.
- * \param  expected      The expected value for the sample in question.
- * \param  got           The actual value returned by the decoder.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
-
-/** Get the "verify" flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_verify().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_verify().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_verify(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the "streamable subset" flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_streamable_subset().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_streamable_subset().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_streamable_subset(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the "mid/side stereo coding" flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_do_mid_side_stereo().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_get_do_mid_side_stereo().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the "adaptive mid/side switching" flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_loose_mid_side_stereo().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the number of input channels being processed.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_channels().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_channels().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_channels(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the input sample resolution setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_bits_per_sample().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_bits_per_sample().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_bits_per_sample(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the input sample rate setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_sample_rate().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_sample_rate().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_sample_rate(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the blocksize setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_blocksize().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_blocksize().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_blocksize(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the maximum LPC order setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_max_lpc_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_max_lpc_order().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_lpc_order(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the quantized linear predictor coefficient precision setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_qlp_coeff_precision().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_qlp_coeff_precision().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_qlp_coeff_precision(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the qlp coefficient precision search flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_do_qlp_coeff_prec_search().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the "escape coding" flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_do_escape_coding().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_do_escape_coding().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_escape_coding(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the exhaustive model search flag.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_do_exhaustive_model_search().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__bool
- *    See FLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the minimum residual partition order setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_min_residual_partition_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_min_residual_partition_order().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_min_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get maximum residual partition order setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_max_residual_partition_order().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_max_residual_partition_order().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the Rice parameter search distance setting.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_rice_parameter_search_dist().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval unsigned
- *    See FLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
- */
-FLAC_API unsigned FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Get the previously set estimate of the total samples to be encoded.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_get_total_samples_estimate().
- *
- * \param  encoder  An encoder instance to query.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__uint64
- *    See FLAC__seekable_stream_encoder_set_total_samples_estimate().
- */
-FLAC_API FLAC__uint64 FLAC__seekable_stream_encoder_get_total_samples_estimate(const FLAC__SeekableStreamEncoder *encoder);
-
-/** Initialize the encoder instance.
- *  Should be called after FLAC__seekable_stream_encoder_new() and
- *  FLAC__seekable_stream_encoder_set_*() but before FLAC__seekable_stream_encoder_process()
- *  or FLAC__seekable_stream_encoder_process_interleaved().  Will set and return
- *  the encoder state, which will be FLAC__SEEKABLE_STREAM_ENCODER_OK if
- *  initialization succeeded.
- *
- *  The call to FLAC__seekable_stream_encoder_init() currently will also immediately
- *  call the write callback with the \c fLaC signature and all the encoded
- *  metadata.
- *
- * \param  encoder  An uninitialized encoder instance.
- * \assert
- *    \code encoder != NULL \endcode
- * \retval FLAC__SeekableStreamEncoderState
- *    \c FLAC__SEEKABLE_STREAM_ENCODER_OK if initialization was successful; see
- *    FLAC__SeekableStreamEncoderState for the meanings of other return values.
- */
-FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLAC__SeekableStreamEncoder *encoder);
-
-/** Finish the encoding process.
- *  Flushes the encoding buffer, releases resources, resets the encoder
- *  settings to their defaults, and returns the encoder state to
- *  FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED.
- *
- *  In the event of a prematurely-terminated encode, it is not strictly
- *  necessary to call this immediately before FLAC__seekable_stream_encoder_delete()
- *  but it is good practice to match every FLAC__seekable_stream_encoder_init()
- *  with a FLAC__seekable_stream_encoder_finish().
- *
- * \param  encoder  An uninitialized encoder instance.
- * \assert
- *    \code encoder != NULL \endcode
- */
-FLAC_API void FLAC__seekable_stream_encoder_finish(FLAC__SeekableStreamEncoder *encoder);
-
-/** Submit data for encoding.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_process().
- *
- * \param  encoder  An initialized encoder instance in the OK state.
- * \param  buffer   An array of pointers to each channel's signal.
- * \param  samples  The number of samples in one channel.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false; in this case, check the
- *    encoder state with FLAC__seekable_stream_encoder_get_state() to see what
- *    went wrong.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
-
-/** Submit data for encoding.
- *  This is inherited from FLAC__StreamEncoder; see
- *  FLAC__stream_encoder_process_interleaved().
- *
- * \param  encoder  An initialized encoder instance in the OK state.
- * \param  buffer   An array of channel-interleaved data (see above).
- * \param  samples  The number of samples in one channel, the same as for
- *                  FLAC__seekable_stream_encoder_process().  For example, if
- *                  encoding two channels, \c 1000 \a samples corresponds
- *                  to a \a buffer of 2000 values.
- * \assert
- *    \code encoder != NULL \endcode
- *    \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
- * \retval FLAC__bool
- *    \c true if successful, else \c false; in this case, check the
- *    encoder state with FLAC__seekable_stream_encoder_get_state() to see what
- *    went wrong.
- */
-FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process_interleaved(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
-
-/* \} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/FLAC/src/bitmath.c b/FLAC/src/bitmath.c
new file mode 100644 (file)
index 0000000..b3d797d
--- /dev/null
@@ -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
+ */
+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/FLAC/src/bitreader.c b/FLAC/src/bitreader.c
new file mode 100644 (file)
index 0000000..ab62d41
--- /dev/null
@@ -0,0 +1,1087 @@
+/* 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/FLAC/src/bitwriter.c b/FLAC/src/bitwriter.c
new file mode 100644 (file)
index 0000000..402b1c4
--- /dev/null
@@ -0,0 +1,881 @@
+/* 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/FLAC/src/cpu.c b/FLAC/src/cpu.c
new file mode 100644 (file)
index 0000000..b9df19a
--- /dev/null
@@ -0,0 +1,293 @@
+/* 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/FLAC/src/crc.c b/FLAC/src/crc.c
new file mode 100644 (file)
index 0000000..8123c3b
--- /dev/null
@@ -0,0 +1,143 @@
+/* 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/FLAC/src/fixed.c b/FLAC/src/fixed.c
new file mode 100644 (file)
index 0000000..1e2d5b2
--- /dev/null
@@ -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) ((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 -= (bits-16);
+       }
+       rbps = (FLAC__uint32)err;
+
+       /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+       rbps *= FLAC__FP_LN2;
+       fracbits += 16;
+       FLAC__ASSERT(fracbits >= 0);
+
+       /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+       {
+               const int f = fracbits & 3;
+               if(f) {
+                       rbps >>= f;
+                       fracbits -= f;
+               }
+       }
+
+       rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+       if(rbps == 0)
+               return 0;
+
+       /*
+        * The return value must have 16 fractional bits.  Since the whole part
+        * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+        * must be >= -3, these assertion allows us to be able to shift rbps
+        * left if necessary to get 16 fracbits without losing any bits of the
+        * whole part of rbps.
+        *
+        * There is a slight chance due to accumulated error that the whole part
+        * will require 6 bits, so we use 6 in the assertion.  Really though as
+        * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+        */
+       FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+       FLAC__ASSERT(fracbits >= -3);
+
+       /* now shift the decimal point into place */
+       if(fracbits < 16)
+               return rbps << (16-fracbits);
+       else if(fracbits > 16)
+               return rbps >> (fracbits-16);
+       else
+               return rbps;
+}
+
+static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n)
+{
+       FLAC__uint32 rbps;
+       unsigned bits; /* the number of bits required to represent a number */
+       int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+       FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+       FLAC__ASSERT(err > 0);
+       FLAC__ASSERT(n > 0);
+
+       FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+       if(err <= n)
+               return 0;
+       /*
+        * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+        * These allow us later to know we won't lose too much precision in the
+        * fixed-point division (err<<fracbits)/n.
+        */
+
+       fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1);
+
+       err <<= fracbits;
+       err /= n;
+       /* err now holds err/n with fracbits fractional bits */
+
+       /*
+        * Whittle err down to 16 bits max.  16 significant bits is enough for
+        * our purposes.
+        */
+       FLAC__ASSERT(err > 0);
+       bits = FLAC__bitmath_ilog2_wide(err)+1;
+       if(bits > 16) {
+               err >>= (bits-16);
+               fracbits -= (bits-16);
+       }
+       rbps = (FLAC__uint32)err;
+
+       /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+       rbps *= FLAC__FP_LN2;
+       fracbits += 16;
+       FLAC__ASSERT(fracbits >= 0);
+
+       /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+       {
+               const int f = fracbits & 3;
+               if(f) {
+                       rbps >>= f;
+                       fracbits -= f;
+               }
+       }
+
+       rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+       if(rbps == 0)
+               return 0;
+
+       /*
+        * The return value must have 16 fractional bits.  Since the whole part
+        * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+        * must be >= -3, these assertion allows us to be able to shift rbps
+        * left if necessary to get 16 fracbits without losing any bits of the
+        * whole part of rbps.
+        *
+        * There is a slight chance due to accumulated error that the whole part
+        * will require 6 bits, so we use 6 in the assertion.  Really though as
+        * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+        */
+       FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+       FLAC__ASSERT(fracbits >= -3);
+
+       /* now shift the decimal point into place */
+       if(fracbits < 16)
+               return rbps << (16-fracbits);
+       else if(fracbits > 16)
+               return rbps >> (fracbits-16);
+       else
+               return rbps;
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, 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/FLAC/src/fixed_intrin_sse2.c b/FLAC/src/fixed_intrin_sse2.c
new file mode 100644 (file)
index 0000000..6a9b4dd
--- /dev/null
@@ -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")
+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/FLAC/src/fixed_intrin_ssse3.c b/FLAC/src/fixed_intrin_ssse3.c
new file mode 100644 (file)
index 0000000..f4d93e8
--- /dev/null
@@ -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")
+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/FLAC/src/float.c b/FLAC/src/float.c
new file mode 100644 (file)
index 0000000..25d1a78
--- /dev/null
@@ -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, 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/FLAC/src/format.c b/FLAC/src/format.c
new file mode 100644 (file)
index 0000000..214bd09
--- /dev/null
@@ -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 " 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/FLAC/src/lpc.c b/FLAC/src/lpc.c
new file mode 100644 (file)
index 0000000..531247b
--- /dev/null
@@ -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 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/FLAC/src/lpc_intrin_avx2.c b/FLAC/src/lpc_intrin_avx2.c
new file mode 100644 (file)
index 0000000..f9f5ccd
--- /dev/null
@@ -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, 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/FLAC/src/lpc_intrin_sse.c b/FLAC/src/lpc_intrin_sse.c
new file mode 100644 (file)
index 0000000..430e73f
--- /dev/null
@@ -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[], 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/FLAC/src/lpc_intrin_sse2.c b/FLAC/src/lpc_intrin_sse2.c
new file mode 100644 (file)
index 0000000..1383394
--- /dev/null
@@ -0,0 +1,1090 @@
+/* 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/FLAC/src/lpc_intrin_sse41.c b/FLAC/src/lpc_intrin_sse41.c
new file mode 100644 (file)
index 0000000..bef73f4
--- /dev/null
@@ -0,0 +1,1314 @@
+/* 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/FLAC/src/md5.c b/FLAC/src/md5.c
new file mode 100644 (file)
index 0000000..e9013a9
--- /dev/null
@@ -0,0 +1,516 @@
+#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/FLAC/src/memory.c b/FLAC/src/memory.c
new file mode 100644 (file)
index 0000000..a8ebd10
--- /dev/null
@@ -0,0 +1,218 @@
+/* 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/FLAC/src/metadata_iterators.c b/FLAC/src/metadata_iterators.c
new file mode 100644 (file)
index 0000000..0a84d03
--- /dev/null
@@ -0,0 +1,3481 @@
+/* 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/FLAC/src/metadata_object.c b/FLAC/src/metadata_object.c
new file mode 100644 (file)
index 0000000..9cb9501
--- /dev/null
@@ -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, 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/FLAC/src/ogg_decoder_aspect.c b/FLAC/src/ogg_decoder_aspect.c
new file mode 100644 (file)
index 0000000..40cee19
--- /dev/null
@@ -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 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/FLAC/src/ogg_encoder_aspect.c b/FLAC/src/ogg_encoder_aspect.c
new file mode 100644 (file)
index 0000000..ebd4614
--- /dev/null
@@ -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, 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/FLAC/src/ogg_helper.c b/FLAC/src/ogg_helper.c
new file mode 100644 (file)
index 0000000..7ca9160
--- /dev/null
@@ -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 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/FLAC/src/ogg_mapping.c b/FLAC/src/ogg_mapping.c
new file mode 100644 (file)
index 0000000..08fa514
--- /dev/null
@@ -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 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/FLAC/src/private/all.h b/FLAC/src/private/all.h
new file mode 100644 (file)
index 0000000..7715962
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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__ALL_H
+#define FLAC__PRIVATE__ALL_H
+
+#include "bitmath.h"
+#include "bitreader.h"
+#include "bitwriter.h"
+#include "cpu.h"
+#include "crc.h"
+#include "fixed.h"
+#include "float.h"
+#include "format.h"
+#include "lpc.h"
+#include "md5.h"
+#include "memory.h"
+#include "metadata.h"
+#include "stream_encoder_framing.h"
+
+#endif
diff --git a/FLAC/src/private/bitmath.h b/FLAC/src/private/bitmath.h
new file mode 100644 (file)
index 0000000..9c75f85
--- /dev/null
@@ -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 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/FLAC/src/private/bitreader.h b/FLAC/src/private/bitreader.h
new file mode 100644 (file)
index 0000000..7c73165
--- /dev/null
@@ -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);
+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/FLAC/src/private/bitwriter.h b/FLAC/src/private/bitwriter.h
new file mode 100644 (file)
index 0000000..ef3ad1b
--- /dev/null
@@ -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);
+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/FLAC/src/private/cpu.h b/FLAC/src/private/cpu.h
new file mode 100644 (file)
index 0000000..7c65180
--- /dev/null
@@ -0,0 +1,186 @@
+/* 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/FLAC/src/private/crc.h b/FLAC/src/private/crc.h
new file mode 100644 (file)
index 0000000..294f60e
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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/FLAC/src/private/fixed.h b/FLAC/src/private/fixed.h
new file mode 100644 (file)
index 0000000..68cdfce
--- /dev/null
@@ -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
+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/FLAC/src/private/float.h b/FLAC/src/private/float.h
new file mode 100644 (file)
index 0000000..12ece60
--- /dev/null
@@ -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 (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/FLAC/src/private/format.h b/FLAC/src/private/format.h
new file mode 100644 (file)
index 0000000..5b9cfbd
--- /dev/null
@@ -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"
+
+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/FLAC/src/private/lpc.h b/FLAC/src/private/lpc.h
new file mode 100644 (file)
index 0000000..6eb02be
--- /dev/null
@@ -0,0 +1,250 @@
+/* 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/FLAC/src/private/macros.h b/FLAC/src/private/macros.h
new file mode 100644 (file)
index 0000000..becc59f
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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/FLAC/src/private/md5.h b/FLAC/src/private/md5.h
new file mode 100644 (file)
index 0000000..c665ab3
--- /dev/null
@@ -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[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+
+#endif
diff --git a/FLAC/src/private/memory.h b/FLAC/src/private/memory.h
new file mode 100644 (file)
index 0000000..f103c53
--- /dev/null
@@ -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, 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/FLAC/src/private/metadata.h b/FLAC/src/private/metadata.h
new file mode 100644 (file)
index 0000000..161947f
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "FLAC/metadata.h"
+
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
diff --git a/FLAC/src/private/ogg_decoder_aspect.h b/FLAC/src/private/ogg_decoder_aspect.h
new file mode 100644 (file)
index 0000000..218f44e
--- /dev/null
@@ -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;
+       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/FLAC/src/private/ogg_encoder_aspect.h b/FLAC/src/private/ogg_encoder_aspect.h
new file mode 100644 (file)
index 0000000..f55ef32
--- /dev/null
@@ -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;
+       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/FLAC/src/private/ogg_helper.h b/FLAC/src/private/ogg_helper.h
new file mode 100644 (file)
index 0000000..4c1000c
--- /dev/null
@@ -0,0 +1,44 @@
+/* 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_HELPER_H
+#define FLAC__PRIVATE__OGG_HELPER_H
+
+#include <ogg/ogg.h>
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */
+
+void simple_ogg_page__init(ogg_page *page);
+void simple_ogg_page__clear(ogg_page *page);
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data);
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data);
+
+#endif
diff --git a/FLAC/src/private/ogg_mapping.h b/FLAC/src/private/ogg_mapping.h
new file mode 100644 (file)
index 0000000..1fa022d
--- /dev/null
@@ -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 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/FLAC/src/private/stream_encoder.h b/FLAC/src/private/stream_encoder.h
new file mode 100644 (file)
index 0000000..ab1721f
--- /dev/null
@@ -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[],
+                       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/FLAC/src/private/stream_encoder_framing.h b/FLAC/src/private/stream_encoder_framing.h
new file mode 100644 (file)
index 0000000..f633a9d
--- /dev/null
@@ -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, 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/FLAC/src/private/window.h b/FLAC/src/private/window.h
new file mode 100644 (file)
index 0000000..bfed774
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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.
+ */
+
+#ifndef FLAC__PRIVATE__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *     FLAC__window_*()
+ *     --------------------------------------------------------------------
+ *     Calculates window coefficients according to different apodization
+ *     functions.
+ *
+ *     OUT window[0,L-1]
+ *     IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/FLAC/src/protected/all.h b/FLAC/src/protected/all.h
new file mode 100644 (file)
index 0000000..9468bd3
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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__ALL_H
+#define FLAC__PROTECTED__ALL_H
+
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+#endif
diff --git a/FLAC/src/protected/stream_decoder.h b/FLAC/src/protected/stream_decoder.h
new file mode 100644 (file)
index 0000000..5c31c16
--- /dev/null
@@ -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;
+       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/FLAC/src/protected/stream_encoder.h b/FLAC/src/protected/stream_encoder.h
new file mode 100644 (file)
index 0000000..8850c6b
--- /dev/null
@@ -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;
+       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/FLAC/src/share/alloc.h b/FLAC/src/share/alloc.h
new file mode 100644 (file)
index 0000000..914de9b
--- /dev/null
@@ -0,0 +1,219 @@
+/* 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.
+ */
+
+#ifndef FLAC__SHARE__ALLOC_H
+#define FLAC__SHARE__ALLOC_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
+ * before #including this file,  otherwise SIZE_MAX might not be defined
+ */
+
+#include <limits.h> /* for SIZE_MAX */
+#if HAVE_STDINT_H
+#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
+#endif
+#include <stdlib.h> /* for size_t, malloc(), etc */
+#include "share/compat.h"
+
+#ifndef SIZE_MAX
+# ifndef SIZE_T_MAX
+#  ifdef _MSC_VER
+#   ifdef _WIN64
+#    define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff)
+#   else
+#    define SIZE_T_MAX 0xffffffff
+#   endif
+#  else
+#   error
+#  endif
+# endif
+# define SIZE_MAX SIZE_T_MAX
+#endif
+
+/* avoid malloc()ing 0 bytes, see:
+ * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
+*/
+static inline void *safe_malloc_(size_t size)
+{
+       /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       if(!size)
+               size++;
+       return malloc(size);
+}
+
+static inline void *safe_calloc_(size_t nmemb, size_t size)
+{
+       if(!nmemb || !size)
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       return calloc(nmemb, size);
+}
+
+/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
+
+static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       return safe_malloc_(size2);
+}
+
+static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       return safe_malloc_(size3);
+}
+
+static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       size4 += size3;
+       if(size4 < size3)
+               return 0;
+       return safe_malloc_(size4);
+}
+
+void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
+
+static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || !size2 || !size3)
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       size1 *= size2;
+       if(size1 > SIZE_MAX / size3)
+               return 0;
+       return malloc(size1*size3);
+}
+
+/* size1*size2 + size3 */
+static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || !size2)
+               return safe_malloc_(size3);
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return safe_malloc_add_2op_(size1*size2, size3);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || (!size2 && !size3))
+               return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+       size2 += size3;
+       if(size2 < size3)
+               return 0;
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return malloc(size1*size2);
+}
+
+static inline void *safe_realloc_(void *ptr, size_t size)
+{
+       void *oldptr = ptr;
+       void *newptr = realloc(ptr, size);
+       if(size > 0 && newptr == 0)
+               free(oldptr);
+       return newptr;
+}
+static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
+{
+       size2 += size1;
+       if(size2 < size1) {
+               free(ptr);
+               return 0;
+       }
+       return realloc(ptr, size2);
+}
+
+static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       return realloc(ptr, size3);
+}
+
+static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
+{
+       size2 += size1;
+       if(size2 < size1)
+               return 0;
+       size3 += size2;
+       if(size3 < size2)
+               return 0;
+       size4 += size3;
+       if(size4 < size3)
+               return 0;
+       return realloc(ptr, size4);
+}
+
+static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
+{
+       if(!size1 || !size2)
+               return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+       if(size1 > SIZE_MAX / size2)
+               return 0;
+       return safe_realloc_(ptr, size1*size2);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+       if(!size1 || (!size2 && !size3))
+               return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+       size2 += size3;
+       if(size2 < size3)
+               return 0;
+       return safe_realloc_mul_2op_(ptr, size1, size2);
+}
+
+#endif
diff --git a/FLAC/src/share/compat.h b/FLAC/src/share/compat.h
new file mode 100644 (file)
index 0000000..2083f3a
--- /dev/null
@@ -0,0 +1,209 @@
+/* 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.
+ */
+
+/* This is the prefered location of all CPP hackery to make $random_compiler
+ * work like something approaching a C99 (or maybe more accurately GNU99)
+ * compiler.
+ *
+ * It is assumed that this header will be included after "config.h".
+ */
+
+#ifndef FLAC__SHARE__COMPAT_H
+#define FLAC__SHARE__COMPAT_H
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */
+#if !defined __MINGW32__
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#else /* MinGW */
+#if !defined(HAVE_FSEEKO)
+#define fseeko fseeko64
+#define ftello ftello64
+#endif
+#endif
+#else
+#define FLAC__off_t off_t
+#endif
+
+#if HAVE_INTTYPES_H
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#endif
+
+#if defined(_MSC_VER)
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#endif
+
+#if defined(_MSC_VER)
+#define inline __inline
+#endif
+
+#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64)
+/* MSVS generates VERY slow 32-bit code with __restrict */
+#define flac_restrict __restrict
+#elif defined __GNUC__
+#define flac_restrict __restrict__
+#else
+#define flac_restrict
+#endif
+
+#define FLAC__U64L(x) x##ULL
+
+#if defined _MSC_VER || defined __MINGW32__
+#define FLAC__STRCASECMP _stricmp
+#define FLAC__STRNCASECMP _strnicmp
+#elif defined __BORLANDC__
+#define FLAC__STRCASECMP stricmp
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for _setmode(), chmod() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+
+#if defined _MSC_VER
+#  if _MSC_VER >= 1800
+#    include <inttypes.h>
+#  elif _MSC_VER >= 1600
+/* Visual Studio 2010 has decent C99 support */
+#    include <stdint.h>
+#    define PRIu64 "llu"
+#    define PRId64 "lld"
+#    define PRIx64 "llx"
+#  else
+#    include <limits.h>
+#    ifndef UINT32_MAX
+#      define UINT32_MAX _UI32_MAX
+#    endif
+     typedef unsigned __int64 uint64_t;
+     typedef unsigned __int32 uint32_t;
+     typedef unsigned __int16 uint16_t;
+     typedef unsigned __int8 uint8_t;
+     typedef __int64 int64_t;
+     typedef __int32 int32_t;
+     typedef __int16 int16_t;
+     typedef __int8  int8_t;
+#    define PRIu64 "I64u"
+#    define PRId64 "I64d"
+#    define PRIx64 "I64x"
+#  endif
+#endif /* defined _MSC_VER */
+
+#ifdef _WIN32
+/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */
+
+#include "share/win_utf8_io.h"
+#define flac_printf printf_utf8
+#define flac_fprintf fprintf_utf8
+#define flac_vfprintf vfprintf_utf8
+
+#include "share/windows_unicode_filenames.h"
+#define flac_fopen flac_internal_fopen_utf8
+#define flac_chmod flac_internal_chmod_utf8
+#define flac_utime flac_internal_utime_utf8
+#define flac_unlink flac_internal_unlink_utf8
+#define flac_rename flac_internal_rename_utf8
+#define flac_stat flac_internal_stat64_utf8
+
+#else
+
+#define flac_printf printf
+#define flac_fprintf fprintf
+#define flac_vfprintf vfprintf
+
+#define flac_fopen fopen
+#define flac_chmod chmod
+#define flac_utime utime
+#define flac_unlink unlink
+#define flac_rename rename
+#define flac_stat stat
+
+#endif
+
+#ifdef _WIN32
+#define flac_stat_s __stat64 /* stat struct */
+#define flac_fstat _fstat64
+#else
+#define flac_stat_s stat /* stat struct */
+#define flac_fstat fstat
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* FLAC needs to compile and work correctly on systems with a normal ISO C99
+ * snprintf as well as Microsoft Visual Studio which has an non-standards
+ * conformant snprint_s function.
+ *
+ * This function wraps the MS version to behave more like the ISO version.
+ */
+#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+int flac_snprintf(char *str, size_t size, const char *fmt, ...);
+int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* FLAC__SHARE__COMPAT_H */
diff --git a/FLAC/src/share/endswap.h b/FLAC/src/share/endswap.h
new file mode 100644 (file)
index 0000000..9088a74
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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.
+ */
+
+/* It is assumed that this header will be included after "config.h". */
+
+#if HAVE_BSWAP32                       /* GCC and Clang */
+
+/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */
+#if ! HAVE_BSWAP16
+static inline unsigned short __builtin_bswap16(unsigned short a)
+{
+       return (a<<8)|(a>>8);
+}
+#endif
+
+#define        ENDSWAP_16(x)           (__builtin_bswap16 (x))
+#define        ENDSWAP_32(x)           (__builtin_bswap32 (x))
+#define        ENDSWAP_64(x)           (__builtin_bswap64 (x))
+
+#elif defined _MSC_VER         /* Windows */
+
+#include <stdlib.h>
+
+#define        ENDSWAP_16(x)           (_byteswap_ushort (x))
+#define        ENDSWAP_32(x)           (_byteswap_ulong (x))
+#define        ENDSWAP_64(x)           (_byteswap_uint64 (x))
+
+#elif defined HAVE_BYTESWAP_H          /* Linux */
+
+#include <byteswap.h>
+
+#define        ENDSWAP_16(x)           (bswap_16 (x))
+#define        ENDSWAP_32(x)           (bswap_32 (x))
+#define        ENDSWAP_64(x)           (bswap_64 (x))
+
+#else
+
+#define        ENDSWAP_16(x)           ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
+#define        ENDSWAP_32(x)           ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24))
+#define        ENDSWAP_64(x)           ((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32))
+
+#endif
+
+
+/* Host to little-endian byte swapping (for MD5 calculation) */
+#if CPU_IS_BIG_ENDIAN
+
+#define H2LE_16(x)             ENDSWAP_16 (x)
+#define H2LE_32(x)             ENDSWAP_32 (x)
+
+#else
+
+#define H2LE_16(x)             (x)
+#define H2LE_32(x)             (x)
+
+#endif
diff --git a/FLAC/src/share/getopt.h b/FLAC/src/share/getopt.h
new file mode 100644 (file)
index 0000000..66aced0
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+       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.
+*/
+/* Declarations for getopt.
+   Copyright (C) 1989,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.  */
+
+#ifndef SHARE__GETOPT_H
+#define SHARE__GETOPT_H
+
+/*[JEC] was:#ifndef __need_getopt*/
+/*[JEC] was:# define _GETOPT_H 1*/
+/*[JEC] was:#endif*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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.  */
+
+extern char *share__optarg;
+
+/* 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.  */
+
+extern int share__optind;
+
+/* Callers store zero here to inhibit the error message `share__getopt' prints
+   for unrecognized options.  */
+
+extern int share__opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int share__optopt;
+
+/*[JEC] was:#ifndef __need_getopt */
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to share__getopt_long or share__getopt_long_only is a vector
+   of `struct share__option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   share__no_argument          (or 0) if the option does not take an argument,
+   share__required_argument    (or 1) if the option requires an argument,
+   share__optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `share__optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `share__getopt'
+   returns the contents of the `val' field.  */
+
+struct share__option
+{
+# if defined __STDC__ && __STDC__
+  const char *name;
+# else
+  char *name;
+# endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct share__option'.  */
+
+# define share__no_argument            0
+# define share__required_argument      1
+# define share__optional_argument      2
+/*[JEC] was:#endif*/   /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+   arguments in ARGV (ARGC of them, minus the program name) for
+   options given in OPTS.
+
+   Return the option character from OPTS just read.  Return -1 when
+   there are no more options.  For unrecognized options, or options
+   missing arguments, `share__optopt' is set to the option letter, and '?' is
+   returned.
+
+   The OPTS string is a list of characters which are recognized option
+   letters, optionally followed by colons, specifying that that letter
+   takes an argument, to be placed in `share__optarg'.
+
+   If a letter in OPTS is followed by two colons, its argument is
+   optional.  This behavior is specific to the GNU `share__getopt'.
+
+   The argument `--' causes premature termination of argument
+   scanning, explicitly telling `share__getopt' that there are no more
+   options.
+
+   If OPTS begins with `--', then non-option arguments are treated as
+   arguments to the option '\0'.  This behavior is specific to the GNU
+   `share__getopt'.  */
+
+/*[JEC] was:#if defined __STDC__ && __STDC__*/
+/*[JEC] was:# ifdef __GNU_LIBRARY__*/
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int share__getopt (int argc, char *const *argv, const char *shortopts);
+/*[JEC] was:# else*/ /* not __GNU_LIBRARY__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# endif*/ /* __GNU_LIBRARY__ */
+
+/*[JEC] was:# ifndef __need_getopt*/
+extern int share__getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct share__option *longopts, int *longind);
+extern int share__getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct share__option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int share___getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct share__option *longopts, int *longind,
+                            int long_only);
+/*[JEC] was:# endif*/
+/*[JEC] was:#else*/ /* not __STDC__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# ifndef __need_getopt*/
+/*[JEC] was:extern int getopt_long ();*/
+/*[JEC] was:extern int getopt_long_only ();*/
+
+/*[JEC] was:extern int _getopt_internal ();*/
+/*[JEC] was:# endif*/
+/*[JEC] was:#endif*/ /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations.  */
+/*[JEC] was:#undef __need_getopt*/
+
+#endif /* getopt.h */
diff --git a/FLAC/src/share/grabbag.h b/FLAC/src/share/grabbag.h
new file mode 100644 (file)
index 0000000..92ec998
--- /dev/null
@@ -0,0 +1,30 @@
+/* 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
+ */
+
+#ifndef SHARE__GRABBAG_H
+#define SHARE__GRABBAG_H
+
+/* These can't be included by themselves, only from within grabbag.h */
+#include "grabbag/cuesheet.h"
+#include "grabbag/file.h"
+#include "grabbag/picture.h"
+#include "grabbag/replaygain.h"
+#include "grabbag/seektable.h"
+
+#endif
diff --git a/FLAC/src/share/macros.h b/FLAC/src/share/macros.h
new file mode 100644 (file)
index 0000000..20b3ea5
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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.
+ */
+
+#include <errno.h>
+
+/* FLAC_CHECK_RETURN : Check the return value of the provided function and
+ * print an error message if it fails (ie returns a value < 0).
+ *
+ * Ideally, a library should not print anything, but this macro is only used
+ * for things that extremely unlikely to fail, like `chown` to a previoulsy
+ * saved `uid`.
+ */
+
+#define FLAC_CHECK_RETURN(x) \
+                       {       if ((x) < 0) \
+                                       fprintf (stderr, "%s : %s\n", #x, strerror (errno)) ; \
+                       }
diff --git a/FLAC/src/share/private.h b/FLAC/src/share/private.h
new file mode 100644 (file)
index 0000000..f7e3b85
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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.
+ */
+
+#ifndef FLAC__SHARE__PRIVATE_H
+#define FLAC__SHARE__PRIVATE_H
+
+/*
+ * Unpublished debug routines from libFLAC> This should not be used from any
+ * client code other than code shipped with the FLAC sources.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder);
+
+#endif /* FLAC__SHARE__PRIVATE_H */
diff --git a/FLAC/src/share/replaygain_analysis.h b/FLAC/src/share/replaygain_analysis.h
new file mode 100644 (file)
index 0000000..f06a9b2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  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
+ *  coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *  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/
+ */
+
+#ifndef GAIN_ANALYSIS_H
+#define GAIN_ANALYSIS_H
+
+#include <stddef.h>
+
+#define GAIN_NOT_ENOUGH_SAMPLES  -24601
+#define GAIN_ANALYSIS_ERROR           0
+#define GAIN_ANALYSIS_OK              1
+
+#define INIT_GAIN_ANALYSIS_ERROR      0
+#define INIT_GAIN_ANALYSIS_OK         1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float   flac_float_t;         /* Type used for filtering */
+
+extern flac_float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */
+
+int     InitGainAnalysis ( long samplefreq );
+int     ValidGainFrequency ( long samplefreq );
+int     AnalyzeSamples   ( const flac_float_t* left_samples, const flac_float_t* right_samples, size_t num_samples, int num_channels );
+flac_float_t GetTitleGain     ( void );
+flac_float_t GetAlbumGain     ( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GAIN_ANALYSIS_H */
diff --git a/FLAC/src/share/replaygain_synthesis.h b/FLAC/src/share/replaygain_synthesis.h
new file mode 100644 (file)
index 0000000..5f4c3ff
--- /dev/null
@@ -0,0 +1,52 @@
+/* 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
+ */
+
+#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+
+#include <stdlib.h> /* for size_t */
+#include "FLAC/format.h"
+
+#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS FLAC__MAX_CHANNELS
+
+typedef enum {
+       NOISE_SHAPING_NONE = 0,
+       NOISE_SHAPING_LOW = 1,
+       NOISE_SHAPING_MEDIUM = 2,
+       NOISE_SHAPING_HIGH = 3
+} NoiseShaping;
+
+typedef struct {
+       const float*  FilterCoeff;
+       FLAC__uint64  Mask;
+       double        Add;
+       float         Dither;
+       float         ErrorHistory     [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];  /* 16th order Noise shaping */
+       float         DitherHistory    [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];
+       int           LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS];
+       unsigned      LastHistoryIndex;
+       NoiseShaping  ShapingType;
+} DitherContext;
+
+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);
+
+#endif
diff --git a/FLAC/src/share/safe_str.h b/FLAC/src/share/safe_str.h
new file mode 100644 (file)
index 0000000..eb974c5
--- /dev/null
@@ -0,0 +1,69 @@
+/* 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.
+ */
+
+/* Safe string handling functions to replace things like strcpy, strncpy,
+ * strcat, strncat etc.
+ * All of these functions guarantee a correctly NUL terminated string but
+ * the string may be truncated if the destination buffer was too short.
+ */
+
+#ifndef FLAC__SHARE_SAFE_STR_H
+#define FLAC__SHARE_SAFE_STR_H
+
+static inline char *
+safe_strncat(char *dest, const char *src, size_t dest_size)
+{
+       char * ret;
+
+       if (dest_size < 1)
+               return dest;
+
+       ret = strncat(dest, src, dest_size - strlen (dest));
+       dest [dest_size - 1] = 0;
+
+       return ret;
+}
+
+static inline char *
+safe_strncpy(char *dest, const char *src, size_t dest_size)
+{
+       char * ret;
+
+       if (dest_size < 1)
+               return dest;
+
+       ret = strncpy(dest, src, dest_size);
+       dest [dest_size - 1] = 0;
+
+       return ret;
+}
+
+#endif /* FLAC__SHARE_SAFE_STR_H */
diff --git a/FLAC/src/share/utf8.h b/FLAC/src/share/utf8.h
new file mode 100644 (file)
index 0000000..7d6650d
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SHARE__UTF8_H
+#define SHARE__UTF8_H
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ *  -1 : memory allocation failed
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ *   3 : unknown encoding (but still converted, using '?')
+ */
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#endif
diff --git a/FLAC/src/share/win_utf8_io.h b/FLAC/src/share/win_utf8_io.h
new file mode 100644 (file)
index 0000000..13fd118
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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 _WIN32
+
+#ifndef flac__win_utf8_io_h
+#define flac__win_utf8_io_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+size_t strlen_utf8(const char *str);
+int win_get_console_width(void);
+
+int get_utf8_argv(int *argc, char ***argv);
+
+int printf_utf8(const char *format, ...);
+int fprintf_utf8(FILE *stream, const char *format, ...);
+int vfprintf_utf8(FILE *stream, const char *format, va_list argptr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
diff --git a/FLAC/src/share/windows_unicode_filenames.h b/FLAC/src/share/windows_unicode_filenames.h
new file mode 100644 (file)
index 0000000..86820ca
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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 _WIN32
+
+#ifndef flac__windows_unicode_filenames_h
+#define flac__windows_unicode_filenames_h
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void flac_internal_set_utf8_filenames(FLAC__bool flag);
+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
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
diff --git a/FLAC/src/stream_decoder.c b/FLAC/src/stream_decoder.c
new file mode 100644 (file)
index 0000000..d364b0c
--- /dev/null
@@ -0,0 +1,3400 @@
+/* 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);
+       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)) {
+                                               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 */
+                       pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame;
+#endif
+               if(pos >= (FLAC__int64)upper_bound)
+                       pos = (FLAC__int64)upper_bound - 1;
+               if(pos < (FLAC__int64)lower_bound)
+                       pos = (FLAC__int64)lower_bound;
+               if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+                       decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+                       return false;
+               }
+               if(!FLAC__stream_decoder_flush(decoder)) {
+                       /* above call sets the state for us */
+                       return false;
+               }
+               /* Now we need to get a frame.  First we need to reset our
+                * unparseable_frame_count; if we get too many unparseable
+                * frames in a row, the read callback will return
+                * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+                * FLAC__stream_decoder_process_single() to return false.
+                */
+               decoder->private_->unparseable_frame_count = 0;
+               if(!FLAC__stream_decoder_process_single(decoder) ||
+                  decoder->protected_->state == FLAC__STREAM_DECODER_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/FLAC/src/stream_encoder.c b/FLAC/src/stream_encoder.c
new file mode 100644 (file)
index 0000000..037b8cb
--- /dev/null
@@ -0,0 +1,4549 @@
+/* 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)) {
+                               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/FLAC/src/stream_encoder_framing.c b/FLAC/src/stream_encoder_framing.c
new file mode 100644 (file)
index 0000000..0929cd7
--- /dev/null
@@ -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 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/FLAC/src/stream_encoder_intrin_avx2.c b/FLAC/src/stream_encoder_intrin_avx2.c
new file mode 100644 (file)
index 0000000..a94a02b
--- /dev/null
@@ -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[],
+               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/FLAC/src/stream_encoder_intrin_sse2.c b/FLAC/src/stream_encoder_intrin_sse2.c
new file mode 100644 (file)
index 0000000..0f1d7aa
--- /dev/null
@@ -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[],
+               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/FLAC/src/stream_encoder_intrin_ssse3.c b/FLAC/src/stream_encoder_intrin_ssse3.c
new file mode 100644 (file)
index 0000000..21a08fc
--- /dev/null
@@ -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[],
+               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/FLAC/src/window.c b/FLAC/src/window.c
new file mode 100644 (file)
index 0000000..e977fd8
--- /dev/null
@@ -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 * 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/FLAC/src/windows_unicode_filenames.c b/FLAC/src/windows_unicode_filenames.c
new file mode 100644 (file)
index 0000000..2404e31
--- /dev/null
@@ -0,0 +1,201 @@
+/* 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;
+       }
+}