diff options
author | Josh Coalson <jcoalson@users.sourceforce.net> | 2000-12-10 04:09:52 +0000 |
---|---|---|
committer | Josh Coalson <jcoalson@users.sourceforce.net> | 2000-12-10 04:09:52 +0000 |
commit | bb7f6b99d02e15e0ff98ff1d9d037098dc5dc4e9 (patch) | |
tree | e76e9be0f1736ac69cdaf084d413bdbcffd55425 | |
download | flac-bb7f6b99d02e15e0ff98ff1d9d037098dc5dc4e9.tar.gz |
Initial revision
63 files changed, 12744 insertions, 0 deletions
diff --git a/COPYING.GPL b/COPYING.GPL new file mode 100644 index 00000000..c3c7a9ea --- /dev/null +++ b/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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 Library General +Public License instead of this License. diff --git a/COPYING.LGPL b/COPYING.LGPL new file mode 100644 index 00000000..5c879e45 --- /dev/null +++ b/COPYING.LGPL @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile 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) 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. + + c) 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. + + d) 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 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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/Makefile b/Makefile new file mode 100644 index 00000000..09f27ee3 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# +# GNU Makefile +# +# Useful targets +# +# all : build all libraries and programs in the default configuration (currently 'release') +# debug : build all libraries and programs in debug mode +# release : build all libraries and programs in release mode +# test : run the unit and stream tests +# clean : remove all non-distro files +# + +all: libFLAC flac test_streams test_unit + +DEFAULT_CONFIG = release + +CONFIG = $(DEFAULT_CONFIG) + +debug : CONFIG = debug +release : CONFIG = release + +debug : all +release : all + +libFLAC: + (cd src/$@ ; make $(CONFIG)) + +flac: libFLAC + (cd src/$@ ; make $(CONFIG)) + +test_streams: libFLAC + (cd src/$@ ; make $(CONFIG)) + +test_unit: libFLAC + (cd src/$@ ; make $(CONFIG)) + +test: debug + (cd test ; make) + +clean: + -(cd src/libFLAC ; make clean) + -(cd src/flac ; make clean) + -(cd src/plugin_xmms ; make clean) + -(cd src/test_streams ; make clean) + -(cd src/test_unit ; make clean) + -(cd test ; make clean) @@ -0,0 +1,44 @@ +========== +FLAC - 0.2 +========== + +This is the source release for the FLAC project. The +reference encoder/decoder library 'libFLAC' is released +under the LGPL (see COPYING.LGPL). This means the code +in include/FLAC/ and src/libFLAC/. All other code is +covered by the GPL (see COPYING.GPL). See + + doc/index.html + +for full documentation. + +A brief description of the directory tree: + + build/ makefile templates for building + doc/ the HTML documentation + include/ public include files for libFLAC + obj/ the compiled libraries and executables will + end up here + src/ the source code and private headers + test/ the test scripts + + +============================= +Building in a GNU environment +============================= + +All files called 'Makefile' are GNUmake files. To build all +libraries and programs, just 'make all' from the top-level +directory. To run the tests, just 'make test'. + +Everything can be built in either debug or release mode. +See the Makefiles for details. + + +================== +Building with MSVC +================== + +There is no overall make system for MSVC but the individual +source directories with a 'Makefile.vc' file in them allow +building with MSVC. Just 'nmake /f Makefile.vc'. diff --git a/build/exe.mk b/build/exe.mk new file mode 100644 index 00000000..b4bd1a3f --- /dev/null +++ b/build/exe.mk @@ -0,0 +1,37 @@ +# +# GNU makefile fragment for building an executable +# + +CC = gcc +# LINKAGE can be forced to -static or -dynamic from invocation if desired, but it defaults to -static +LINKAGE = -static +LINK = gcc $(LINKAGE) +BINPATH = ../../obj/bin +LIBPATH = ../../obj/lib +PROGRAM = $(BINPATH)/$(PROGRAM_NAME) + +all : release + +debug : CFLAGS = -g -O0 -DDEBUG $(DEBUG_CFLAGS) -Wall -W $(INCLUDES) +release : CFLAGS = -O3 -DNDEBUG $(RELEASE_CFLAGS) -Wall -W $(INCLUDES) + +LFLAGS = -L$(LIBPATH) + +debug : $(PROGRAM) +release : $(PROGRAM) + +$(PROGRAM) : $(OBJS) + $(LINK) -o $@ $(OBJS) $(LFLAGS) $(LIBS) + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ +%.i : %.c + $(CC) $(CFLAGS) -E $< -o $@ + +.PHONY : clean +clean : + -rm -f $(OBJS) $(PROGRAM) + +.PHONY : depend +depend: + makedepend -- $(CFLAGS) $(INCLUDES) -- *.c diff --git a/build/lib.mk b/build/lib.mk new file mode 100644 index 00000000..62c4c73a --- /dev/null +++ b/build/lib.mk @@ -0,0 +1,39 @@ +# +# GNU makefile fragment for building a library +# + +CC = gcc +LINK = ar cru +LINKD = ld -G +LIBPATH = ../../obj/lib +STATIC_LIB = $(LIBPATH)/$(LIB_NAME).a +DYNAMIC_LIB = $(LIBPATH)/$(LIB_NAME).so + +all : release + +debug : CFLAGS = -g -O0 -DDEBUG $(DEBUG_CFLAGS) -Wall -W $(INCLUDES) +release : CFLAGS = -O3 -DNDEBUG $(RELEASE_CFLAGS) -Wall -W $(INCLUDES) + +LFLAGS = -L$(LIBPATH) + +debug : $(STATIC_LIB) $(DYNAMIC_LIB) +release : $(STATIC_LIB) $(DYNAMIC_LIB) + +$(STATIC_LIB) : $(OBJS) + $(LINK) $@ $(OBJS) + +$(DYNAMIC_LIB) : $(OBJS) + $(LINKD) -o $@ $(OBJS) $(LFLAGS) $(LIBS) + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ +%.i : %.c + $(CC) $(CFLAGS) -E $< -o $@ + +.PHONY : clean +clean : + -rm -f $(OBJS) $(STATIC_LIB) $(DYNAMIC_LIB) + +.PHONY : depend +depend: + makedepend -- $(CFLAGS) $(INCLUDES) -- *.c diff --git a/doc/comparison.html b/doc/comparison.html new file mode 100644 index 00000000..4107413a --- /dev/null +++ b/doc/comparison.html @@ -0,0 +1,654 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - comparison</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> comparison </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">comparison</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + The purpose of the comparison page is not only to show how compression ratios and encoding times using the flac reference encoder compare to other lossless encoders, but also to compare features (for example, some coders archive only and files must be uncompressed completely before playback can start). Keep a few things in mind: + </P> + <P> + <UL> + <LI> + As far as I know, only two of the lossless encoders out there (flac and Shorten) are truly free. Most others give out free binaries, but without access to the source, you are leaving your data to the whim of the maintainer for eternity; you have no way to port the program to another OS or fix it if it breaks. This can be a serious drawback unless the format has world-class clout (like MP3). + </LI> + <LI> + The compression ratios and times are representative only of the reference encoder. They are not indicative of the limits of all FLAC encoders or the FLAC format itself since the format is open and extensible, and anyone is free to write a better FLAC encoder. And it is almost certain that the reference encoder itself will improve. + </LI> + <LI> + Since FLAC supports streaming, it is at a slight disadvantage to the formats that don't because they don't have the extra overhead of all those frame headers. + </LI> + </UL> + </P> + <P> + I make an effort to keep this information as accurate as possible, but if any of the data is wrong, <A HREF="mailto:jcoalson@users.sourceforge.net">let me know</A> and I'll correct it. + </P> + <P> + Reviewed encoders: + </P> + <P> + <UL> + <LI> + <A HREF="index.html">flac</A> of course. + </LI> + <LI> + <A HREF="http://www-ft.ee.tu-berlin.de/~liebchen/lpac.html">LPAC</A> - A closed source codec. At least it's available for more than just Windows, but there's only a Winamp plugin. + </LI> + <LI> + <A HREF="http://www.monkeysaudio.com/">Monkey's Audio</A> - A closed source, Windows-only codec, with a Winamp plugin. + </LI> + <LI> + <A HREF="http://www.jpg.com/products/sound.html">Pegasus-SPS</A> - A closed source, Windows-only codec. + </LI> + <LI> + <A HREF="http://rksoft.virtualave.net/">RKAU</A> - A closed source, Windows-only codec. + </LI> + <LI> + <A HREF="http://www.softsound.com/Shorten.html">Shorten</A> - A.J. Robinson's well-known codec; source is available <A HREF="http://rpmfind.net/linux/rpm2html/search.php?query=shorten">here</A>. + </LI> + <LI> + <A HREF="http://www.gadgetlabs.com/wavezip.htm">WaveZIP</A> - A closed source, Windows-only archiver. Uses the <A HREF="http://members.aol.com/_ht_a/sndspace/index.html">MUSICompress</A>[tm] engine which supposedly has a patent. + </LI> + <LI> + <A HREF="http://www.wavpack.com/">WavPack</A> - A closed source, Windows-only archiver. + </LI> + </UL> + </P> + <P> + Encoders I couldn't get a copy of: + </P> + <P> + <UL> + <LI> + AudioPak + </LI> + <LI> + WavARC + </LI> + </UL> + </P> + <P> + If you take maximum compression ratio and speed out of the picture (as you will see later, most coders exhibit similar performance), here is a subjective sort based on overall "usefulness". As far as features go, having source code gives you the most freedom since you can add anything you need that is missing; besides, open source projects tend to get better faster than closed source ones. A close second (depending on the user) would be OS support or plugin support. + </P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD ALIGN="RIGHT"> + <FONT SIZE="+1"><B>Codec</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Source Available?</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Plugins Available?</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Streamable?</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Seekable?</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Cost</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>OS support</B></FONT> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + flac v0.2 + </TD> + <TD> + YES + </TD> + <TD> + YES (Winamp, XMMS) + </TD> + <TD> + YES + </TD> + <TD> + YES + </TD> + <TD> + FREE + </TD> + <TD> + ANY (source) + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + Shorten v2.3a + </TD> + <TD> + YES + </TD> + <TD> + YES (Winamp plugin somewhere) + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + FREE + </TD> + <TD> + ANY (source) + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + LPAC v1.20 (codec 2.0) + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + YES (Winamp only) + </TD> + <TD BGCOLOR="#D3D4C5"> + no? + </TD> + <TD> + YES + </TD> + <TD> + FREE + </TD> + <TD> + Windows/Linux/Solaris + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + Monkey's Audio v3.71 + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + YES (Winamp only) + </TD> + <TD> + YES + </TD> + <TD> + YES + </TD> + <TD> + FREE + </TD> + <TD BGCOLOR="#D3D4C5"> + Windows only + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + RKAU v1.06 + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + YES (Winamp only) + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + YES + </TD> + <TD> + FREE + </TD> + <TD BGCOLOR="#D3D4C5"> + Windows only + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + WavPack v3.6 + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + FREE + </TD> + <TD BGCOLOR="#D3D4C5"> + Windows only + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + WaveZIP v2 + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD> + FREE (24-bit costs $) + </TD> + <TD BGCOLOR="#D3D4C5"> + Windows only + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" BGCOLOR="#F4F4CC"> + Pegasus-SPS + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + no + </TD> + <TD BGCOLOR="#D3D4C5"> + $39 (free trial) + </TD> + <TD BGCOLOR="#D3D4C5"> + Windows only + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + <P> + The machine I used for encoding the test files is a PII-333 with 256 megs of RAM, running Windows NT 4.0 SP5. Unfortunately, Windows is the lowest-common-denominator platform for all the encoders. + </P> + <P> + The input corpus currently consists entirely of CD music tracks. In the future it may include more kinds of input (like speech, other sample rates, etc). There are ??? tracks whose genres range from death metal to pop to western classical to Indian classical. + </P> + <P> + In all tables, the results are sorter by compression ratio, which is compressed size / uncompressed size. The first table is a summary of results on all input tracks. The remaining table shows the results of the encoders on each track. + </P> + <P> + Some interesting things to note: LPAC quality settings are not too stable with -r (which allows seeking during playback) turned on. In most cases the 'normal' mode makes the smallest file, and much faster. RKAU also has a tendency to get bigger in the 'high' mode. Shorten's method for quantizing and transmitting the LPC coefficients is not very good which is the main reason why the fixed predictors runs are both smaller and faster. + </P> + <P> + Another ironic fact is that the encoders that are patented or cost money turn out to be the worst by most measures. SPS is so archane and crippled that I gave up trying to put together results for it after one track. + </P> + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Encoder</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Encode time</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Compressed size</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Compression ratio</B></FONT> + </TD> + </TR> + <TR><TD>Monkey's Audio 3.80 (extra high)</TD><TD>20:24.18</TD><TD>381.85 MB</TD><TD>0.5073</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>RKAU 1.06 (normal)</TD><TD>52:53.46</TD><TD>383.36 MB</TD><TD>0.5093</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>133:25.36</TD><TD>383.75 MB</TD><TD>0.5098</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>Monkey's Audio 3.80 (high)</TD><TD>7:45.75</TD><TD>387.97 MB</TD><TD>0.5154</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>20:49.34</TD><TD>393.16 MB</TD><TD>0.5223</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>LPAC 1.20 (-r, high)</TD><TD>88:20.18</TD><TD>393.12 MB</TD><TD>0.5223</TD></TR> + <TR><TD>LPAC 1.20 (-r, extra high)</TD><TD>109:27.86</TD><TD>393.93 MB</TD><TD>0.5234</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>flac 0.2 (-6)</TD><TD>41:11.46</TD><TD>399.30 MB</TD><TD>0.5305</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>10:05.48</TD><TD>403.70 MB</TD><TD>0.5363</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>6:41.17</TD><TD>417.24 MB</TD><TD>0.5543</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>9:16.47</TD><TD>422.59 MB</TD><TD>0.5614</TD></TR> + <TR BGCOLOR="#D3D4C5"><TD>WaveZip</TD><TD>8:24.17</TD><TD>435.06 MB</TD><TD>0.5780</TD></TR> + </TABLE> + </TD></TR></TABLE> + </P> + <P> + Here are the results for each individual track. + </P> + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD ALIGN="RIGHT"> + <FONT SIZE="+1"><B>Track</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Encoder</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Encode time</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Compressed size</B></FONT> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1"><B>Compression ratio</B></FONT> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="14" BGCOLOR="#F4F4CC"> + Dream Theater<BR><I>6:00</I><BR>58.47 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:39.08</TD><TD>43.70 MB</TD><TD>0.7475</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:41.98</TD><TD>43.85 MB</TD><TD>0.7500</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>8:12.44</TD><TD>43.87 MB</TD><TD>0.7503</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>2:59.56</TD><TD>43.88 MB</TD><TD>0.7504</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>flac 0.2 (-6)</TD><TD>3:13.55</TD><TD>44.38 MB</TD><TD>0.7591</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>6:51.24</TD><TD>44.42 MB</TD><TD>0.7598</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>1:45.72</TD><TD>44.44 MB</TD><TD>0.7601</TD></TR> + <TR><TD>LPAC 1.20 (-r, extra high)</TD><TD>7:50.80</TD><TD>44.44 MB</TD><TD>0.7601</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:47.79</TD><TD>44.74 MB</TD><TD>0.7653</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>0:49.21</TD><TD>45.37 MB</TD><TD>0.7760</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Pegasus-SPS</TD><TD>4:45.00</TD><TD>45.40 MB</TD><TD>0.7765</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:34.50</TD><TD>46.68 MB</TD><TD>0.7984</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WaveZip</TD><TD>0:38.99</TD><TD>47.22 MB</TD><TD>0.8077</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Tool<BR><I>Forty-six & 2</I><BR>64.25 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:48.94</TD><TD>39.30 MB</TD><TD>0.6116</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:33.43</TD><TD>39.51 MB</TD><TD>0.6149</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (normal)</TD><TD>3:34.75</TD><TD>39.93 MB</TD><TD>0.6214</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>8:37.42</TD><TD>39.97 MB</TD><TD>0.6220</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>1:52.22</TD><TD>40.57 MB</TD><TD>0.6314</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>7:36.55</TD><TD>40.61 MB</TD><TD>0.6320</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>9:49.64</TD><TD>40.71 MB</TD><TD>0.6336</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>3:35.02</TD><TD>41.01 MB</TD><TD>0.6383</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:52.37</TD><TD>41.72 MB</TD><TD>0.6492</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:50.22</TD><TD>43.05 MB</TD><TD>0.6701</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:35.93</TD><TD>43.19 MB</TD><TD>0.6722</TD></TR> + <TR><TD>WaveZip</TD><TD>0:42.84</TD><TD>44.52 MB</TD><TD>0.6930</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Cannibal Corpse<BR><I>Mummified In Barbed Wire</I><BR>33.37 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>0:49.20</TD><TD>23.47 MB</TD><TD>0.7033</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:23.25</TD><TD>23.66 MB</TD><TD>0.7087</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>1:01.16</TD><TD>23.75 MB</TD><TD>0.7116</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>5:13.57</TD><TD>23.92 MB</TD><TD>0.7168</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>6:04.27</TD><TD>23.95 MB</TD><TD>0.7175</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>1:32.20</TD><TD>24.04 MB</TD><TD>0.7202</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>3:21.70</TD><TD>24.04 MB</TD><TD>0.7202</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>1:50.43</TD><TD>24.31 MB</TD><TD>0.7285</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:27.03</TD><TD>25.12 MB</TD><TD>0.7525</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>0:28.07</TD><TD>25.44 MB</TD><TD>0.7621</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:19.85</TD><TD>26.59 MB</TD><TD>0.7966</TD></TR> + <TR><TD>WaveZip</TD><TD>0:22.25</TD><TD>26.89 MB</TD><TD>0.8058</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Alanis Morisette<BR><I>Hand In My Pocket</I><BR>39.09 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:03.98</TD><TD>22.85 MB</TD><TD>0.5845</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:25.70</TD><TD>23.04 MB</TD><TD>0.5893</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>5:54.68</TD><TD>23.16 MB</TD><TD>0.5925</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>2:23.63</TD><TD>23.19 MB</TD><TD>0.5933</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>1:07.58</TD><TD>23.45 MB</TD><TD>0.6000</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>4:47.03</TD><TD>23.49 MB</TD><TD>0.6008</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>5:50.53</TD><TD>23.52 MB</TD><TD>0.6016</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>2:10.43</TD><TD>23.55 MB</TD><TD>0.6023</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:31.44</TD><TD>24.30 MB</TD><TD>0.6217</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:30.45</TD><TD>24.72 MB</TD><TD>0.6324</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:21.93</TD><TD>25.33 MB</TD><TD>0.6478</TD></TR> + <TR><TD>WaveZip</TD><TD>0:28.05</TD><TD>25.95 MB</TD><TD>0.6638</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Gloria Estefan<BR><I>Conga</I><BR>45.15 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:15.79</TD><TD>30.12 MB</TD><TD>0.6670</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:29.68</TD><TD>30.32 MB</TD><TD>0.6716</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>flac 0.2 (-6)</TD><TD>2:35.05</TD><TD>30.82 MB</TD><TD>0.6825</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>6:52.69</TD><TD>30.83 MB</TD><TD>0.6828</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (normal)</TD><TD>2:41.42</TD><TD>30.87 MB</TD><TD>0.6837</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>1:20.29</TD><TD>31.03 MB</TD><TD>0.6871</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:37.15</TD><TD>31.04 MB</TD><TD>0.6875</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>5:33.21</TD><TD>31.06 MB</TD><TD>0.6879</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>6:39.28</TD><TD>31.11 MB</TD><TD>0.6889</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:35.51</TD><TD>31.76 MB</TD><TD>0.7033</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:24.65</TD><TD>32.62 MB</TD><TD>0.7223</TD></TR> + <TR><TD>WaveZip</TD><TD>0:29.42</TD><TD>33.02 MB</TD><TD>0.7313</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Cream<BR><I>White Room</I><BR>53.01 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>8:15.46</TD><TD>34.30 MB</TD><TD>0.6469</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>3:12.99</TD><TD>34.35 MB</TD><TD>0.6479</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:28.45</TD><TD>34.65 MB</TD><TD>0.6535</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:24.17</TD><TD>34.91 MB</TD><TD>0.6586</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>1:34.16</TD><TD>35.10 MB</TD><TD>0.6621</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>3:00.29</TD><TD>35.14 MB</TD><TD>0.6629</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, high)</TD><TD>6:39.29</TD><TD>35.17 MB</TD><TD>0.6633</TD></TR> + <TR><TD>LPAC 1.20 (-r, extra high)</TD><TD>7:39.28</TD><TD>35.19 MB</TD><TD>0.6638</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:40.44</TD><TD>35.39 MB</TD><TD>0.6676</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>0:44.18</TD><TD>35.82 MB</TD><TD>0.6758</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:29.49</TD><TD>36.39 MB</TD><TD>0.6864</TD></TR> + <TR><TD>WaveZip</TD><TD>0:35.77</TD><TD>37.13 MB</TD><TD>0.7004</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Maurice Ravel<BR><I>Fanfare from "L'eventail de Jeanne"</I><BR>20.82 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (normal)</TD><TD>1:46.51</TD><TD>6.86 MB</TD><TD>0.3297</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>3:53.54</TD><TD>6.90 MB</TD><TD>0.3316</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>0:30.30</TD><TD>7.09 MB</TD><TD>0.3407</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>0:30.93</TD><TD>7.47 MB</TD><TD>0.3586</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>3:06.27</TD><TD>7.48 MB</TD><TD>0.3591</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>2:21.16</TD><TD>7.48 MB</TD><TD>0.3593</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (high)</TD><TD>0:12.58</TD><TD>7.56 MB</TD><TD>0.3634</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>1:02.16</TD><TD>7.82 MB</TD><TD>0.3755</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:16.11</TD><TD>7.99 MB</TD><TD>0.3838</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:07.92</TD><TD>8.16 MB</TD><TD>0.3921</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:13.88</TD><TD>8.28 MB</TD><TD>0.3977</TD></TR> + <TR><TD>WaveZip</TD><TD>0:13.11</TD><TD>8.72 MB</TD><TD>0.4193</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Maurice Ravel<BR><I>String Quartet (4th movement)</I><BR>56.18 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>1:29.26</TD><TD>20.87 MB</TD><TD>0.3715</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>3:51.42</TD><TD>21.46 MB</TD><TD>0.3820</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (high)</TD><TD>0:34.29</TD><TD>21.55 MB</TD><TD>0.3836</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>10:39.05</TD><TD>21.56 MB</TD><TD>0.3838</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, high)</TD><TD>6:28.14</TD><TD>22.30 MB</TD><TD>0.3969</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>1:28.02</TD><TD>22.32 MB</TD><TD>0.3972</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>8:13.86</TD><TD>22.38 MB</TD><TD>0.3983</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>0:43.84</TD><TD>22.53 MB</TD><TD>0.4010</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>flac 0.2 (-6)</TD><TD>3:00.34</TD><TD>22.85 MB</TD><TD>0.4067</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:29.33</TD><TD>23.63 MB</TD><TD>0.4205</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:38.05</TD><TD>25.58 MB</TD><TD>0.4552</TD></TR> + <TR><TD>WaveZip</TD><TD>0:36.60</TD><TD>25.84 MB</TD><TD>0.4600</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Sergei Prokofiev<BR><I>Piano Concerto No.3 (3rd movement)</I><BR>100.68 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>2:37.54</TD><TD>34.55 MB</TD><TD>0.3431</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>6:34.97</TD><TD>35.31 MB</TD><TD>0.3507</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (high)</TD><TD>1:00.47</TD><TD>35.46 MB</TD><TD>0.3521</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>10:12.47</TD><TD>35.74 MB</TD><TD>0.3549</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>18:34.20</TD><TD>35.80 MB</TD><TD>0.3555</TD></TR> + <TR><TD>LPAC 1.20 (-r, extra high)</TD><TD>12:18.79</TD><TD>35.83 MB</TD><TD>0.3558</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>2:33.43</TD><TD>36.05 MB</TD><TD>0.3580</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>1:17.06</TD><TD>37.88 MB</TD><TD>0.3762</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>flac 0.2 (-6)</TD><TD>5:15.13</TD><TD>38.56 MB</TD><TD>0.3830</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:50.03</TD><TD>39.34 MB</TD><TD>0.3907</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WaveZip</TD><TD>1:05.60</TD><TD>43.67 MB</TD><TD>0.4337</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>1:09.86</TD><TD>45.36 MB</TD><TD>0.4505</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Frederic Chopin<BR><I>Prelude No.24 in d minor</I><BR>27.46 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>0:42.69</TD><TD>10.53 MB</TD><TD>0.3834</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:19.69</TD><TD>10.77 MB</TD><TD>0.3921</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, high)</TD><TD>3:21.61</TD><TD>10.91 MB</TD><TD>0.3973</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>0:41.79</TD><TD>10.92 MB</TD><TD>0.3976</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>3:56.36</TD><TD>10.93 MB</TD><TD>0.3979</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>1:58.42</TD><TD>10.97 MB</TD><TD>0.3994</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>5:20.71</TD><TD>11.21 MB</TD><TD>0.4083</TD></TR> + <TR><TD>WavPack 3.6 (high)</TD><TD>0:22.32</TD><TD>11.52 MB</TD><TD>0.4193</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>flac 0.2 (-6)</TD><TD>1:26.66</TD><TD>11.77 MB</TD><TD>0.4285</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:13.56</TD><TD>12.01 MB</TD><TD>0.4374</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WaveZip</TD><TD>0:18.75</TD><TD>13.08 MB</TD><TD>0.4765</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:20.61</TD><TD>14.39 MB</TD><TD>0.5239</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + Domenico Scarlatti<BR><I>Sonata K.42 (arr.Yepes for guitar)</I><BR>16.39 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>0:25.79</TD><TD>6.96 MB</TD><TD>0.4245</TD></TR> + <TR><TD>RKAU 1.06 (high)</TD><TD>3:09.40</TD><TD>6.96 MB</TD><TD>0.4246</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (normal)</TD><TD>1:14.43</TD><TD>6.97 MB</TD><TD>0.4252</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:10.28</TD><TD>7.14 MB</TD><TD>0.4356</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>0:25.98</TD><TD>7.27 MB</TD><TD>0.4436</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>2:21.30</TD><TD>7.34 MB</TD><TD>0.4480</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>3:00.91</TD><TD>7.38 MB</TD><TD>0.4500</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>0:53.18</TD><TD>7.41 MB</TD><TD>0.4519</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:13.17</TD><TD>7.41 MB</TD><TD>0.4520</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:07.99</TD><TD>7.47 MB</TD><TD>0.4558</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WaveZip</TD><TD>0:10.56</TD><TD>7.83 MB</TD><TD>0.4781</TD></TR> + <TR><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:10.91</TD><TD>8.20 MB</TD><TD>0.5001</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + The Benedictine Monks of<BR>Santo Domingo de Silos<BR><I>Laetatus sum</I><BR>24.26 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>3:15.29</TD><TD>12.21 MB</TD><TD>0.5031</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>1:25.48</TD><TD>12.21 MB</TD><TD>0.5034</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>0:41.19</TD><TD>12.47 MB</TD><TD>0.5138</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>0:15.69</TD><TD>12.68 MB</TD><TD>0.5228</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, normal)</TD><TD>0:41.22</TD><TD>12.75 MB</TD><TD>0.5253</TD></TR> + <TR><TD>LPAC 1.20 (-r, high)</TD><TD>3:40.65</TD><TD>12.88 MB</TD><TD>0.5309</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>4:53.81</TD><TD>12.92 MB</TD><TD>0.5323</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>1:22.09</TD><TD>12.92 MB</TD><TD>0.5324</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>0:20.21</TD><TD>13.15 MB</TD><TD>0.5420</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>0:12.71</TD><TD>13.28 MB</TD><TD>0.5475</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>0:17.35</TD><TD>13.41 MB</TD><TD>0.5527</TD></TR> + <TR><TD>WaveZip</TD><TD>0:16.37</TD><TD>13.72 MB</TD><TD>0.5655</TD></TR> + <TR> + <TD ALIGN="RIGHT" ROWSPAN="13" BGCOLOR="#F4F4CC"> + L. Subramaniam<BR><I>Raga Sivapriya</I><BR>213.56 MB + </TD> + <TD> </TD><TD> </TD><TD> </TD><TD> </TD> + </TR> + <TR BGCOLOR="D3D4C5"><TD>RKAU 1.06 (high)</TD><TD>47:18.78</TD><TD>92.94 MB</TD><TD>0.4351</TD></TR> + <TR><TD>RKAU 1.06 (normal)</TD><TD>19:37.68</TD><TD>93.31 MB</TD><TD>0.4369</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Monkey's Audio (extra high)</TD><TD>5:51.97</TD><TD>95.30 MB</TD><TD>0.4462</TD></TR> + <TR><TD>Monkey's Audio (high)</TD><TD>2:14.54</TD><TD>97.52 MB</TD><TD>0.4566</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, high)</TD><TD>23:13.96</TD><TD>97.80 MB</TD><TD>0.4579</TD></TR> + <TR><TD>LPAC 1.20 (-r, normal)</TD><TD>5:46.84</TD><TD>98.04 MB</TD><TD>0.4590</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>LPAC 1.20 (-r, extra high)</TD><TD>30:04.06</TD><TD>98.10 MB</TD><TD>0.4593</TD></TR> + <TR><TD>flac 0.2 (-6)</TD><TD>11:47.13</TD><TD>98.76 MB</TD><TD>0.4624</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>WavPack 3.6 (high)</TD><TD>2:50.35</TD><TD>99.53 MB</TD><TD>0.4660</TD></TR> + <TR><TD>Shorten 2.3a (-p0 -b1024)</TD><TD>1:53.28</TD><TD>102.54 MB</TD><TD>0.4801</TD></TR> + <TR BGCOLOR="D3D4C5"><TD>Shorten 2.3a (-p8 -b2048)</TD><TD>2:34.37</TD><TD>102.59 MB</TD><TD>0.4803</TD></TR> + <TR><TD>WaveZip</TD><TD>2:25.86</TD><TD>107.47 MB</TD><TD>0.5032</TD></TR> + </TABLE> + </TD></TR></TABLE> + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/developers.html b/doc/developers.html new file mode 100644 index 00000000..e0cbef3d --- /dev/null +++ b/doc/developers.html @@ -0,0 +1,130 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - developers</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> developers </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">developers</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + FLAC is an open source project and we are happy to enlist the help of anyone who wants to contribute. You can do this to a limited extent through the <A HREF="http://sourceforge.net/mail/?group_id=13478">mailing list</A> but if you have major changes to make to the code it's best to <A HREF="http://sourceforge.net/project/memberlist.php?group_id=13478">sign up as a developer</A>. In either case, make sure to check out the <A HREF="goals.html">FLAC goals</A> first; there are some thing the we <B>don't</B> want added to FLAC, like copy protection and lossy compression. + </P> + <P> + There are several areas that are especially important: + </P> + <P> + <UL> + <LI> + Converging on the <A HREF="format.html">bitstream format</A>. This is probably the single most important issue. + </LI> + <LI> + Testing. This is a close second, since if you are a lossless encoder you have to be absolutely lossless for all input. The test suite has patterns that are designed to strain the encoder to the limit but more test cases would definitely help. + </LI> + <LI> + Makefile fixups and code changes to work on more platforms. Both libFLAC and flac are ANSI C and use only the standard C library and math library, meaning ports should not be that difficult. Currently there is a GNU make system and makefiles for MSVC. + </LI> + <LI> + More input plugins. Currently there are plugins for XMMS and Winamp. More is better! + </LI> + <LI> + Speeding up the encoding. Encoding speed at average compression is a little slower than I would like. Improvements to the reference encoder that don't drastically obfuscate the code would be welcome. + </LI> + </UL> + </P> + <P> + Some other "nice-to-haves": + </P> + <P> + <UL> + <LI> + Improving the compression methods. Some suggestions: on the entropy coding side, try context-modeling the Rice paramter, using general Golomb coding and Huffman coding. On the prediction side, try some other methods for determining the LP coefficients (covariance method, Marple, Burg), or explore other kinds of modeling. + </LI> + <LI> + A faster seek algorithm in the file decoder. + </LI> + <LI> + A stream analyser that gives useful statistics for tuning or testing new algorithms. + </LI> + <LI> + Fix the MSVC makefiles to make libFLAC.dll (instead of just the .lib). + </LI> + <LI> + Clean up the Winamp2 plugin and/or write a Winamp3 one. + </LI> + <LI> + Configurable ID3V1 support and ID3V2 support in the plugins. + </LI> + <LI> + Better encoding decoding statistics for flac. + </LI> + <LI> + Support more input types than just WAVE and raw in flac. + </LI> + <LI> + Expand the test suite. + </LI> + <LI> + A better logo! Gimp jedi I'm not... + </LI> + </UL> + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/documentation.html b/doc/documentation.html new file mode 100644 index 00000000..4b387c9a --- /dev/null +++ b/doc/documentation.html @@ -0,0 +1,454 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - documentation</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> documentation </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">documentation</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + This page describes the user-level view of the FLAC format (for a more detailed explanation see the <A HREF="format.html">format page</A>). It also contains the user documentation for <B><TT>flac</TT></B>, which is the command-line file encoder/decoder, and the <A HREF="#plugins">input plugins</A>. + </P> + <P> + Keep in mind that the online version of this document will always apply to the latest release. For older releases, check the documentation included with the release package. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">format</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + See the <A HREF="format.html#scope">Scope</A>, <A HREF="format.html#architecture">Architecture</A>, <A HREF="format.html#definitions">Definitions</A>, and <A HREF="format.html#overview">Overview</A> sections of the <A HREF="format.html">format page</A> for a good introduction. This section will be expanded in the future. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">flac</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + <B><TT>flac</TT></B> is the command-line file encoder/decoder. The input to the encoder and the output to the decoder must either be RIFF WAVE format, or raw interleaved sample data. <B><TT>flac</TT></B> only supports linear PCM samples (in other words, no A-LAW, uLAW, etc.). Another restriction (hopefully short-term) is that the input must be 8 or 16 bits per sample. This is not a limitation of the FLAC format, just the reference encoder. + </P> + <P> + <B><TT>flac</TT></B> assumes that RIFF WAVE files will have the extension ".wav"; this may be overridden with a command-line option. Other than this, <B><TT>flac</TT></B> makes no assumptions about file extensions, though the convention is that FLAC files have the extension ".flac" (or ".fla" on ancient file systems like FAT-16). + </P> + <P> + Before going into the full command-line description, two other things help to sort it out: 1) <B><TT>flac</TT></B> encodes by default, so you must use <B>-d</B> to decode; 2) the options <B><TT>-0</TT></B> .. <B><TT>-9</TT></B> that control the compression level actually are just synonyms for different groups of specific coding options (described later). You can get the same effect by using the same options. + </P> + <P> + <B><TT>flac</TT></B> will be invoked one of two ways, depending on whether you are encoding or decoding: + <UL> + <LI> + Encoding: flac [-v] [--skip #] [<format-options>] [<encoding options>] inputfile outputfile + </LI> + <LI> + Decoding: flac -d [-v] [--skip #] [<format-options>] inputfile outputfile + </LI> + </UL> + </P> + <P> + In either case, inputfile may be "-" for stdin, and "-" for stdout. The encoding options affect the compression ratio and encoding speed. The format options are used to tell <B><TT>flac</TT></B> the arrangement of samples if the input file (or output file when decoding) is a raw file. If it is a RIFF WAVE file the format options are not needed since they are read from the WAVE header. + </P> + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <FONT SIZE="+1"><B>General Options</B></FONT> + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -d + </TD> + <TD> + Decode (<B><TT>flac</TT></B> encodes by default). + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -s + </TD> + <TD> + Silent: do not show encoding/decoding statistics. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + --skip # + </TD> + <TD> + Skip over the first # of samples of the input. This works for both encoding and decoding. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <FONT SIZE="+1"><B>Encoding Options</B></FONT> + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + --lax + </TD> + <TD> + Allow encoder to generate non-Subset files. The resulting FLAC file may not be streamable, so you should only use this option in combination with custom encoding options meant for archival. File decoders will still be able play (and seek in) such files. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -b # + </TD> + <TD> + Set the blocksize. The default is 1152 for -l 0, otherwise 4608. Subset streams must use one of 192/576/1152/2304/4608. The current encoder uses the same blocksize for the entire stream. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -m + </TD> + <TD> + Enable mid-side coding (only for stereo streams). Tends to increase compression by a few percent on average. For each block both the stereo pair and mid-side versions of the block will be encoded, and smallest resulting frame will be stored. Currently mid-side encoding is only available when bits-per-sample <= 16. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -0 .. -9 + </TD> + <TD> + Fastest compression .. highest compression. The default is <TT>-6</TT>. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -0 + </TD> + <TD> + Synonymous with -l 0 + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -1 + </TD> + <TD> + Synonymous with -l 0 -m + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -2 + </TD> + <TD> + Synonymous with -l 0 -m -r # (where # is set based on the blocksize) + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -3 + </TD> + <TD> + Reserved + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -4 + </TD> + <TD> + Synonymous with -l 8 + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -5 + </TD> + <TD> + Synonymous with -l 8 -m + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -6 + </TD> + <TD> + Synonymous with -l 8 -m -r # (where # is set based on the blocksize) + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -7 + </TD> + <TD> + Reserved + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -8 + </TD> + <TD> + Synonymous with -l 32 -m -r # (where # is set based on the blocksize) + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -9 + </TD> + <TD> + Synonymous with -l 32 -m -e -r 99 -p. This is painfully slow but gives you the maximum compression <B><TT>flac</TT></B> can do for a given blocksize. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -e + </TD> + <TD> + Exhaustive model search (expensive!). Normally the encoder estimates the best model to use and encodes once based on the estimate. With an exhaustive model search, the encoder will generate subframes for every order and use the smallest. If the max LPC order is high this can significantly increase the encode time but can shave off another 0.5%. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -l # + </TD> + <TD> + Specifies the maximum LPC order. This number must be <= 32. If 0, the encoder will not attempt generic linear prediction, and use only fixed predictors. Using fixed predictors is faster but usually results in files being 5-10% larger. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -q # + </TD> + <TD> + Specifies the precision of the quantized LP coefficients, in bits. The default is <B><TT>-q 0</TT></B>, which means let the encoder decide based on the signal. Unless you really know your input file it's best to leave this up to the encoder. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -p + </TD> + <TD> + Do exhaustive LP coefficient quantization optimization. This option overrides any <B><TT>-q</TT></B> option. It is expensive and typically will only improve the compression a tiny fraction of a percent. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -r # + </TD> + <TD> + Do Rice parameter optimization. By default the encoder uses a single Rice parameter for the subframe's entire residual. With this option, the residual is partitioned into 2^n pieces, each with its own Rice parameter. Higher values of n yield diminishing returns. The most bang for the buck is usually with <B><TT>-r 2</TT></B> (more for higher blocksizes). This usually shaves off another 1.5%. The technique tends to peak out about when blocksize/(2^n)=128. Use <B><TT>-r 99</TT></B> to force the highest degree of optimization. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + </TD> + <TD> + -m-, -e-, -p-, --lax- can all be used to turn off a particular option. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <FONT SIZE="+1"><B>Format Options</B></FONT> + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fb | -fl + </TD> + <TD> + Specify big-endian | little-endian byte order in the raw file. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fc # + </TD> + <TD> + Specify the number of channels in the raw file. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fp # + </TD> + <TD> + Specify the number of bits per sample in the raw file. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fs # + </TD> + <TD> + Specify the sample rate of the raw file. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fu + </TD> + <TD> + Specify that the samples in the raw file are unsigned (the default is signed). + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fr + </TD> + <TD> + Treat the input file (or output file if decoding) as a raw file, regardless of the extension. + </TD> + </TR> + <TR> + <TD NOWRAP ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + -fw + </TD> + <TD> + Treat the input file (or output file if decoding) as a RIFF WAVE file, regardless of the extension. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <A NAME="plugins"><B><FONT SIZE="+2">xmms plugin</FONT></B></A> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + All that is necessary is to copy <B><TT>libxmms-flac.so</TT></B> to the directory where XMMS looks for input plugins (usually <B><TT>/usr/lib/xmms/Input</TT></B>). There is nothing else to configure. Make sure to restart XMMS before trying to play any .flac files. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">winamp plugin</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + All that is necessary is to copy <B><TT>in_flac.dll</TT></B> to the <B><TT>Plugins/</TT></B> directory of your Winamp installation. There is nothing else to configure. Make sure to restart Winamp before trying to play any .flac files. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/download.html b/doc/download.html new file mode 100644 index 00000000..165ba1b2 --- /dev/null +++ b/doc/download.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - download</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> download </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">download</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + This page will be updated once the CVS repository is set up and the first release is made. Check back soon or <A HREF="http://sourceforge.net/mail/?group_id=13478">join the mailing list</A>. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/features.html b/doc/features.html new file mode 100644 index 00000000..127b77a5 --- /dev/null +++ b/doc/features.html @@ -0,0 +1,142 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - features</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> features </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">features</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + FLAC stands for Free Lossless Audio Coder. The FLAC project consists of: + </P> + <P> + <UL> + <LI>the stream format</LI> + <LI>libFLAC, which implements a reference encoder, stream decoder, and file decoder</LI> + <LI>flac, which is a command-line wrapper around libFLAC to encode and decode .flac files</LI> + <LI>input plugins for various music players (Winamp, XMMS, and more in the works)</LI> + </UL> + </P> + <P> + "Free" means that the specification of the stream format is in the public domain (the FLAC project reserves the right to set the FLAC specification and certify compliance), and that neither the FLAC format nor any of the implemented encoding/decoding methods are covered by any patent. It also means that the source for libFLAC is available under the <A HREF="http://www.opensource.org/licenses/lgpl-license.html">LGPL</A> and the sources for flac and the plugins are available under the <A HREF="http://www.opensource.org/licenses/gpl-license.html">GPL</A>. + </P> + <P> + What FLAC is: + </P> + <UL> + <P><LI> + FLAC is patent free. The FLAC format or encoding/decoding methods are not covered by any patents. + </LI></P> + <P><LI> + FLAC is lossless. The encoding of PCM data incurs no loss of information, and the decoded audio is bit-for-bit identical to what went into the encoder. + </LI></P> + <P><LI> + FLAC is designed to compress audio data. Technically, flac can "compress" other kinds of data losslessly (if you pass it in as a mono 8-bit raw file), but the output files tend to be bigger. + </LI></P> + <P><LI> + The compression capabilities of FLAC are extendable, meaning that new methods can be added to future versions of the format without breaking older streams or decoders. + </LI></P> + <P><LI> + The currently implemented compression methods in the reference encoder yield streams on par or smaller than shorten. The encoding time is variable, but is generally between that of <A HREF="http://www.softsound.com/Shorten.html">shorten</A>, and that of, say, <A HREF="http://www.mp3dev.org/mp3/">LAME</A>. The most aggressive compression however can be quite slow. For more info see the <A HREF="comparison.html">comparison page</A>. + </LI></P> + <P><LI> + FLAC is asymmetric in favor of decode speed. Decoding requires only integer arithmetic, and is much less compute-intensive than for most perceptual codecs. Real-time decode performance is easily achievable on even modest hardare. + </LI></P> + <P><LI> + FLAC is suitable for archiving, since there is no information loss. You are not locked into the format since there is no generation loss if you decide to convert your data to another format in the future. + </LI></P> + <P><LI> + FLAC is suitable for streaming. Each FLAC frame contains enough data to decode that frame. FLAC does not even rely on previous or following frames. FLAC uses sync codes and CRCs (similar to MPEG and other formats), which, along with framing, allow decoders to pick up in the middle of a stream with a minimum of delay. + </LI></P> + <P><LI> + FLAC supports fast sample-accurate seeking. Not only is this useful for playback, it makes FLAC files suitable for use in editing applications. + </LI></P> + <P><LI> + FLAC has an extendable meta-data system. New meta-data blocks can be defined and implemented in future versions of FLAC without breaking older streams or decoders. ID3 and ID3V2 tags may be attached to .flac files without disrupting the decoder. + </LI></P> + </UL> + <P> + Some things that follow from the features: + </P> + <UL> + <P><LI> + FLAC streams can be played back consecutively with no audible gaps in between, unlike say, MP3s (this is one of the minor <A HREF="goals.html">goals</A>). For example, you can encode a live album as individual tracks and still play them back seamlessly. + </LI></P> + <P><LI> + The sample-accurate seeking allows versatile playback: a sophisticated player could do index points, complex looping, or other structured playback. This could be useful in for say DJs, or practice sessions where you want to play along through specific passages. + </LI></P> + <P><LI> + Basically, you get the versatility of a WAV file in a compressed streamable format. + </LI></P> + </UL> + <P> + What FLAC is <B>not</B>: + </P> + <UL> + <P><LI> + Lossy. FLAC is intended for lossless compression only, as there are many good lossy formats already, such as <A HREF="http://www.mp3-tech.org/">MP3</A> (see <A HREF="http://www.mp3dev.org/mp3/">LAME</A> for an excellent open-source implementation), and <A HREF="http://www.xiph.org/ogg/vorbis/index.html">Ogg Vorbis</A>. + </LI></P> + <P><LI> + SDMI compliant, et cetera. There is no intention to support any methods of copy protection, which are, for all practical purposes, a complete waste of bits. (Another way to look at it is that since copy protection is futile, it really carries no information, so you might say FLAC already losslessly compresses all possible copy protection information down to zero bits!) Of course, we can't stop what some misguided person does with proprietary meta-data blocks, but then again, non-proprietary decoders will skip them anyway. + </LI></P> + </UL> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/format.html b/doc/format.html new file mode 100644 index 00000000..6b73b607 --- /dev/null +++ b/doc/format.html @@ -0,0 +1,1092 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - format</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> format </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">format</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + This is a detailed description of the FLAC format. The format is still in an alpha stage, which means it can change (even breaking old streams) until the first beta, so if you are a developer, <A HREF="http://sourceforge.net/mail/?group_id=13478">join the mailing list</A> or check back regularly. + </P> + <P> + First, as the original developer I have to say that I am not a compression expert and I feel obligated to give credit where it is due. FLAC owes a lot to the many people who have advanced the audio compression field so freely. For instance: + </P> + <P> + <UL> + <LI> + <A HREF="http://svr-www.eng.cam.ac.uk/~ajr/">A. J. Robinson</A> for his work on <A HREF="http://svr-www.eng.cam.ac.uk/~ajr/GroupPubs/Robinson94-tr156/index.html">Shorten</A>; his code and paper are a good starting point on some of the basic methods used by FLAC. FLAC expands on the fixed predictors used in shorten. + </LI> + <LI> + <A HREF="http://commsci.usc.edu/faculty/golomb.html">S. W. Golomb</A> and Robert F. Rice; their universal codes are used by FLAC's entropy coder. + </LI> + <LI> + N. Levinson and J. Durbin; the reference encoder uses an algorithm developed and refined by them for determining the LPC coefficients from the autocorrelation coefficients. + </LI> + <LI> + And of course, the main guy, <A HREF="http://www.digitalcentury.com/encyclo/update/shannon.html">Claude Shannon</A> + </LI> + </UL> + </P> + <P> + <A NAME="scope"><FONT SIZE="+1"><B><U>Scope</U></B></FONT></A> + </P> + <P> + It is a known fact that no algorithm can losslessly compress all possible input, so most compressors restrict themselves to a useful domain and try to work as well as possible within that domain. FLAC's domain is audio data. Though it can losslessly code any input, only certain kinds of input will get smaller. FLAC exploits the fact that audio data typically has a high degree of sample-to-sample correlation. + </P> + <P> + Within the audio domain, there are many possible subdomains. For example: low bitrate speech, high-bitrate multi-channel music, etc. FLAC itself does not target a specific subdomain but many of the default parameters of the reference encoder are tuned to CD-quality music data (i.e. 44.1kHz, 2 channel, 16 bits per sample). The effect of the encoding parameters on different kinds of audio data will be examined later. + </P> + <P> + <A NAME="architecture"><FONT SIZE="+1"><B><U>Architecture</U></B></FONT></A> + </P> + <P> + Similar to many audio coders, a FLAC encoder has the following stages: + </P> + <UL> + <P><LI> + <A HREF="#blocking">Blocking</A>. The input is broken up into many contiguous blocks. With FLAC, the blocks may vary in size. The optimal size of the block is usually affected by many factors, including the sample rate, spectral characteristics over time, etc. Though FLAC allows the block size to vary within a stream, the reference encoder uses a fixed block size. + </LI></P> + <P><LI> + <A HREF="#interchannel">Interchannel Decorrelation</A>. In the case of stereo streams, the encoder will create mid and side signals based on the average and difference (respectively) of the left and right channels. The encoder will then pass the best form of the signal to the next stage. + </LI></P> + <P><LI> + <A HREF="#prediction">Prediction</A>. The block is passed through a prediction stage where the encoder tries to find a mathematical description (usually an approximate one) of the signal. This description is typically much smaller than the raw signal itself. Since the methods of prediction are known to both the encoder and decoder, only the parameters of the predictor need be included in the compressed stream. FLAC currently uses four different classes of predictors (described in the <A HREF="#prediction">prediction</A> section), but the format has reserved space for additional methods. FLAC allows the class of predictor to change from block to block, or even within the channels of a block. + </LI></P> + <LI><P> + <A HREF="#residualcoding">Residual coding</A>. If the predictor does not describe the signal exactly, the difference between the original signal and the predicted signal (called the error or residual signal) must be coded losslessy. If the predictor is effective, the residual signal will require fewer bits per sample than the original signal. FLAC currently uses only one method for encoding the residual (see the <A HREF="#residualcoding">Residual coding</A> section), but the format has reserved space for additional methods. FLAC allows the residual coding method to change from block to block, or even within the channels of a block. + </LI></P> + </UL> + <P> + In addition, FLAC specifies a metadata system, which allows arbitrary information about the stream to be included at the beginning of the stream. + </P> + <P> + <A NAME="definitions"><FONT SIZE="+1"><B><U>Definitions</U></B></FONT></A> + </P> + <P> + Many terms like "block" and "frame" are used to mean different things in differenct encoding schemes. For example, a frame in MP3 corresponds to many samples across several channels, whereas an S/PDIF frame represents just one sample for each channel. The definitions we use for FLAC follow. Note that when we talk about blocks and subblocks we are refering to the raw unencoded audio data that is the input to the encoder, and when we talk about frames and subframes, we are refering to the FLAC-encoded data. + </P> + <UL> + <P><LI> + <B>Block</B>: One or more audio samples that span several channels. + </LI></P> + <P><LI> + <B>Subblock</B>: One or more audio samples within a channel. So a block contains one subblock for each channel, and all subblocks contain the same number of samples. + </LI></P> + <P><LI> + <B>Blocksize</B>: The number of samples in any of a block's subblocks. For example, a one second block sampled at 44.1KHz has a blocksize of 44100, regardless of the number of channels. + </LI></P> + <P><LI> + <B>Frame</B>: A frame header plus one or more subframes. + </LI></P> + <P><LI> + <B>Subframe</B>: A subframe header plus one or more encoded samples from a given channel. All subframes within a frame will contain the same number of samples. + </LI></P> + </UL> + <P> + <A NAME="blocking"><FONT SIZE="+1"><B><U>Blocking</U></B></FONT></A> + </P> + <P> + The size used for blocking the audio data has a direct effect on the compression ratio. If the block size is too small, the resulting large number of frames mean that excess bits will be wasted on frame headers. If the block size is too large, the characteristics of the signal may vary so much that the encoder will be unable to find a good predictor. In order to simplify encoder/decoder design, FLAC imposes a minimum block size of 16 samples, and a maximum block size of 65535 samples. This range covers the optimal size for all of the audio data FLAC supports. + </P> + <P> + Currently the reference encoder uses a fixed block size, optimized on the sample rate of the input. Future version may vary the block size depending on the characteristics of the signal. + </P> + <P> + Blocked data is passed to the predictor stage one subblock (channel) at a time. Each subblock is independently coded into a subframe, and the subframes are concatenated into a frame. Because each channel is coded independently, it means that one channel of a stereo frame may be encoded as a constant subframe, and the other an LPC subframe. The FLAC format has reserved space for supporting mid-side coding of stereo data, but it is currently not defined or implemented in the reference codec. + </P> + <P> + <A NAME="interchannel"><FONT SIZE="+1"><B><U>Interchannel Decorrelation</U></B></FONT></A> + </P> + <P> + In stereo streams, in many cases there is an exploitable amount of correlation between the left and right channels. FLAC allows the frames of stereo streams to have different channel assignments, and an encoder may choose to use the best representation on a frame-by-frame basis. + </P> + <UL> + <P><LI> + <B>Independent</B>. The left and right channels are coded independently. + </LI></P> + <P><LI> + <B>Mid-side</B>. The left and right channels are transformed into mid and side channels. The mid channel is the midpoint (average) of the left and right signals, and the side is the difference signal (left minus right). + </LI></P> + <P><LI> + <B>Left-side</B>. The left channel and side channel are coded. + </LI></P> + <P><LI> + <B>Right-side</B>. The right channel and side channel are coded + </LI></P> + </UL> + <P> + Surprisingly, the left-side and right-side forms can be the most efficient in many frames, even though the raw number of bits per sample needed for the original signal is slightly more than that needed for independent or mid-side coding. + </P> + <P> + <A NAME="prediction"><FONT SIZE="+1"><B><U>Prediction</U></B></FONT></A> + </P> + <P> + FLAC uses four methods for modeling the input signal: + </P> + <UL> + <P><LI> + <B>Verbatim</B>. This is essentially a zero-order predictor of the signal. The predictor of the signal is the signal itself, so the compression is zero. This is the baseline against which the other predictors are measured. If you feed random data to the encoder, the verbatim predictor will probably be used for every subblock. Since the raw signal is not actually passed through the residual coding stage (it is added to the stream 'verbatim'), the encoding results will not be the same as a zero-order linear predictor. + </LI></P> + <P><LI> + <B>Constant</B>. This predictor is used whenever the subblock contains digital silence, i.e. a constant value throughout. The signal is run-length encoded and added to the stream. + </LI></P> + <P><LI> + <B>Fixed linear predictor</B>. FLAC uses a class of computationally-efficient fixed linear predictors (for a good description, see <A HREF="http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf">audiopak</A> and <A HREF="http://svr-www.eng.cam.ac.uk/~ajr/GroupPubs/Robinson94-tr156/index.html">shorten</A>). FLAC adds a fourth-order predictor to the zero-to-third-order predictors used by shorten. Since the predictors are fixed, the predictor order is the only parameter that needs to be stored in the compressed stream. The error signal is then passed to the residual coder. + </LI></P> + <P><LI> + <B>FIR Linear prediction</B>. For more accurate modeling (at a cost of slower encoding), FLAC supports up to 32nd order FIR linear prediction (again, for info on linear prediction, see <A HREF="http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf">audiopak</A> and <A HREF="http://svr-www.eng.cam.ac.uk/~ajr/GroupPubs/Robinson94-tr156/index.html">shorten</A>). The reference encoder uses the Levinson-Durbin method for calculating the LPC coefficients from the autocorrelation coefficients, and the coefficients are quantized before computing the residual. Whereas encoders such as shorten used a fixed quantization for the entire input, FLAC allows the quantized coefficient precision to vary from subframe to subframe. The FLAC reference encoder estimates the optimal precision to use based on the block size and dynamic range of the original signal. + </LI></P> + </UL> + <P> + <A NAME="residualcoding"><FONT SIZE="+1"><B><U>Residual Coding</U></B></FONT></A> + </P> + <P> + FLAC currently defines two similar methods for the coding of the error signal from the prediction stage. The error signal is coded using Rice codes in one of two ways: 1) the encoder estimates a single rice parameter based on the variance of the residual, and Rice codes the entire residual using this parameter; 2) the residual is partitioned into several equal-length regions of contiguous samples, and each region is coded with its own Rice parameter based on the region's mean. (Note that the first method is a special case of the second method with one partition, except the Rice parameter is based on the residual variance instead of the mean.) + </P> + <P> + The FLAC format has reserved space for other coding methods. Some possiblities for volunteers would be to explore better context-modeling of the Rice parameter, generic Golomb coding (Rice codes are a subset of Golomb codes where the Rice parameter k is the Golomb parameter m = 2^k), and Huffman coding. See <A HREF="http://www.hpl.hp.com/techreports/98/HPL-98-193.html">LOCO-I</A> and <A HREF="http://www.cs.tut.fi/~albert/Dev/pucrunch/packing.html">pucrunch</A> for descriptions of several universal codes. + </P> + <P> + <FONT SIZE="+1"><B><U>Format</U></B></FONT> + </P> + <P> + This section specifies the FLAC bitstream format. FLAC has no format version information, but it does contain reserved space in several places. Future versions of the format may use this reserved space safely without breaking the format of older streams. Older decoders may choose to abort decoding or skip data encoded with newer methods. Apart from reserved patterns, in places the format specifies invalid patterns, meaning that the patterns may never appear in any valid bitstream, in any prior, present, or future versions of the format. These invalid patterns are usually used to make the synchronization mechanism more robust. + </P> + <P> + All numbers used in a FLAC bitstream are integers; there are no floating-point representations. All numbers are big-endian coded. All numbers are unsigned unless otherwise specified. + </P> + <P> + <A NAME="overview">A FLAC bitstream may be appended with ID3V1 data or prepended with ID3V2 data. FLAC has no knowledge of such data, but the reference decoder knows how to skip an ID3 tag. The input plugins support ID3V1 tags</A> + </P> + <P> + Before the formal description of the stream, an overview might be helpful. + </P> + <UL> + <P><LI> + A FLAC bitstream consists of the "fLaC" marker at the beginning of the stream, followed by a mandatory metadata block (called the 'Encoding' block), any number of other metadata blocks, then the audio frames. + </LI></P> + <P><LI> + FLAC supports up to 128 kinds of metadata blocks, but currently only one is defined. This is the 'Encoding' block, which has info about the whole stream like sample rate, number of channels, total number of samples, etc. This block must be present as the first metadata block in the stream. Other metadata blocks may follow, and ones that the decoder doesn't understand, it will skip. + </LI></P> + <P><LI> + The audio data is composed of one or more audio frames. Each frame consists of a frame header, which contains a sync code, info about the frame like the block size, sample rate, number of channels, et cetera, and an 8-bit CRC. The frame header also contains either the sample number of the first sample in the frame (for variable-blocksize streams), or the frame number (for fixed-blocksize streams). This allows for fast, sample-accurate seeking to be performed. Following the frame header are encoded subframes, one for each channel, and finally, the frame is zero-padded to a byte boundary. Each subframe has its own header that specifies how the subframe is encoded. + </LI></P> + <P><LI> + Since a decoder may start decoding in the middle of a stream, there must be a method to determine the start of a frame. A 9-bit sync code begins every frame. The sync code will not appear anywhere else in the frame header. However, since it may appear in the subframes, the decoder has two other ways of ensuring a correct sync. The first is to check that the rest of the frame header contains no invalid data. Even this is not foolproof since valid header patterns can still occur within the subframes. The decoder's final check is to generate an 8-bit CRC of the frame header and compare this to the CRC stored at the end of the frame header. + </LI></P> + <P><LI> + Again, since a decoder may start decoding at an arbitrary frame in the stream, each frame header must contain some basic information about the stream because the decoder may not have access to the ENCODING metadata block at the start of the stream. This information includes sample rate, bits per sample, number of channels, etc. Since the frame header is pure overhead, it has a direct effect on the compression ratio. To keep the frame header as small as possible, FLAC uses lookup tables for the most commonly used values for frame parameters. For instance, the sample rate part of the frame header is specified using 4 bits. Eight of the bit patterns correspond to the commonly used sample rates of 8/16/22.05/24/32/44.1/48/96 kHz. However, odd sample rates can be specified by using one of the 'hint' bit patterns, directing the decoder to find the exact sample rate at the end of the frame header. The same method is used for specifying the block size and bits per sample. In this way, the frame header size stays small for all of the most common forms of audio data. + </LI></P> + <P><LI> + Individual subframes (one for each channel) are coded separately within a frame, and appear serially in the stream. In other words, the encoded audio data is NOT channel-interleaved. This reduces decoder complexity at the cost of requiring larger decode buffers. Each subframe has its own header specifying the attributes of the subframe, like prediction method and order, residual coding parameters, etc. The header is followed by the encoded audio data for that channel. + </LI></P> + <P><LI> + FLAC specifies a subset of itself as the Subset format. The purpose of this is to ensure that any streams encoded according to the Subset are truly "streamable", meaning that a decoder that cannot seek within the stream can still pick up in the middle of the stream and start decoding. It also makes hardware decoder implementations more practical by limiting the blocking such that decoder buffer sizes can be easily determined. "flac" generates Subset streams by default unless the "--lax" command-line option is used. The Subset makes the following limitations on what may be used in the stream: + <UL> + <LI> + The blocksize bits in the <A HREF="#frame_header">frame header</A> must be 001-101, specifying a fixed-blocksize stream (the exception being the last block as described in the table). This also means that the Encoding metadata block must specify equal mininum and maximum blocksizes. + </LI> + <LI> + The bits-per-sample bits in the <A HREF="#frame_header">frame header</A> must be 001-110. + </LI> + <LI> + The sample rate bits in the <A HREF="#frame_header">frame header</A> must be 0001-1011. + </LI> + </UL> + </LI></P> + </UL> + + <P> + The following tables constitute a formal description of the FLAC format. Numbers in angle brackets indicate how many bits are used for a given field. + </P> + + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="stream"><FONT SIZE="+1"><B>STREAM</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <32> + </TD> + <TD> + "fLaC", the FLAC stream marker in ASCII, meaning byte 0 of the stream is 0x66, followed by 0x4C 0x61 0x43 + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_encoding_block"><I>METADATA_ENCODING_BLOCK</I></A> + </TD> + <TD> + This is the mandatory metadata block that has the basic properties of the stream + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block"><I>METADATA_BLOCK</I></A>* + </TD> + <TD> + Zero or more metadata blocks + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#frame"><I>FRAME</I></A>+ + </TD> + <TD> + One or more audio frames + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="metadata_block"><FONT SIZE="+1"><B>METADATA_BLOCK</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block_header"><I>METADATA_BLOCK_HEADER</I></A> + </TD> + <TD> + A block header that specifies the type and size of the metadata block data. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block_data"><I>METADATA_BLOCK_DATA</I></A> + </TD> + <TD> + + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="metadata_encoding_block"><FONT SIZE="+1"><B>METADATA_ENCODING_BLOCK</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block_header"><I>METADATA_BLOCK_HEADER</I></A> + </TD> + <TD> + A block header that specifies the ENCODING BLOCK + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block_encoding"><I>METADATA_BLOCK_ENCODING</I></A> + </TD> + <TD> + + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="metadata_block_header"><FONT SIZE="+1"><B>METADATA_BLOCK_HEADER</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <1> + </TD> + <TD> + Last-metadata-block flag: '1' if this block is the last metadata block before the audio blocks, '0' otherwise. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <7> + </TD> + <TD> + BLOCK_TYPE<BR> + <UL> + <LI> + <TT>0</TT> : ENCODING + </LI> + <LI> + <TT>1-127</TT> : reserved + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <24> + </TD> + <TD> + Length (in bytes) of metadata to follow (does not include the size of the METADATA_BLOCK_HEADER) + </TD> + </TR> + <TR> + <TD> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1">NOTES</FONT><BR> + <UL> + <LI> + Currently, FLAC specifies only one metadata block, the ENCODING block. Its presence as the first metadata block in the stream is mandatory. + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="metadata_block_data"><FONT SIZE="+1"><B>METADATA_BLOCK_DATA</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#metadata_block_encoding"><I>METADATA_BLOCK_ENCODING</I></A> + </TD> + <TD> + Currently, FLAC specifies only one metadata block, the ENCODING block. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="metadata_block_encoding"><FONT SIZE="+1"><B>METADATA_BLOCK_ENCODING</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <16> + </TD> + <TD> + The minimum block size (in samples) used in the stream. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <16> + </TD> + <TD> + The maximum block size (in samples) used in the stream. (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <16> + </TD> + <TD> + The minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <16> + </TD> + <TD> + The maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <20> + </TD> + <TD> + Sample rate in Hz. Though 20 bits are available, the maximum sample rate is limited by the structure of frame headers to 1048570Hz. Also, a value of 0 is invalid. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <3> + </TD> + <TD> + (number of channels)-1. FLAC supports from 1 to 8 channels + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <5> + </TD> + <TD> + (bits per sample)-1. FLAC supports from 1 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <36> + </TD> + <TD> + Total samples in stream. 'Samples' means channel-wide sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. A value of zero here means the number of total samples is unknown. + </TD> + </TR> + <TR> + <TD> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1">NOTES</FONT><BR> + <UL> + <LI> + FLAC specifies a minimum block size of 16 and a maximum block size of 65535, meaning the bit patterns corresponding to the numbers 0-15 in the minimum blocksize and maximum blocksize fields are invalid. + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="frame"><FONT SIZE="+1"><B>FRAME</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#frame_header"><I>FRAME_HEADER</I></A> + </TD> + <TD> + nbsp; + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#subframe"><I>SUBFRAME</I></A>+ + </TD> + <TD> + One SUBFRAME per channel. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <?> + </TD> + <TD> + Zero-padding to byte alignment. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="frame_header"><FONT SIZE="+1"><B>FRAME_HEADER</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <9> + </TD> + <TD> + sync code '<TT>111111110</TT>' + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <3> + </TD> + <TD> + block size in channel-wide samples:<BR> + <UL> + <LI> + <TT>000</TT> : get from ENCODING metadata block + </LI> + <LI> + <TT>001</TT> : 192 samples + </LI> + <LI> + <TT>010-101</TT> : 576 * (2^(2-n)) samples, i.e. 576/1152/2304/4608 + </LI> + <LI> + <TT>110</TT> : get 8 bit (blocksize-1) from end of header + </LI> + <LI> + <TT>111</TT> : get 16 bit (blocksize-1) from end of header + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <4> + </TD> + <TD> + sample rate:<BR> + <UL> + <LI> + <TT>0000</TT> : get from ENCODING metadata block + </LI> + <LI> + <TT>0001-0011</TT> : reserved + </LI> + <LI> + <TT>0100</TT> : 8kHz + </LI> + <LI> + <TT>0101</TT> : 16kHz + </LI> + <LI> + <TT>0110</TT> : 22.05kHz + </LI> + <LI> + <TT>0111</TT> : 24kHz + </LI> + <LI> + <TT>1000</TT> : 32kHz + </LI> + <LI> + <TT>1001</TT> : 44.1kHz + </LI> + <LI> + <TT>1010</TT> : 48kHz + </LI> + <LI> + <TT>1011</TT> : 96kHz + </LI> + <LI> + <TT>1100</TT> : get 8 bit sample rate (in kHz) from end of header + </LI> + <LI> + <TT>1101</TT> : get 16 bit sample rate (in Hz) from end of header + </LI> + <LI> + <TT>1110</TT> : get 16 bit sample rate (in tens of Hz) from end of header + </LI> + <LI> + <TT>1111</TT> : invalid, to prevent sync-fooling string of 1s + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <4> + </TD> + <TD> + channel assignment + <UL> + <LI> + <TT>0000-0111</TT> : (number of independent channels)-1. when == 0001, channel 0 is the left channel and channel 1 is the right + </LI> + <LI> + <TT>1000</TT> : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel + </LI> + <LI> + <TT>1001</TT> : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel + </LI> + <LI> + <TT>1010</TT> : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel + </LI> + <LI> + <TT>1011-1111</TT> : reserved + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <3> + </TD> + <TD> + sample size in bits:<BR> + <UL> + <LI> + <TT>000</TT> : get from ENCODING metadata block + </LI> + <LI> + <TT>001</TT> : 8 bits per sample + </LI> + <LI> + <TT>010</TT> : 12 bits per sample + </LI> + <LI> + <TT>011</TT> : reserved + </LI> + <LI> + <TT>100</TT> : 16 bits per sample + </LI> + <LI> + <TT>101</TT> : 20 bits per sample + </LI> + <LI> + <TT>110</TT> : 24 bits per sample + </LI> + <LI> + <TT>111</TT> : reserved + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <1> + </TD> + <TD> + zero bit padding, to prevent sync-fooling string of 1s + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <?> + </TD> + <TD> + if(variable blocksize)<BR> + <8-56>:"UTF-8" coded sample number (decoded number is 36 bits)<BR> + else<BR> + <8-48>:"UTF-8" coded frame number (decoded number is 31 bits) + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <?> + </TD> + <TD> + if(blocksize bits == 11x)<BR> + 8/16 bit (blocksize-1) + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <?> + </TD> + <TD> + if(sample rate bits == 11xx)<BR> + 8/16 bit sample rate + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <8> + </TD> + <TD> + CRC-8 (polynomial = x^8 + x^2 + x + 1) of everything before the crc, including the sync code + </TD> + </TR> + <TR> + <TD> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1">NOTES</FONT><BR> + <UL> + <LI> + The blocksize bits 000-101 may only be used if the blocksize is fixed throughout the entire stream. Blocksize bits 110-111 may be used in any case but the decoder will have to pessimistically guess that it is a variable-blocksize stream. There is only one special case: the encoder may use blocksize bits 110-111 on the last frame of a fixed-blocksize stream, as long as the blocksize is not greater than the stream blocksize. + </LI> + <LI> + The "UTF-8" coding used for the sample/frame number is the same variable length code used to store compressed UCS-2, extended to handle larger input. + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe"><FONT SIZE="+1"><B>SUBFRAME</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#subframe_header"><I>SUBFRAME_HEADER</I></A> + </TD> + <TD> + + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#subframe_constant"><I>SUBFRAME_CONSTANT</I></A><BR>|| <A HREF="#subframe_fixed"><I>SUBFRAME_FIXED</I></A><BR>|| <A HREF="#subframe_lpc"><I>SUBFRAME_LPC</I></A><BR>|| <A HREF="#subframe_verbatim"><I>SUBFRAME_VERBATIM</I></A> + </TD> + <TD VALIGN="TOP"> + The SUBFRAME_HEADER specifies which one. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe_header"><FONT SIZE="+1"><B>SUBFRAME_HEADER</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <8> + </TD> + <TD> + Subframe type: + <UL> + <LI> + <TT>xxxxxxx1</TT> : invalid, to prevent sync-fooling string of 1s + </LI> + <LI> + <TT>00000000</TT> : <A HREF="#subframe_constant">SUBFRAME_CONSTANT</A> + </LI> + <LI> + <TT>00000010</TT> : <A HREF="#subframe_verbatim">SUBFRAME_VERBATIM</A> + </LI> + <LI> + <TT>000001x0</TT> : reserved + </LI> + <LI> + <TT>00001xx0</TT> : reserved + </LI> + <LI> + <TT>0001xxx0</TT> : if(xxx <= 4) <A HREF="#subframe_fixed">SUBFRAME_FIXED</A>, xxx=order ; else reserved + </LI> + <LI> + <TT>001xxxx0</TT> : reserved + </LI> + <LI> + <TT>01xxxxx0</TT> : <A HREF="#subframe_lpc">SUBFRAME_LPC</A>, xxxxx=order-1 + </LI> + <LI> + <TT>1xxxxxxx</TT> : invalid, to prevent sync-fooling string of 1s + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe_constant"><FONT SIZE="+1"><B>SUBFRAME_CONSTANT</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <n> + </TD> + <TD> + Unencoded constant value of the subblock, n = frame's bits-per-sample. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe_fixed"><FONT SIZE="+1"><B>SUBFRAME_FIXED</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <n> + </TD> + <TD> + Unencoded warm-up samples (n = frame's bits-per-sample * predictor order). + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#residual"><I>RESIDUAL</I></A> + </TD> + <TD> + Encoded residual + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe_lpc"><FONT SIZE="+1"><B>SUBFRAME_LPC</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <n> + </TD> + <TD> + Unencoded warm-up samples (n = frame's bits-per-sample * lpc order). + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <4> + </TD> + <TD> + (quantized linear predictor coefficients' precision in bits)-1 (1111 = invalid). + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <5> + </TD> + <TD> + Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed). + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <n> + </TD> + <TD> + Unencoded predictor coefficients (n = qlp coeff precision * lpc order). + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#residual"><I>RESIDUAL</I></A> + </TD> + <TD> + Encoded residual + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="subframe_verbatim"><FONT SIZE="+1"><B>SUBFRAME_VERBATIM</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <n*i> + </TD> + <TD> + Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="residual"><FONT SIZE="+1"><B>RESIDUAL</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <2> + </TD> + <TD> + Residual coding method:<BR> + <UL> + <LI> + <TT>00</TT> : partitioned rice coding + </LI> + <LI> + <TT>01-11</TT> : reserved + </LI> + </UL> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#partitioned_rice"><I>RESIDUAL_CODING_METHOD_PARTITIONED_RICE</I></A> + </TD> + <TD> + + </TD> + </TR> + <TR> + <TD> + </TD> + <TD BGCOLOR="#F4F4CC"> + <FONT SIZE="+1">NOTES</FONT><BR> + <UL> + <LI> + Currently, FLAC specifies only one entropy coding method. + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="partitioned_rice"><FONT SIZE="+1"><B>RESIDUAL_CODING_METHOD_PARTITIONED_RICE</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <4> + </TD> + <TD> + Partition order. + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <A HREF="#rice_partition"><I>RICE_PARTITION</I></A>+ + </TD> + <TD> + There will be 2^order partitions. + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + + <P> + <TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#EEEED4"><TR><TD> + <TABLE WIDTH="100%" BORDER="1" BGCOLOR="#EEEED4"> + <TR> + <TD COLSPAN="2" BGCOLOR="#D3D4C5"> + <A NAME="rice_partition"><FONT SIZE="+1"><B>RICE_PARTITION</B></FONT></A> + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <4> + </TD> + <TD> + Rice parameter + </TD> + </TR> + <TR> + <TD ALIGN="RIGHT" VALIGN="TOP" BGCOLOR="#F4F4CC"> + <?> + </TD> + <TD> + Encoded residual. The number of samples (n) in the partition is determined as follows:<BR> + <UL> + <LI> + if the partition order is zero, n = frame's blocksize + </LI> + <LI> + else if this is not the first partition of the subframe, n = (frame's blocksize / (2^partition order)) + </LI> + <LI> + else n = (frame's blocksize / (2^partition order)) - predictor order + </LI> + </UL> + </TD> + </TR> + </TABLE> + </TD></TR></TABLE> + </P> + +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/goals.html b/doc/goals.html new file mode 100644 index 00000000..3aa165b6 --- /dev/null +++ b/doc/goals.html @@ -0,0 +1,112 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - goals</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> goals </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">goals</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + Since FLAC is an open-source project, it's important to have a set of goals that everyone works to. They may change slightly from time to time but they're a good guideline. Changes should be in line with the goals and should not attempt to embrace any of the anti-goals! + </P> + <P> + <B>Goals</B> + </P> + <P> + <UL> + <LI> + FLAC should be and stay an open format. The source code is all either LGPL'd or GPL'd. + </LI> + <LI> + FLAC should be lossless. This seems obvious but lossy compression seems to creep into every audio coder. This goal also means that flac should stay archival quality and be truly lossless for all input. Testing of releases should be thorough. + </LI> + <LI> + FLAC should yield respectable compression, on par or better than other lossless coders. + </LI> + <LI> + FLAC should allow at least realtime decoding on even modest hardware. + </LI> + <LI> + FLAC should support fast sample-accurate seeking. + </LI> + <LI> + FLAC should allow gapless playback of consecutive streams. This follows from the lossless goal. + </LI> + <LI> + The FLAC project owes a lot to the many people who have advanced the audio compression field so freely, and aims also to contribute through the open-source development of new ideas. + </LI> + </UL> + </P> + <P> + <B>Anti-goals</B> + </P> + <P> + <UL> + <LI> + Lossy compression. There are already many suitable lossy format (<A HREF="http://www.xiph.org/ogg/vorbis/index.html">Ogg Vorbis</A>, <A HREF="http://www.mp3-tech.org/">MP3</A>, etc.). + </LI> + <LI> + Copy protection of any kind. Don't get me started, just see the <A HREF="features.html">features page</A> for the short answer. + </LI> + </UL> + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/images/1x1.gif b/doc/images/1x1.gif Binary files differnew file mode 100644 index 00000000..f14ea135 --- /dev/null +++ b/doc/images/1x1.gif diff --git a/doc/images/logo.jpg b/doc/images/logo.jpg Binary files differnew file mode 100644 index 00000000..9a995bd1 --- /dev/null +++ b/doc/images/logo.jpg diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 00000000..4a1043f8 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,232 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - Free Lossless Audio Coder</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> home </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="news.html">news</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + +<TABLE cellspacing="0" cellpadding="3" border="0" width="100%" bgcolor="#99CC99"> + <TR> + <TD align="center" valign="top"> + +<TABLE WIDTH="100%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">status</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P>FLAC is currently in the alpha stage. The current version is 0.2. The format is well defined but may change enough before becoming beta to break older streams. It also has not gone through enough testing yet to be considered archival quality. You should keep those two things in mind when using any alpha or beta versions of FLAC.</P> + <P>That said, we intend to settle on the format quickly, then start releasing beta versions. If you use FLAC and have suggestions or bugs, please <A HREF="http://sourceforge.net/mail/?group_id=13478">join the mailing list</A> or <A HREF="http://sourceforge.net/project/memberlist.php?group_id=13478">developers group</A> and help us move to an official 1.0 version.</P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +<TABLE WIDTH="100%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">what is FLAC?</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + FLAC stands for Free Lossless Audio Coder. The FLAC project consists of: + </P> + <P> + <UL> + <LI>the stream format</LI> + <LI>libFLAC, which implements a reference encoder, stream decoder, and file decoder</LI> + <LI>flac, which is a command-line wrapper around libFLAC to encode and decode .flac files</LI> + <LI>input plugins for various music players (Winamp, XMMS, and more in the works)</LI> + </UL> + </P> + <P> + "Free" means that the specification of the stream format is in the public domain (the FLAC project reserves the right to set the FLAC specification and certify compliance), and that neither the FLAC format nor any of the implemented encoding/decoding methods are covered by any patent. It also means that the source for libFLAC is available under the <A HREF="http://www.opensource.org/licenses/lgpl-license.html">LGPL</A> and the sources for flac and the plugins are available under the <A HREF="http://www.opensource.org/licenses/gpl-license.html">GPL</A>. + </P> + <P> + See the <A HREF="features.html">features page</A>, <A HREF="documentation.html">documentation page</A>, or <A HREF="format.html">FLAC format page</A> for more info, the <A HREF="comparison.html">comparison page</A> to see how the reference encoder measures up, or the <A HREF="goals.html">goals page</A> for what the FLAC project hopes to achieve. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + + +<TABLE WIDTH="100%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">download</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + Visit the <A HREF="download.html">download page</A> for links to the source code or pre-built binaries, or go directly to the <A HREF="http://www.sourceforge.net/projects/flac/">source</A> on SourceForge. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + + +<TABLE WIDTH="100%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">documentation</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + The documentation is available online as well as in the distributions. The general installation and usage documentation for flac and the plugins is <A HREF="documentation.html">here</A>. For a detailed description of the FLAC format and reference encoder see the <A HREF="format.html">FLAC format page</A>. + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + + +<TABLE WIDTH="100%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">message from the maintainer</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + I came up with FLAC because no audio compression format I could find did everything I needed. Since I couldn't mash them all together (most are closed-source), I solidified all my requirements (now the FLAC <A HREF="goals.html">goals</A>) and wrote the first implementation. I intended to open-source it from the beginning for two reasons: 1) so that people who knew more about audio compression than me could help improve it; and 2) I wanted to give something back to the OS community, whose huge body of work I rely on so much. + </P> + <P> + So I started the FLAC project on SourceForge as soon as I had a relatively complete first implementation. Now I'm the maintainer of the FLAC project. You can get in touch with me about it through the <A HREF="http://sourceforge.net/mail/?group_id=13478">mailing list</A> or <A HREF="mailto:jcoalson@users.sourceforge.net">directly</A> + </P> + <P> + --Josh Coalson + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + + +</TD> + + +<TD width="26%" valign="top" align="center"> + + +<TABLE WIDTH="95%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD ALIGN="center"><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B>news</B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD BGCOLOR="#EEEED4"><SMALL><FONT FACE="Lucida,Verdana,Helvetica,Arial"><A HREF="news.html#20001101">10-Dec-2000</A> :<BR> FLAC <A HREF="http://www.sourceforge.net/projects/flac/">debuts</A> on SourceForge<BR></FONT></SMALL></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE><BR><P> + + +<TABLE WIDTH="95%"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD ALIGN="center"><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B>links</B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD BGCOLOR="#EEEED4"><SMALL><FONT FACE="Lucida,Verdana,Helvetica,Arial"><A HREF="http://www.sourceforge.net/projects/flac/">SourceForge</A><BR></FONT></SMALL></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE><BR><P> + + +<A href="http://sourceforge.net"><IMG src="http://sourceforge.net/sflogo.php?group_id=13478&type=1" width="88" height="31" border="0" alt="SourceForge Logo"></A><BR> + + +<BR></FONT> +</TD></TR></TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/doc/news.html b/doc/news.html new file mode 100644 index 00000000..d2c0ba37 --- /dev/null +++ b/doc/news.html @@ -0,0 +1,76 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <TITLE>FLAC - news</TITLE> +</HEAD> + +<BODY MARGINWIDTH="0" MARGINHEIGHT="0" LEFTMARGIN="0" RIGHTMARGIN="0" TOPMARGIN="0" BGCOLOR="#99CC99" TEXT="#000000" LINK="#336699" VLINK="#336699" ALINK="#336699"> + +<TABLE BORDER=0 WIDTH="100%" CELLPADDING=1 CELLSPACING=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#000000"><A HREF="http://flac.sourceforge.net/"><IMG SRC="images/logo.jpg" ALIGN=CENTER ALT="FLAC Logo" BORDER=0 HSPACE=0></a></TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="25" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<TABLE WIDTH="100%" CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD ALIGN="CENTER" BGCOLOR="#D3D4C5"> + <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0> + <TR> + <TD HEIGHT=22 BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="index.html">home</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> news </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="download.html">download</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="features.html">features</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="goals.html">goals</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="format.html">format</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="comparison.html">comparison</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="documentation.html">documentation</A> </TD><TD BGCOLOR="#D3D4C5" ALIGN=CENTER>|</TD> + <TD BGCOLOR="#D3D4C5" ALIGN=CENTER NOWRAP> <A CLASS="topnav" HREF="developers.html">developers</A> </TD> + </TR> + </TABLE> + </TD> + </TR> +</TABLE> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="2" ALT=""></TD></TR></TABLE> + +<CENTER> + +<TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#99CC99"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="15" ALT=""></TD></TR></TABLE> + + +<TABLE WIDTH="100%" CELLPADDING="5" CELLSPACING="5" BORDER="0"> +<TR><TD> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#D3D4C5"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <B><FONT SIZE="+2">news</FONT></B> + </FONT></TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> + <TABLE CELLSPACING="0" CELLPADDING="3" WIDTH="100%" BORDER="0" BGCOLOR="#EEEED4"> + <TR><TD><FONT FACE="Lucida,Verdana,Helvetica,Arial"> + <P> + <A NAME="20001101">10-Dec-2000:</A> + </P> + <P> + <UL> + <LI><B>FLAC debuts on SourceForge.</B> The FLAC project is now being hosted on SourceForge. Visit the <A HREF="http://www.sourceforge.net/projects/projects/flac/">FLAC project page</A> to join the mailing list or sign up as a developer.</LI> + </UL> + </P> + </FONT> + </TD></TR> + </TABLE> + <TABLE WIDTH="100%" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR BGCOLOR="#000000"><TD><IMG SRC="images/1x1.gif" WIDTH="1" HEIGHT="1" ALT=""></TD></TR></TABLE> +</TD></TR> +</TABLE> + + +</CENTER> + +</BODY> +</HTML> diff --git a/include/FLAC/all.h b/include/FLAC/all.h new file mode 100644 index 00000000..9464dcc0 --- /dev/null +++ b/include/FLAC/all.h @@ -0,0 +1,28 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__ALL_H +#define FLAC__ALL_H + +#include "encoder.h" +#include "file_decoder.h" +#include "ordinals.h" +#include "stream_decoder.h" + +#endif diff --git a/include/FLAC/encoder.h b/include/FLAC/encoder.h new file mode 100644 index 00000000..e1171b4c --- /dev/null +++ b/include/FLAC/encoder.h @@ -0,0 +1,77 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__ENCODER_H +#define FLAC__ENCODER_H + +#include "format.h" + +typedef enum { + FLAC__ENCODER_WRITE_OK = 0, + FLAC__ENCODER_WRITE_FATAL_ERROR = 1 +} FLAC__EncoderWriteStatus; + +typedef enum { + FLAC__ENCODER_OK, + FLAC__ENCODER_UNINITIALIZED, + FLAC__ENCODER_INVALID_NUMBER_OF_CHANNELS, + FLAC__ENCODER_INVALID_BITS_PER_SAMPLE, + FLAC__ENCODER_INVALID_SAMPLE_RATE, + FLAC__ENCODER_INVALID_BLOCK_SIZE, + FLAC__ENCODER_INVALID_QLP_COEFF_PRECISION, + FLAC__ENCODER_MID_SIDE_CHANNELS_MISMATCH, + FLAC__ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH, + FLAC__ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER, + FLAC__ENCODER_NOT_STREAMABLE, + FLAC__ENCODER_FRAMING_ERROR, + FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING, + FLAC__ENCODER_FATAL_ERROR_WHILE_WRITING, /* that is, the write_callback returned an error */ + FLAC__ENCODER_MEMORY_ALLOCATION_ERROR +} FLAC__EncoderState; + +struct FLAC__EncoderPrivate; +typedef struct { + /* + * none of these fields may change once FLAC__encoder_init() is called + */ + struct FLAC__EncoderPrivate *guts; /* must be 0 when passed to FLAC__encoder_init() */ + FLAC__EncoderState state; /* must be FLAC__ENCODER_UNINITIALIZED when passed to FLAC__encoder_init() */ + bool streamable_subset; + bool do_mid_side_stereo; /* 0 or 1; 1 only if channels==2 */ + unsigned channels; /* must be <= FLAC__MAX_CHANNELS */ + unsigned bits_per_sample; /* do not give the encoder wider data than what you specify here or bad things will happen! */ + unsigned sample_rate; + unsigned blocksize; + unsigned max_lpc_order; /* 0 => encoder will not try general LPC, only fixed predictors; must be <= FLAC__MAX_LPC_ORDER */ + unsigned qlp_coeff_precision; /* >= FLAC__MIN_QLP_COEFF_PRECISION, or 0 to let encoder select based on blocksize; */ + /* qlp_coeff_precision+bits_per_sample must be < 32 */ + bool do_qlp_coeff_prec_search; /* 0 => use qlp_coeff_precision, 1 => search around qlp_coeff_precision, take best */ + bool do_exhaustive_model_search; /* 0 => use estimated bits per residual for scoring, 1 => generate all, take shortest */ + unsigned rice_optimization_level; /* 0 => estimate Rice parameter based on residual variance, 1-8 => partition residual, use parameter for each */ +} FLAC__Encoder; + + +FLAC__Encoder *FLAC__encoder_get_new_instance(); +void FLAC__encoder_free_instance(FLAC__Encoder *encoder); +FLAC__EncoderState FLAC__encoder_init(FLAC__Encoder *encoder, FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data), void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data), void *client_data); +void FLAC__encoder_finish(FLAC__Encoder *encoder); +bool FLAC__encoder_process(FLAC__Encoder *encoder, const int32 *buf[], unsigned samples); +bool FLAC__encoder_process_interleaved(FLAC__Encoder *encoder, const int32 buf[], unsigned samples); + +#endif diff --git a/include/FLAC/file_decoder.h b/include/FLAC/file_decoder.h new file mode 100644 index 00000000..54aa1ece --- /dev/null +++ b/include/FLAC/file_decoder.h @@ -0,0 +1,59 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__FILE_DECODER_H +#define FLAC__FILE_DECODER_H + +#include "stream_decoder.h" + +typedef enum { + FLAC__FILE_DECODER_OK, + FLAC__FILE_DECODER_SEEKING, + FLAC__FILE_DECODER_END_OF_FILE, + FLAC__FILE_DECODER_ERROR_OPENING_FILE, + FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR, + FLAC__FILE_DECODER_SEEK_ERROR, + FLAC__FILE_DECODER_STREAM_ERROR, + FLAC__FILE_DECODER_UNINITIALIZED +} FLAC__FileDecoderState; + +struct FLAC__FileDecoderPrivate; +typedef struct { + FLAC__FileDecoderState state; /* must be FLAC__FILE_DECODER_UNINITIALIZED when passed to FLAC__file_decoder_init() */ + struct FLAC__FileDecoderPrivate *guts; /* must be 0 when passed to FLAC__file_decoder_init() */ +} FLAC__FileDecoder; + +FLAC__FileDecoder *FLAC__file_decoder_get_new_instance(); +void FLAC__file_decoder_free_instance(FLAC__FileDecoder *decoder); +FLAC__FileDecoderState FLAC__file_decoder_init( + FLAC__FileDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data), + void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data), + void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data), + void *client_data +); +void FLAC__file_decoder_finish(FLAC__FileDecoder *decoder); +bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder); +bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder); +bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder); +bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder); +bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, uint64 sample); + +#endif diff --git a/include/FLAC/format.h b/include/FLAC/format.h new file mode 100644 index 00000000..2de59a5d --- /dev/null +++ b/include/FLAC/format.h @@ -0,0 +1,315 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__FORMAT_H +#define FLAC__FORMAT_H + +#include "ordinals.h" + +/* changing the following values to be higher will break the framing and hence the stream format, so DON'T! */ +#define FLAC__MIN_BLOCK_SIZE (16u) +#define FLAC__MAX_BLOCK_SIZE (65535u) +#define FLAC__MAX_CHANNELS (8u) +/*NOTE: only up to 24 because of the current predictor coefficient quantization and the fact we use int32s for all work */ +#define FLAC__MAX_BITS_PER_SAMPLE (24u) +/* the following is ((2 ** 20) - 1) div 10 */ +#define FLAC__MAX_SAMPLE_RATE (1048570u) +#define FLAC__MAX_LPC_ORDER (32u) +#define FLAC__MIN_QLP_COEFF_PRECISION (5u) +/* changing this also means changing all of fixed.c and more, so DON'T! */ +#define FLAC__MAX_FIXED_ORDER (4u) +#define FLAC__MAX_RICE_PARTITION_ORDER (15u) + +#define FLAC__VERSION_STRING "0.2" +extern const unsigned FLAC__MAJOR_VERSION; +extern const unsigned FLAC__MINOR_VERSION; + +extern const byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */; +extern const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */; +extern const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */; + + +/***************************************************************************** + * + * NOTE: Within the bitstream, all fixed-width numbers are big-endian coded. + * All numbers are unsigned unless otherwise noted. + * + *****************************************************************************/ + +typedef enum { + FLAC__METADATA_TYPE_ENCODING = 0 +} FLAC__MetaDataType; + +/***************************************************************************** + * + * 16: minimum blocksize (in samples) of all blocks in the stream + * 16: maximum blocksize (in samples) of all blocks in the stream + * 24: minimum framesize (in bytes) of all frames in the stream; 0 => unknown + * 24: maximum framesize (in bytes) of all frames in the stream; 0 => unknown + * 20: sample rate in Hz, 0 is invalid + * 3: (number of channels)-1 + * 5: (bits per sample)-1 + * 36: total samples, 0 => unknown + *---- ----------------- + * 18 bytes total + */ +typedef struct { + unsigned min_blocksize, max_blocksize; + unsigned min_framesize, max_framesize; + unsigned sample_rate; + unsigned channels; + unsigned bits_per_sample; + uint64 total_samples; +} FLAC__StreamMetaData_Encoding; + +extern const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN; /* = 16 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN; /* = 16 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN; /* = 24 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN; /* = 24 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN; /* = 20 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN; /* = 3 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN; /* = 5 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN; /* = 36 bits */ +extern const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH; /* = 18 bytes */ + +/***************************************************************************** + * + * 1: =1 if this is the last meta-data block, else =0 + * 7: meta-data type (c.f. FLAC__MetaDataType) + * 24: length (in bytes) of the block-specific data to follow + *---- ----------------- + * 4 bytes total + */ +typedef struct { + FLAC__MetaDataType type; + bool is_last; + unsigned length; /* in bytes */ + union { + FLAC__StreamMetaData_Encoding encoding; + } data; +} FLAC__StreamMetaData; + +extern const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /* = 1 bits */ +extern const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /* = 7 bits */ +extern const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /* = 24 bits */ + +/*****************************************************************************/ + +typedef enum { + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0 +} FLAC__EntropyCodingMethodType; + +/***************************************************************************** + * + * 4: partition order => (2 ** order) subdivisions + */ +typedef struct { + unsigned order; + unsigned parameters[1 << FLAC__MAX_RICE_PARTITION_ORDER]; +} FLAC__EntropyCodingMethod_PartitionedRice; + +extern const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /* = 4 bits */ +extern const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /* = 4 bits */ + +/***************************************************************************** + * + * 2: entropy coding method: + * 00: partitioned rice coding + * 01-11: reserved + * ?: entropy coding method data + */ +typedef struct { + FLAC__EntropyCodingMethodType type; + union { + FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; + } data; +} FLAC__EntropyCodingMethod; + +extern const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /* = 2 bits */ + +/*****************************************************************************/ + +typedef enum { + FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, + FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, + FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, + FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 +} FLAC__ChannelAssignment; + +/***************************************************************************** + * + * 9: sync code '111111110' + * 3: blocksize in samples + * 000: get from stream header => implies constant blocksize throughout stream + * 001: 192 samples (AES/EBU) => implies constant blocksize throughout stream + * 010-101: 576 * (2^(2-n)) samples, i.e. 576/1152/2304/4608 => implies constant blocksize throughout stream + * 110: get 8 bit (blocksize-1) from end of header => variable blocksize throughout stream unless it's the last frame + * 111: get 16 bit (blocksize-1) from end of header => variable blocksize throughout stream unless it's the last frame + * 4: sample rate: + * 0000: get from stream header + * 0001-0011: reserved + * 0100: 8kHz + * 0101: 16kHz + * 0110: 22.05kHz + * 0111: 24kHz + * 1000: 32kHz + * 1001: 44.1kHz + * 1010: 48kHz + * 1011: 96kHz + * 1100: get 8 bit sample rate (in kHz) from end of header + * 1101: get 16 bit sample rate (in Hz) from end of header + * 1110: get 16 bit sample rate (in tens of Hz) from end of header + * 1111: invalid, to prevent sync-fooling string of 1s (use to check for erroneous sync) + * 4: channel assignment + * 0000-0111: (number of independent channels)-1. when == 0001, channel 0 is the left channel and channel 1 is the right + * 1000: left/side stereo : channel 0 is the left channel, channel 1 is the side(difference) channel + * 1001: right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel + * 1010: mid/side stereo : channel 0 is the mid(average) channel, channel 1 is the side(difference) channel + * 1011-1111: reserved + * 3: sample size in bits + * 000: get from stream header + * 001: 8 bits per sample + * 010: 12 bits per sample + * 011: reserved + * 100: 16 bits per sample + * 101: 20 bits per sample + * 110: 24 bits per sample + * 111: reserved + * 1: zero pad, to prevent sync-fooling string of 1s (use to check for erroneous sync) + * ?: if(variable blocksize) + * 8-56: 'UTF-8' coded sample number (decoded number is 0-36 bits) (use to check for erroneous sync) + * else + * 8-48: 'UTF-8' coded frame number (decoded number is 0-31 bits) (use to check for erroneous sync) + * ?: if(blocksize bits == 11x) + * 8/16 bit (blocksize-1) + * ?: if(sample rate bits == 11xx) + * 8/16 bit sample rate + * 8: CRC-8 (polynomial = x^8 + x^2 + x + 1) of everything before the crc, including the sync code + */ +typedef struct { + unsigned blocksize; /* in samples */ + unsigned sample_rate; /* in Hz */ + unsigned channels; + FLAC__ChannelAssignment channel_assignment; + unsigned bits_per_sample; + union { + uint32 frame_number; + uint64 sample_number; + } number; +} FLAC__FrameHeader; + +extern const unsigned FLAC__FRAME_HEADER_SYNC; /* = 0x1fe */ +extern const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /* = 9 bits */ +extern const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /* = 3 bits */ +extern const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /* = 4 bits */ +extern const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /* = 4 bits */ +extern const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /* = 3 bits */ +extern const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /* = 1 bit */ +extern const unsigned FLAC__FRAME_HEADER_CRC8_LEN; /* = 8 bits */ + +/*****************************************************************************/ + +typedef enum { + FLAC__SUBFRAME_TYPE_CONSTANT = 0, + FLAC__SUBFRAME_TYPE_VERBATIM = 1, + FLAC__SUBFRAME_TYPE_FIXED = 2, + FLAC__SUBFRAME_TYPE_LPC = 3 +} FLAC__SubframeType; + +/***************************************************************************** + * + * n: constant value for signal; n = frame's bits-per-sample + */ +typedef struct { + int32 value; +} FLAC__SubframeHeader_Constant; + +/***************************************************************************** + * + * n*i: unencoded signal; n = frame's bits-per-sample, i = frame's blocksize + */ +/* There is no (trivial) for structure FLAC__SubframeHeader_Verbatim */ + +/***************************************************************************** + * + * n: unencoded warm-up samples (n = fixed-predictor order * bits per sample) + * ?: entropy coding method info + * ?: encoded residual ((blocksize minus fixed-predictor order) samples) + * The order is stored in the main subframe header + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + unsigned order; + int32 warmup[FLAC__MAX_FIXED_ORDER]; +} FLAC__SubframeHeader_Fixed; + +/***************************************************************************** + * + * n: unencoded warm-up samples (n = lpc order * bits per sample) + * 4: (qlp coeff precision in bits)-1 (1111 = invalid, use to check for erroneous sync) + * 5: qlp shift needed in bits (signed) + * n: unencoded predictor coefficients (n = lpc order * qlp coeff precision) + * ?: entropy coding method info + * ?: encoded residual ((blocksize minus lpc order) samples) + * The order is stored in the main subframe header + */ +typedef struct { + FLAC__EntropyCodingMethod entropy_coding_method; + unsigned order; + unsigned qlp_coeff_precision; + int quantization_level; + int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; + int32 warmup[FLAC__MAX_LPC_ORDER]; +} FLAC__SubframeHeader_LPC; + +extern const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN; /* = 4 bits */ +extern const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN; /* = 5 bits */ + +/***************************************************************************** + * + * 8: subframe type + * xxxxxxx1: invalid, to prevent sync-fooling string of 1s (use to check for erroneous sync) + * 00000000: constant value + * 00000010: verbatim + * 000001x0: reserved + * 00001xx0: reserved + * 0001xxx0: fixed predictor, xxx=order <= 4, else reserved + * 001xxxx0: reserved + * 01xxxxx0: lpc, xxxxx=order-1 + * 1xxxxxxx: invalid, to prevent sync-fooling string of 1s (use to check for erroneous sync) + * ?: subframe-specific header (c.f. FLAC__SubframeHeader_*) + */ +typedef struct { + FLAC__SubframeType type; + union { + FLAC__SubframeHeader_Constant constant; + FLAC__SubframeHeader_Fixed fixed; + FLAC__SubframeHeader_LPC lpc; + } data; /* data will be undefined for FLAC__SUBFRAME_TYPE_VERBATIM */ +} FLAC__SubframeHeader; + +extern const unsigned FLAC__SUBFRAME_HEADER_TYPE_CONSTANT; /* = 0x00 */ +extern const unsigned FLAC__SUBFRAME_HEADER_TYPE_VERBATIM; /* = 0x02 */ +extern const unsigned FLAC__SUBFRAME_HEADER_TYPE_FIXED; /* = 0x10 */ +extern const unsigned FLAC__SUBFRAME_HEADER_TYPE_LPC; /* = 0x40 */ +extern const unsigned FLAC__SUBFRAME_HEADER_TYPE_LEN; /* = 8 bits */ + +/*****************************************************************************/ + +#endif diff --git a/include/FLAC/ordinals.h b/include/FLAC/ordinals.h new file mode 100644 index 00000000..d9f024a6 --- /dev/null +++ b/include/FLAC/ordinals.h @@ -0,0 +1,75 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__ORDINALS_H +#define FLAC__ORDINALS_H + +#ifdef bool +#undef bool +#endif +#ifdef true +#undef true +#endif +#ifdef false +#undef false +#endif +#ifdef byte +#undef byte +#endif +#ifdef int16 +#undef int16 +#endif +#ifdef uint16 +#undef uint16 +#endif +#ifdef int32 +#undef int32 +#endif +#ifdef uint32 +#undef uint32 +#endif +#ifdef int64 +#undef int64 +#endif +#ifdef uint64 +#undef uint64 +#endif +#ifdef real +#undef real +#endif + +#define true 1 +#define false 0 + +typedef int bool; +typedef unsigned char byte; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +#if defined _WIN32 && !defined __CYGWIN__ +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int int64; +typedef unsigned long long uint64; +#endif +typedef double real; + +#endif diff --git a/include/FLAC/stream_decoder.h b/include/FLAC/stream_decoder.h new file mode 100644 index 00000000..8ac06095 --- /dev/null +++ b/include/FLAC/stream_decoder.h @@ -0,0 +1,83 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__STREAM_DECODER_H +#define FLAC__STREAM_DECODER_H + +#include "format.h" + +typedef enum { + 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_RESYNC_IN_HEADER, + FLAC__STREAM_DECODER_END_OF_STREAM, + FLAC__STREAM_DECODER_ABORTED, + FLAC__STREAM_DECODER_UNPARSEABLE_STREAM, + FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, + FLAC__STREAM_DECODER_UNINITIALIZED +} FLAC__StreamDecoderState; + +typedef enum { + FLAC__STREAM_DECODER_READ_CONTINUE, + FLAC__STREAM_DECODER_READ_END_OF_STREAM, + FLAC__STREAM_DECODER_READ_ABORT +} FLAC__StreamDecoderReadStatus; + +typedef enum { + FLAC__STREAM_DECODER_WRITE_CONTINUE, + FLAC__STREAM_DECODER_WRITE_ABORT +} FLAC__StreamDecoderWriteStatus; + +typedef enum { + FLAC__STREAM_DECODER_ERROR_LOST_SYNC +} FLAC__StreamDecoderErrorStatus; + +struct FLAC__StreamDecoderPrivate; +typedef struct { + /* these fields are read-only and valid as of the last write_callback() */ + unsigned channels; + FLAC__ChannelAssignment channel_assignment; + unsigned bits_per_sample; + unsigned sample_rate; /* in Hz */ + unsigned blocksize; /* in samples (per channel) */ + FLAC__StreamDecoderState state; /* must be FLAC__STREAM_DECODER_UNINITIALIZED when passed to FLAC__stream_decoder_init() */ + struct FLAC__StreamDecoderPrivate *guts; /* must be 0 when passed to FLAC__stream_decoder_init() */ +} FLAC__StreamDecoder; + +FLAC__StreamDecoder *FLAC__stream_decoder_get_new_instance(); +void FLAC__stream_decoder_free_instance(FLAC__StreamDecoder *decoder); +FLAC__StreamDecoderState FLAC__stream_decoder_init( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data), + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data), + void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data), + void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data), + void *client_data +); +void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_process_whole_stream(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_process_metadata(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_process_one_frame(FLAC__StreamDecoder *decoder); +bool FLAC__stream_decoder_process_remaining_frames(FLAC__StreamDecoder *decoder); + +#endif diff --git a/src/flac/Makefile b/src/flac/Makefile new file mode 100644 index 00000000..ea58b13d --- /dev/null +++ b/src/flac/Makefile @@ -0,0 +1,16 @@ +# +# GNU makefile +# + +PROGRAM_NAME = flac +INCLUDES = -I./include -I../../include +LIBS = -lFLAC -lm + +OBJS = \ + decode.o \ + encode.o \ + main.o + +include ../../build/exe.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/flac/Makefile.vc b/src/flac/Makefile.vc new file mode 100644 index 00000000..e0d7cdf1 --- /dev/null +++ b/src/flac/Makefile.vc @@ -0,0 +1,25 @@ +!include <win32.mak> + +!IFDEF DEBUG +.c.obj: + $(cc) $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $< +!else +.c.obj: + $(cc) $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /O2 -DNODEBUG $< +!endif + +C_FILES= \ + decode.c \ + encode.c \ + main.c + +OBJS= $(C_FILES:.c=.obj) + +all: flac.exe + +flac.exe: $(OBJS) + link.exe /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.exe $(OBJS) libFLAC.lib + +clean: + -del *.obj *.pch + -del ..\..\obj\bin\flac.exe diff --git a/src/flac/decode.c b/src/flac/decode.c new file mode 100644 index 00000000..b8dfca0b --- /dev/null +++ b/src/flac/decode.c @@ -0,0 +1,377 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#if defined _WIN32 && !defined __CYGWIN__ +/* where MSVC puts unlink() */ +# include <io.h> +#else +# include <unistd.h> +#endif +#include <stdio.h> /* for FILE */ +#include <string.h> /* for strcmp() */ +#include "FLAC/all.h" +#include "decode.h" + +typedef struct { + FILE *fout; + bool abort_flag; + bool is_wave_out; + bool is_big_endian; + bool is_unsigned_samples; + uint64 total_samples; + unsigned bps; + unsigned channels; + unsigned sample_rate; + bool verbose; + uint64 skip; + uint64 samples_processed; + unsigned frame_counter; +} stream_info_struct; + +static FLAC__FileDecoder *decoder; +static bool is_big_endian_host; + +/* local routines */ +static bool init(const char *infile, stream_info_struct *stream_info); +static bool write_little_endian_uint16(FILE *f, uint16 val); +static bool write_little_endian_uint32(FILE *f, uint32 val); +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); +static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); +static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static void print_stats(const stream_info_struct *stream_info); + +int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip) +{ + stream_info_struct stream_info; + + decoder = 0; + stream_info.abort_flag = false; + stream_info.is_wave_out = true; + stream_info.verbose = verbose; + stream_info.skip = skip; + stream_info.samples_processed = 0; + stream_info.frame_counter = 0; + + if(0 == strcmp(outfile, "-")) { + stream_info.fout = stdout; + } + else { + if(0 == (stream_info.fout = fopen(outfile, "wb"))) { + fprintf(stderr, "ERROR: can't open output file %s\n", outfile); + return false; + } + } + + if(!init(infile, &stream_info)) + goto wav_abort_; + + if(skip > 0) { + if(!FLAC__file_decoder_process_metadata(decoder)) { + fprintf(stderr, "ERROR during decoding\n"); + goto wav_abort_; + } + if(!FLAC__file_decoder_seek_absolute(decoder, skip)) { + fprintf(stderr, "ERROR seeking while skipping bytes in input file %s\n", infile); + goto wav_abort_; + } + if(!FLAC__file_decoder_process_remaining_frames(decoder)) { + fprintf(stderr, "ERROR during decodingg\n"); + goto wav_abort_; + } + if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) { + fprintf(stderr, "ERROR during decodinggg\n"); + goto wav_abort_; + } + } + else { + if(!FLAC__file_decoder_process_whole_file(decoder)) { + fprintf(stderr, "ERROR during decoding\n"); + goto wav_abort_; + } + if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) { + fprintf(stderr, "ERROR during decodingg, state=%u\n", decoder->state); + goto wav_abort_; + } + } + + if(decoder) { + if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder); + print_stats(&stream_info); + FLAC__file_decoder_free_instance(decoder); + } + fclose(stream_info.fout); + if(verbose) + printf("\n"); + return 0; +wav_abort_: + if(decoder) { + if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder); + FLAC__file_decoder_free_instance(decoder); + } + fclose(stream_info.fout); + unlink(outfile); + return 1; +} + +int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples) +{ + stream_info_struct stream_info; + + decoder = 0; + stream_info.abort_flag = false; + stream_info.is_wave_out = false; + stream_info.is_big_endian = is_big_endian; + stream_info.is_unsigned_samples = is_unsigned_samples; + stream_info.verbose = verbose; + stream_info.skip = skip; + stream_info.samples_processed = 0; + stream_info.frame_counter = 0; + + if(0 == strcmp(outfile, "-")) { + stream_info.fout = stdout; + } + else { + if(0 == (stream_info.fout = fopen(outfile, "wb"))) { + fprintf(stderr, "ERROR: can't open output file %s\n", outfile); + return false; + } + } + + if(!init(infile, &stream_info)) + goto raw_abort_; + + if(skip > 0) { + if(!FLAC__file_decoder_process_metadata(decoder)) { + fprintf(stderr, "ERROR during decoding\n"); + goto raw_abort_; + } + if(!FLAC__file_decoder_seek_absolute(decoder, skip)) { + fprintf(stderr, "ERROR seeking while skipping bytes in input file %s\n", infile); + goto raw_abort_; + } + if(!FLAC__file_decoder_process_remaining_frames(decoder)) { + fprintf(stderr, "ERROR during decodingg\n"); + goto raw_abort_; + } + if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) { + fprintf(stderr, "ERROR during decodinggg\n"); + goto raw_abort_; + } + } + else { + if(!FLAC__file_decoder_process_whole_file(decoder)) { + fprintf(stderr, "ERROR during decoding\n"); + goto raw_abort_; + } + if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) { + fprintf(stderr, "ERROR during decodingg\n"); + goto raw_abort_; + } + } + + if(decoder) { + if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder); + print_stats(&stream_info); + FLAC__file_decoder_free_instance(decoder); + } + fclose(stream_info.fout); + if(verbose) + printf("\n"); + return 0; +raw_abort_: + if(decoder) { + if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder); + FLAC__file_decoder_free_instance(decoder); + } + fclose(stream_info.fout); + unlink(outfile); + return 1; +} + +bool init(const char *infile, stream_info_struct *stream_info) +{ + uint32 test = 1; + + is_big_endian_host = (*((byte*)(&test)))? false : true; + + decoder = FLAC__file_decoder_get_new_instance(); + if(0 == decoder) { + fprintf(stderr, "ERROR creating the decoder instance\n"); + return false; + } + + if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) { + fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state); + return false; + } + + return true; +} + +bool write_little_endian_uint16(FILE *f, uint16 val) +{ + byte *b = (byte*)(&val); + if(is_big_endian_host) { + byte tmp; + tmp = b[1]; b[1] = b[0]; b[0] = tmp; + } + return fwrite(b, 1, 2, f) == 2; +} + +bool write_little_endian_uint32(FILE *f, uint32 val) +{ + byte *b = (byte*)(&val); + if(is_big_endian_host) { + byte tmp; + tmp = b[3]; b[3] = b[0]; b[0] = tmp; + tmp = b[2]; b[2] = b[1]; b[1] = tmp; + } + return fwrite(b, 1, 4, f) == 4; +} + +FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + FILE *fout = stream_info->fout; + unsigned bps = stream_info->bps, channels = stream_info->channels; + bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian); + bool is_unsigned_samples = (stream_info->is_wave_out? bps==8 : stream_info->is_unsigned_samples); + unsigned wide_samples = header->blocksize, wide_sample, sample, channel, byte; + static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */ + unsigned char *ucbuffer = (unsigned char *)scbuffer; + signed short *ssbuffer = (signed short *)scbuffer; + unsigned short *usbuffer = (unsigned short *)scbuffer; + + (void)decoder; + + if(stream_info->abort_flag) + return FLAC__STREAM_DECODER_WRITE_ABORT; + + stream_info->samples_processed += wide_samples; + stream_info->frame_counter++; + + if(stream_info->verbose && !(stream_info->frame_counter & 0x1f)) + print_stats(stream_info); + + if(bps == 8) { + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ucbuffer[sample] = buffer[channel][wide_sample] + 128; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + scbuffer[sample] = buffer[channel][wide_sample]; + } + if(fwrite(ucbuffer, 1, sample, fout) != sample) + return FLAC__STREAM_DECODER_WRITE_ABORT; + } + else { /* bps == 16 */ + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + usbuffer[sample] = buffer[channel][wide_sample] + 32768; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + ssbuffer[sample] = buffer[channel][wide_sample]; + } + if(is_big_endian != is_big_endian_host) { + unsigned char tmp; + for(byte = 0; byte < sample<<1; byte += 2) { + tmp = ucbuffer[byte]; + ucbuffer[byte] = ucbuffer[byte+1]; + ucbuffer[byte+1] = tmp; + } + } + if(fwrite(usbuffer, 2, sample, fout) != sample) + return FLAC__STREAM_DECODER_WRITE_ABORT; + } + return FLAC__STREAM_DECODER_WRITE_CONTINUE; +} + +void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + (void)decoder; + if(metadata->type == FLAC__METADATA_TYPE_ENCODING) { + stream_info->total_samples = metadata->data.encoding.total_samples - stream_info->skip; + stream_info->bps = metadata->data.encoding.bits_per_sample; + stream_info->channels = metadata->data.encoding.channels; + stream_info->sample_rate = metadata->data.encoding.sample_rate; + + if(stream_info->bps != 8 && stream_info->bps != 16) { + fprintf(stderr, "ERROR: bits per sample is not 8 or 16\n"); + stream_info->abort_flag = true; + return; + } + + /* write the WAVE headers if necessary */ + if(stream_info->is_wave_out) { + uint64 data_size = stream_info->total_samples * stream_info->channels * ((stream_info->bps+7)/8); + if(data_size >= 0xFFFFFFDC) { + fprintf(stderr, "ERROR: stream is too big for a wave file\n"); + stream_info->abort_flag = true; + return; + } + if(fwrite("RIFF", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; + if(!write_little_endian_uint32(stream_info->fout, (uint32)(data_size+36))) stream_info->abort_flag = true; /* filesize-8 */ + if(fwrite("WAVEfmt ", 1, 8, stream_info->fout) != 8) stream_info->abort_flag = true; + if(fwrite("\020\000\000\000", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; /* chunk size = 16 */ + if(fwrite("\001\000", 1, 2, stream_info->fout) != 2) stream_info->abort_flag = true; /* compression code == 1 */ + if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels))) stream_info->abort_flag = true; + if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate)) stream_info->abort_flag = true; + if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate * stream_info->channels * ((stream_info->bps+7) / 8))) stream_info->abort_flag = true; /* @@@ or is it (sample_rate*channels*bps) / 8 ??? */ + if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels * ((stream_info->bps+7) / 8)))) stream_info->abort_flag = true; /* block align */ + if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->bps))) stream_info->abort_flag = true; /* bits per sample */ + if(fwrite("data", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; + if(!write_little_endian_uint32(stream_info->fout, (uint32)data_size)) stream_info->abort_flag = true; /* data size */ + } + } +} + +void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + (void)decoder; + fprintf(stderr, "*** Got error code %d\n", status); + stream_info->abort_flag = true; +} + +void print_stats(const stream_info_struct *stream_info) +{ + if(stream_info->verbose) { + printf("\rwrote %u of %u samples, %6.2f%% complete", + (unsigned)stream_info->samples_processed, + (unsigned)stream_info->total_samples, +#ifdef _MSC_VER + /* with VC++ you have to spoon feed it the casting */ + (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0 +#else + (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0 +#endif + ); + fflush(stdout); + } +} diff --git a/src/flac/decode.h b/src/flac/decode.h new file mode 100644 index 00000000..8c23485f --- /dev/null +++ b/src/flac/decode.h @@ -0,0 +1,25 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef flac__decode_h +#define flac__decode_h + +int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip); +int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples); + +#endif diff --git a/src/flac/encode.c b/src/flac/encode.c new file mode 100644 index 00000000..151dbde7 --- /dev/null +++ b/src/flac/encode.c @@ -0,0 +1,587 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#if defined _WIN32 && !defined __CYGWIN__ +/* where MSVC puts unlink() */ +# include <io.h> +#else +# include <unistd.h> +#endif +#include <stdio.h> /* for FILE */ +#include <string.h> /* for strcmp() */ +#include "FLAC/all.h" +#include "encode.h" + +#define CHUNK_OF_SAMPLES 2048 + +typedef struct { + FILE *fout; + const char *outfile; + FLAC__Encoder *encoder; + bool verbose; + uint64 unencoded_size; + uint64 total_samples_to_encode; + uint64 bytes_written; + uint64 samples_written; + unsigned current_frame; +} encoder_wrapper_struct; + +static bool is_big_endian_host; + +static unsigned char ucbuffer[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*(FLAC__MAX_BITS_PER_SAMPLE>>3)]; +static signed char *scbuffer = (signed char *)ucbuffer; +static uint16 *usbuffer = (uint16 *)ucbuffer; +static int16 *ssbuffer = (int16 *)ucbuffer; + +static int32 in[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES]; +static int32 *input[FLAC__MAX_CHANNELS]; + +/* local routines */ +static bool init(encoder_wrapper_struct *encoder_wrapper); +static bool init_encoder(bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper); +static void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps); +static FLAC__EncoderWriteStatus write_callback(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); +static void metadata_callback(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data); +static void print_stats(const encoder_wrapper_struct *encoder_wrapper); +static bool read_little_endian_uint16(FILE *f, uint16 *val, bool eof_ok); +static bool read_little_endian_uint32(FILE *f, uint32 *val, bool eof_ok); + +int encode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision) +{ + encoder_wrapper_struct encoder_wrapper; + FILE *fin; + bool is_unsigned_samples; + unsigned channels, bps, sample_rate, data_bytes; + size_t bytes_per_wide_sample, bytes_read; + uint16 x; + uint32 xx; + + encoder_wrapper.encoder = 0; + encoder_wrapper.verbose = verbose; + encoder_wrapper.bytes_written = 0; + encoder_wrapper.samples_written = 0; + encoder_wrapper.outfile = outfile; + + if(0 == strcmp(infile, "-")) { + fin = stdin; + } + else { + if(0 == (fin = fopen(infile, "rb"))) { + fprintf(stderr, "ERROR: can't open input file %s\n", infile); + return false; + } + } + if(0 == strcmp(outfile, "-")) { + encoder_wrapper.fout = stdout; + } + else { + if(0 == (encoder_wrapper.fout = fopen(outfile, "wb"))) { + fprintf(stderr, "ERROR: can't open output file %s\n", outfile); + fclose(fin); + return false; + } + } + + if(!init(&encoder_wrapper)) + goto wav_abort_; + + /* + * check the RIFF chunk + */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + if(xx != 0x46464952) { /* "RIFF" */ + fprintf(stderr, "ERROR: no RIFF header\n"); + goto wav_abort_; + } + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + + /* + * now process the WAVE chunk + */ + if(!read_little_endian_uint32(fin, &xx, true)) + goto wav_end_; + if(xx != 0x45564157) { /* "WAVE" */ + fprintf(stderr, "ERROR: no WAVE header\n"); + goto wav_abort_; + } + + /* do the format sub-chunk */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + if(xx != 0x20746d66) { /* "fmt " */ + fprintf(stderr, "ERROR: no format sub-chunk\n"); + goto wav_abort_; + } + /* fmt chunk size */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + if(xx != 16) { + fprintf(stderr, "ERROR: unsupported chunk\n"); + goto wav_abort_; + } + /* compression code */ + if(!read_little_endian_uint16(fin, &x, false)) + goto wav_abort_; + if(x != 1) { + fprintf(stderr, "ERROR: unsupported compression type %u\n", (unsigned)x); + goto wav_abort_; + } + /* number of channels */ + if(!read_little_endian_uint16(fin, &x, false)) + goto wav_abort_; + if(x == 0 || x > FLAC__MAX_CHANNELS) { + fprintf(stderr, "ERROR: unsupported number channels %u\n", (unsigned)x); + goto wav_abort_; + } + channels = x; + /* sample rate */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + if(xx == 0 || xx > FLAC__MAX_SAMPLE_RATE) { + fprintf(stderr, "ERROR: unsupported sample rate %u\n", (unsigned)xx); + goto wav_abort_; + } + sample_rate = xx; + /* avg bytes per second (ignored) */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + /* block align (ignored) */ + if(!read_little_endian_uint16(fin, &x, false)) + goto wav_abort_; + /* bits per sample */ + if(!read_little_endian_uint16(fin, &x, false)) + goto wav_abort_; + if(x != 8 && x != 16) { + fprintf(stderr, "ERROR: unsupported bits per sample %u\n", (unsigned)x); + goto wav_abort_; + } + bps = x; + is_unsigned_samples = (x == 8); + + /* do the data sub-chunk */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + if(xx != 0x61746164) { /* "data" */ + fprintf(stderr, "ERROR: no data sub-chunk\n"); + goto wav_abort_; + } + /* data size */ + if(!read_little_endian_uint32(fin, &xx, false)) + goto wav_abort_; + data_bytes = xx; + + if(!init_encoder(lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, &encoder_wrapper)) + goto wav_abort_; + + bytes_per_wide_sample = channels * (bps >> 3); + + if(-1 == fseek(fin, bytes_per_wide_sample * (unsigned)skip, SEEK_CUR)) { + fprintf(stderr, "ERROR seeking while skipping samples in input file %s\n", infile); + goto wav_abort_; + } + + encoder_wrapper.total_samples_to_encode = data_bytes / bytes_per_wide_sample - skip; + encoder_wrapper.unencoded_size = encoder_wrapper.total_samples_to_encode * bytes_per_wide_sample + 44; /* 44 for the size of the WAV headers */ + + while(data_bytes > 0) { + bytes_read = fread(ucbuffer, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, fin); + if(bytes_read == 0) { + if(ferror(fin)) { + fprintf(stderr, "ERROR reading from %s\n", infile); + goto wav_abort_; + } + else if(feof(fin)) + break; + } + else if(bytes_read % bytes_per_wide_sample != 0) { + fprintf(stderr, "ERROR, got partial sample from input file %s\n", infile); + goto wav_abort_; + } + else { + unsigned wide_samples = bytes_read / bytes_per_wide_sample; + format_input(wide_samples, false, is_unsigned_samples, channels, bps); + if(!FLAC__encoder_process(encoder_wrapper.encoder, input, wide_samples)) { + fprintf(stderr, "ERROR during encoding, state = %d\n", encoder_wrapper.encoder->state); + goto wav_abort_; + } + data_bytes -= bytes_read; + } + } + +wav_end_: + if(encoder_wrapper.encoder) { + if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED) + FLAC__encoder_finish(encoder_wrapper.encoder); + FLAC__encoder_free_instance(encoder_wrapper.encoder); + } + if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) { + print_stats(&encoder_wrapper); + printf("\n"); + } + fclose(fin); + return 0; +wav_abort_: + if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) + printf("\n"); + if(encoder_wrapper.encoder) { + if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED) + FLAC__encoder_finish(encoder_wrapper.encoder); + FLAC__encoder_free_instance(encoder_wrapper.encoder); + } + fclose(fin); + unlink(outfile); + return 1; +} + +int encode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate) +{ + encoder_wrapper_struct encoder_wrapper; + FILE *fin; + size_t bytes_read; + const size_t bytes_per_wide_sample = channels * (bps >> 3); + + encoder_wrapper.encoder = 0; + encoder_wrapper.verbose = verbose; + encoder_wrapper.bytes_written = 0; + encoder_wrapper.samples_written = 0; + encoder_wrapper.outfile = outfile; + + if(0 == strcmp(infile, "-")) { + fin = stdin; + } + else { + if(0 == (fin = fopen(infile, "rb"))) { + fprintf(stderr, "ERROR: can't open input file %s\n", infile); + return false; + } + } + if(0 == strcmp(outfile, "-")) { + encoder_wrapper.fout = stdout; + } + else { + if(0 == (encoder_wrapper.fout = fopen(outfile, "wb"))) { + fprintf(stderr, "ERROR: can't open output file %s\n", outfile); + fclose(fin); + return false; + } + } + + if(!init(&encoder_wrapper)) + goto raw_abort_; + + if(!init_encoder(lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, &encoder_wrapper)) + goto raw_abort_; + + /* get the file length */ + if(0 != fseek(fin, 0, SEEK_END)) { + encoder_wrapper.total_samples_to_encode = encoder_wrapper.unencoded_size = 0; + } + else { + long filesize; + fflush(fin); + if(-1 == (filesize = ftell(fin))) { + encoder_wrapper.total_samples_to_encode = encoder_wrapper.unencoded_size = 0; + } + else { + encoder_wrapper.unencoded_size = filesize - skip * bytes_per_wide_sample; + encoder_wrapper.total_samples_to_encode = filesize / bytes_per_wide_sample - skip; + } + } + + if(-1 == fseek(fin, bytes_per_wide_sample * (unsigned)skip, SEEK_SET)) { + fprintf(stderr, "ERROR seeking while skipping samples in input file %s\n", infile); + goto raw_abort_; + } + + while(!feof(fin)) { + bytes_read = fread(ucbuffer, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, fin); + if(bytes_read == 0) { + if(ferror(fin)) { + fprintf(stderr, "ERROR reading from %s\n", infile); + goto raw_abort_; + } + } + else if(bytes_read % bytes_per_wide_sample != 0) { + fprintf(stderr, "ERROR, got partial sample from input file %s\n", infile); + goto raw_abort_; + } + else { + unsigned wide_samples = bytes_read / bytes_per_wide_sample; + format_input(wide_samples, is_big_endian, is_unsigned_samples, channels, bps); + if(!FLAC__encoder_process(encoder_wrapper.encoder, input, wide_samples)) { + fprintf(stderr, "ERROR during encoding, state = %d\n", encoder_wrapper.encoder->state); + goto raw_abort_; + } + } + } + + if(encoder_wrapper.encoder) { + if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED) + FLAC__encoder_finish(encoder_wrapper.encoder); + FLAC__encoder_free_instance(encoder_wrapper.encoder); + } + if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) { + print_stats(&encoder_wrapper); + printf("\n"); + } + fclose(fin); + return 0; +raw_abort_: + if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) + printf("\n"); + if(encoder_wrapper.encoder) { + if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED) + FLAC__encoder_finish(encoder_wrapper.encoder); + FLAC__encoder_free_instance(encoder_wrapper.encoder); + } + fclose(fin); + unlink(outfile); + return 1; +} + +bool init(encoder_wrapper_struct *encoder_wrapper) +{ + unsigned i; + uint32 test = 1; + + is_big_endian_host = (*((byte*)(&test)))? false : true; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + input[i] = &(in[i][0]); + + encoder_wrapper->encoder = FLAC__encoder_get_new_instance(); + if(0 == encoder_wrapper->encoder) { + fprintf(stderr, "ERROR creating the encoder instance\n"); + return false; + } + + return true; +} + +bool init_encoder(bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper) +{ + if(channels != 2 || bps > 16) + do_mid_side = false; + + encoder_wrapper->encoder->streamable_subset = !lax; + encoder_wrapper->encoder->channels = channels; + encoder_wrapper->encoder->bits_per_sample = bps; + encoder_wrapper->encoder->sample_rate = sample_rate; + encoder_wrapper->encoder->blocksize = blocksize; + encoder_wrapper->encoder->qlp_coeff_precision = qlp_coeff_precision; + encoder_wrapper->encoder->max_lpc_order = max_lpc_order; + encoder_wrapper->encoder->do_mid_side_stereo = do_mid_side; + encoder_wrapper->encoder->do_exhaustive_model_search = do_exhaustive_model_search; + encoder_wrapper->encoder->do_qlp_coeff_prec_search = do_qlp_coeff_prec_search; + encoder_wrapper->encoder->rice_optimization_level = rice_optimization_level; + + if(FLAC__encoder_init(encoder_wrapper->encoder, write_callback, metadata_callback, encoder_wrapper) != FLAC__ENCODER_OK) { + fprintf(stderr, "ERROR initializing encoder, state = %d\n", encoder_wrapper->encoder->state); + return false; + } + + return true; +} + +void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps) +{ + unsigned wide_sample, sample, channel, byte; + + if(bps == 8) { + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + input[channel][wide_sample] = (int32)ucbuffer[sample] - 128; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + input[channel][wide_sample] = (int32)scbuffer[sample]; + } + } + else { + if(is_big_endian != is_big_endian_host) { + unsigned char tmp; + const unsigned bytes = wide_samples * channels * (bps >> 3); + for(byte = 0; byte < bytes; byte += 2) { + tmp = ucbuffer[byte]; + ucbuffer[byte] = ucbuffer[byte+1]; + ucbuffer[byte+1] = tmp; + } + } + if(is_unsigned_samples) { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + input[channel][wide_sample] = (int32)usbuffer[sample] - 32768; + } + else { + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + input[channel][wide_sample] = (int32)ssbuffer[sample]; + } + } +} + +FLAC__EncoderWriteStatus write_callback(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) +{ + encoder_wrapper_struct *encoder_wrapper = (encoder_wrapper_struct *)client_data; + unsigned mask = (encoder->do_exhaustive_model_search || encoder->do_qlp_coeff_prec_search)? 0x07 : 0x1f; + + encoder_wrapper->bytes_written += bytes; + encoder_wrapper->samples_written += samples; + encoder_wrapper->current_frame = current_frame; + + if(samples && encoder_wrapper->verbose && encoder_wrapper->total_samples_to_encode > 0 && !(current_frame & mask)) + print_stats(encoder_wrapper); + + if(fwrite(buffer, sizeof(byte), bytes, encoder_wrapper->fout) == bytes) + return FLAC__ENCODER_WRITE_OK; + else + return FLAC__ENCODER_WRITE_FATAL_ERROR; +} + +void metadata_callback(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data) +{ + encoder_wrapper_struct *encoder_wrapper = (encoder_wrapper_struct *)client_data; + byte b; + FILE *f; + const uint64 samples = metadata->data.encoding.total_samples; + const unsigned min_framesize = metadata->data.encoding.min_framesize; + const unsigned max_framesize = metadata->data.encoding.max_framesize; + + (void)encoder; /* silence compiler warning about unused parameter */ + + if(encoder_wrapper->fout == stdout) + return; + + fclose(encoder_wrapper->fout); + if(0 == (f = fopen(encoder_wrapper->outfile, "r+b"))) + return; + + /* all this is based on intimate knowledge of the stream header + * layout, but a change to the header format that would break this + * would also break all streams encoded in the previous format. + */ + + if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_; + if(fread(&b, 1, 1, f) != 1) goto framesize_; + if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_; + b = (b & 0xf0) | (byte)((samples >> 32) & 0x0F); + if(fwrite(&b, 1, 1, f) != 1) goto framesize_; + b = (byte)((samples >> 24) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto framesize_; + b = (byte)((samples >> 16) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto framesize_; + b = (byte)((samples >> 8) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto framesize_; + b = (byte)(samples & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto framesize_; + +framesize_: + if(-1 == fseek(f, 12, SEEK_SET)) goto end_; + b = (byte)((min_framesize >> 16) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; + b = (byte)((min_framesize >> 8) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; + b = (byte)(min_framesize & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; + b = (byte)((max_framesize >> 16) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; + b = (byte)((max_framesize >> 8) & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; + b = (byte)(max_framesize & 0xFF); + if(fwrite(&b, 1, 1, f) != 1) goto end_; +end_: + fclose(encoder_wrapper->fout); + return; +} + +void print_stats(const encoder_wrapper_struct *encoder_wrapper) +{ +#ifdef _MSC_VER + /* with VC++ you have to spoon feed it the casting */ + double progress = (double)(int64)encoder_wrapper->samples_written / (double)(int64)encoder_wrapper->total_samples_to_encode; +#else + double progress = (double)encoder_wrapper->samples_written / (double)encoder_wrapper->total_samples_to_encode; +#endif + printf("\r%0.2f%% complete: frame %u, wrote %u bytes, %u of %u samples, ratio = %5.3f", + progress * 100.0, encoder_wrapper->current_frame, + (unsigned)encoder_wrapper->bytes_written, (unsigned)encoder_wrapper->samples_written, (unsigned)encoder_wrapper->total_samples_to_encode, +#ifdef _MSC_VER + /* with VC++ you have to spoon feed it the casting */ + (double)(int64)encoder_wrapper->bytes_written / ((double)(int64)encoder_wrapper->unencoded_size * progress) +#else + (double)encoder_wrapper->bytes_written / ((double)encoder_wrapper->unencoded_size * progress) +#endif + ); + fflush(stdout); +} + +bool read_little_endian_uint16(FILE *f, uint16 *val, bool eof_ok) +{ + size_t bytes_read = fread(val, 1, 2, f); + + if(bytes_read == 0) { + if(!eof_ok) { + fprintf(stderr, "ERROR: unexpected EOF\n"); + return false; + } + else + return true; + } + else if(bytes_read < 2) { + fprintf(stderr, "ERROR: unexpected EOF\n"); + return false; + } + else { + if(is_big_endian_host) { + byte tmp, *b = (byte*)val; + tmp = b[1]; b[1] = b[0]; b[0] = tmp; + } + return true; + } +} + +bool read_little_endian_uint32(FILE *f, uint32 *val, bool eof_ok) +{ + size_t bytes_read = fread(val, 1, 4, f); + + if(bytes_read == 0) { + if(!eof_ok) { + fprintf(stderr, "ERROR: unexpected EOF\n"); + return false; + } + else + return true; + } + else if(bytes_read < 4) { + fprintf(stderr, "ERROR: unexpected EOF\n"); + return false; + } + else { + if(is_big_endian_host) { + byte tmp, *b = (byte*)val; + tmp = b[3]; b[3] = b[0]; b[0] = tmp; + tmp = b[2]; b[2] = b[1]; b[1] = tmp; + } + return true; + } +} diff --git a/src/flac/encode.h b/src/flac/encode.h new file mode 100644 index 00000000..74a1f1e3 --- /dev/null +++ b/src/flac/encode.h @@ -0,0 +1,27 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef flac__encode_h +#define flac__encode_h + +#include "FLAC/ordinals.h" + +int encode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision); +int encode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate); + +#endif diff --git a/src/flac/main.c b/src/flac/main.c new file mode 100644 index 00000000..b7cba205 --- /dev/null +++ b/src/flac/main.c @@ -0,0 +1,338 @@ +/* flac - Command-line FLAC encoder/decoder + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "FLAC/all.h" +#include "decode.h" +#include "encode.h" + +static int usage(const char *message, ...); + +int main(int argc, char *argv[]) +{ + int i; + bool verbose = true, lax = false, mode_decode = false, do_mid_side = true, do_exhaustive_model_search = false, do_qlp_coeff_prec_search = false; + unsigned max_lpc_order = 8; + unsigned qlp_coeff_precision = 0; + uint64 skip = 0; + int format_is_wave = -1, format_is_big_endian = -1, format_is_unsigned_samples = false; + int format_channels = -1, format_bps = -1, format_sample_rate = -1; + int blocksize = -1, rice_optimization_level = -1; + + if(argc <= 1) + return usage(0); + + /* get the options */ + for(i = 1; i < argc; i++) { + if(argv[i][0] != '-' || argv[i][1] == 0) + break; + if(0 == strcmp(argv[i], "-d")) + mode_decode = true; + else if(0 == strcmp(argv[i], "-s")) + verbose = false; + else if(0 == strcmp(argv[i], "-s-")) + verbose = true; + else if(0 == strcmp(argv[i], "--skip")) + skip = (uint64)atoi(argv[++i]); /* takes a pretty damn big file to overflow atoi() here, but it could happen */ + else if(0 == strcmp(argv[i], "--lax")) + lax = true; + else if(0 == strcmp(argv[i], "--lax-")) + lax = false; + else if(0 == strcmp(argv[i], "-b")) + blocksize = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-e")) + do_exhaustive_model_search = true; + else if(0 == strcmp(argv[i], "-e-")) + do_exhaustive_model_search = false; + else if(0 == strcmp(argv[i], "-l")) + max_lpc_order = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-m")) + do_mid_side = true; + else if(0 == strcmp(argv[i], "-m-")) + do_mid_side = false; + else if(0 == strcmp(argv[i], "-p")) + do_qlp_coeff_prec_search = true; + else if(0 == strcmp(argv[i], "-p-")) + do_qlp_coeff_prec_search = false; + else if(0 == strcmp(argv[i], "-q")) + qlp_coeff_precision = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-r")) + rice_optimization_level = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-fb")) + format_is_big_endian = true; + else if(0 == strcmp(argv[i], "-fl")) + format_is_big_endian = false; + else if(0 == strcmp(argv[i], "-fc")) + format_channels = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-fp")) + format_bps = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-fs")) + format_sample_rate = atoi(argv[++i]); + else if(0 == strcmp(argv[i], "-fu")) + format_is_unsigned_samples = true; + else if(0 == strcmp(argv[i], "-fr")) + format_is_wave = false; + else if(0 == strcmp(argv[i], "-fw")) + format_is_wave = true; + else if(0 == strcmp(argv[i], "-0")) { + do_exhaustive_model_search = false; + do_mid_side = false; + qlp_coeff_precision = 0; + rice_optimization_level = 0; + max_lpc_order = 0; + } + else if(0 == strcmp(argv[i], "-1")) { + do_exhaustive_model_search = false; + do_mid_side = true; + qlp_coeff_precision = 0; + rice_optimization_level = 0; + max_lpc_order = 0; + } + else if(0 == strcmp(argv[i], "-2")) { + do_exhaustive_model_search = false; + do_mid_side = true; + qlp_coeff_precision = 0; + max_lpc_order = 0; + } + else if(0 == strcmp(argv[i], "-4")) { + do_exhaustive_model_search = false; + do_mid_side = false; + qlp_coeff_precision = 0; + rice_optimization_level = 0; + max_lpc_order = 8; + } + else if(0 == strcmp(argv[i], "-5")) { + do_exhaustive_model_search = false; + do_mid_side = true; + qlp_coeff_precision = 0; + rice_optimization_level = 0; + max_lpc_order = 8; + } + else if(0 == strcmp(argv[i], "-6")) { + do_exhaustive_model_search = false; + do_mid_side = true; + qlp_coeff_precision = 0; + max_lpc_order = 8; + } + else if(0 == strcmp(argv[i], "-8")) { + do_exhaustive_model_search = false; + do_mid_side = true; + qlp_coeff_precision = 0; + max_lpc_order = 32; + } + else if(0 == strcmp(argv[i], "-9")) { + do_exhaustive_model_search = true; + do_mid_side = true; + do_qlp_coeff_prec_search = true; + rice_optimization_level = 99; + max_lpc_order = 32; + } + else if(isdigit((int)(argv[i][1]))) { + return usage("ERROR: compression level '%s' is still reserved\n", argv[i]); + } + else { + return usage("ERROR: invalid option '%s'\n", argv[i]); + } + } + if(i + 2 != argc) + return usage("ERROR: invalid arguments (more/less than 2 filenames?)\n"); + + /* tweak options based on the filenames; validate the values */ + if(!mode_decode) { + if(format_is_wave < 0) { + if(strstr(argv[i], ".wav") == argv[i] + (strlen(argv[i]) - strlen(".wav"))) + format_is_wave = true; + else + format_is_wave = false; + } + if(!format_is_wave) { + if(format_is_big_endian < 0 || format_channels < 0 || format_bps < 0 || format_sample_rate < 0) + return usage("ERROR: for encoding a raw file you must specify { -fb or -fl }, -fc, -fp, and -fs\n"); + } + if(blocksize < 0) { + if(max_lpc_order == 0) + blocksize = 1152; + else + blocksize = 4608; + } + if(rice_optimization_level < 0) { + if(blocksize <= 1152) + rice_optimization_level = 4; + else if(blocksize <= 2304) + rice_optimization_level = 4; + else if(blocksize <= 4608) + rice_optimization_level = 4; + else + rice_optimization_level = 5; + } + } + else { + if(format_is_wave < 0) { + if(strstr(argv[i+1], ".wav") == argv[i+1] + (strlen(argv[i+1]) - strlen(".wav"))) + format_is_wave = true; + else + format_is_wave = false; + } + if(!format_is_wave) { + if(format_is_big_endian < 0) + return usage("ERROR: for decoding to a raw file you must specify -fb or -fl\n"); + } + } + + assert(blocksize >= 0 || mode_decode); + + if(format_channels >= 0) { + if(format_channels == 0 || (unsigned)format_channels > FLAC__MAX_CHANNELS) + return usage("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", format_channels, FLAC__MAX_CHANNELS); + } + if(format_bps >= 0) { + if(format_bps != 8 && format_bps != 16) + return usage("ERROR: invalid bits per sample '%u' (must be 8 or 16)\n", format_bps); + } + if(format_sample_rate >= 0) { + if(format_sample_rate == 0 || (unsigned)format_sample_rate > FLAC__MAX_SAMPLE_RATE) + return usage("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", format_sample_rate, FLAC__MAX_SAMPLE_RATE); + } + if(!mode_decode && ((unsigned)blocksize < FLAC__MIN_BLOCK_SIZE || (unsigned)blocksize > FLAC__MAX_BLOCK_SIZE)) { + return usage("ERROR: invalid blocksize '%u', must be >= %u and <= %u\n", (unsigned)blocksize, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE); + } + if(qlp_coeff_precision > 0 && qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION) { + return usage("ERROR: invalid value for -q '%u', must be 0 or >= %u\n", qlp_coeff_precision, FLAC__MIN_QLP_COEFF_PRECISION); + } + + /* turn off verbosity if the output stream is going to stdout */ + if(0 == strcmp(argv[i+1], "-")) + verbose = false; + + if(verbose) { + printf("\n"); + printf("flac v%u.%u, Copyright (C) 2000 Josh Coalson\n", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION); + printf("flac comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n"); + printf("welcome to redistribute it under certain conditions. Type `flac' for details.\n\n"); + + if(!mode_decode) { + printf("options:%s -b %u%s -l %u%s%s -q %u -r %u\n", + lax?" --lax":"", (unsigned)blocksize, do_mid_side?" -m":"", max_lpc_order, + do_exhaustive_model_search?" -e":"", do_qlp_coeff_prec_search?" -p":"", + qlp_coeff_precision, (unsigned)rice_optimization_level + ); + } + } + + if(mode_decode) + if(format_is_wave) + return decode_wav(argv[i], argv[i+1], verbose, skip); + else + return decode_raw(argv[i], argv[i+1], verbose, skip, format_is_big_endian, format_is_unsigned_samples); + else + if(format_is_wave) + return encode_wav(argv[i], argv[i+1], verbose, skip, lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision); + else + return encode_raw(argv[i], argv[i+1], verbose, skip, lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision, format_is_big_endian, format_is_unsigned_samples, format_channels, format_bps, format_sample_rate); + + return 0; +} + +int usage(const char *message, ...) +{ + va_list args; + + if(message) { + fprintf(stderr, message); + fprintf(stderr, "\n"); + va_start(args, message); + + (void) vfprintf(stderr, message, args); + + va_end(args); + + } + printf("==============================================================================\n"); + printf("flac - Command-line FLAC encoder/decoder version %u.%u\n", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION); + printf("Copyright (C) 2000 Josh Coalson\n"); + printf("\n"); + printf("This program is free software; you can redistribute it and/or\n"); + printf("modify it under the terms of the GNU General Public License\n"); + printf("as published by the Free Software Foundation; either version 2\n"); + printf("of the License, or (at your option) any later version.\n"); + printf("\n"); + printf("This program is distributed in the hope that it will be useful,\n"); + printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + printf("GNU General Public License for more details.\n"); + printf("\n"); + printf("You should have received a copy of the GNU General Public License\n"); + printf("along with this program; if not, write to the Free Software\n"); + printf("Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); + printf("==============================================================================\n"); + printf("Usage:\n"); + printf(" flac [options] infile outfile\n"); + printf("\n"); + printf("For encoding:\n"); + printf(" infile may be a PCM RIFF WAVE file or raw samples\n"); + printf(" outfile will be in FLAC format\n"); + printf("For decoding, the reverse will be true\n"); + printf("\n"); + printf("infile may be - for stdin, outfile may be - for stdout\n"); + printf("\n"); + printf("If the unencoded filename ends with '.wav' or -fw is used, it's assumed to be\n"); + printf("RIFF WAVE. Otherwise, it's assumed to be raw samples and you have to specify\n"); + printf("all the format options. You can force a .wav file to be treated as a raw file\n"); + printf("using -fr.\n"); + printf("\n"); + printf("generic options:\n"); + printf(" -d : decode (default behavior is encode)\n"); + printf(" -s : silent (do not write runtime encode/decode statistics to stdout)\n"); + printf(" --skip samples : can be used both for encoding and decoding\n"); + printf("encoding options:\n"); + printf(" --lax : allow encoder to generate non-Subset files\n"); + printf(" -b blocksize : default is 1152 for -l 0, else 4608; should be 192/576/1152/2304/4608 (unless --lax is used)\n"); + printf(" -m : try mid-side coding for each frame (stereo input only)\n"); + printf(" -0 .. -9 : fastest compression .. highest compression, default is -6\n"); + printf(" these are synonyms for other options:\n"); + printf(" -0 : synonymous with -l 0\n"); + printf(" -1 : synonymous with -l 0 -m\n"); + printf(" -2 : synonymous with -l 0 -m -r # (# is automatically determined by the block size)\n"); + printf(" -3 : reserved\n"); + printf(" -4 : synonymous with -l 8\n"); + printf(" -5 : synonymous with -l 8 -m\n"); + printf(" -6 : synonymous with -l 8 -m -r # (# is automatically determined by the block size)\n"); + printf(" -7 : reserved\n"); + printf(" -8 : synonymous with -l 32 -m -r # (# is automatically determined by the block size)\n"); + printf(" -9 : synonymous with -l 32 -m -e -r 99 -p (very slow!)\n"); + printf(" -e : do exhaustive model search (expensive!)\n"); + printf(" -l max_lpc_order : 0 => use only fixed predictors\n"); + printf(" -p : do exhaustive search of LP coefficient quantization (expensive!); overrides -q\n"); + printf(" -q bits : precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is %u, default is -q 0)\n", FLAC__MIN_QLP_COEFF_PRECISION); + printf(" -r level : rice parameter optimization level (level is 0..99, 0 => none, default is -r 0, above 4 doesn't usually help much)\n"); + printf(" -m-, -e-, -p-, --lax- can all be used to turn off a particular option\n"); + printf("format options:\n"); + printf(" -fb | -fl : big-endian | little-endian byte order\n"); + printf(" -fc channels\n"); + printf(" -fp bits_per_sample\n"); + printf(" -fs sample_rate : in Hz\n"); + printf(" -fu : unsigned samples (default is signed)\n"); + printf(" -fr : force to raw format (even if filename ends in .wav)\n"); + printf(" -fw : force to RIFF WAVE\n"); + return 1; +} diff --git a/src/libFLAC/Makefile b/src/libFLAC/Makefile new file mode 100644 index 00000000..f6662a39 --- /dev/null +++ b/src/libFLAC/Makefile @@ -0,0 +1,22 @@ +# +# GNU makefile +# + +LIB_NAME = libFLAC +INCLUDES = -I./include -I../../include +DEBUG_CFLAGS = -DFLAC_OVERFLOW_DETECT + +OBJS = \ + bitbuffer.o \ + crc.o \ + encoder.o \ + encoder_framing.o \ + file_decoder.o \ + fixed.o \ + format.o \ + lpc.o \ + stream_decoder.o + +include ../../build/lib.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/libFLAC/Makefile.vc b/src/libFLAC/Makefile.vc new file mode 100644 index 00000000..5bccf54b --- /dev/null +++ b/src/libFLAC/Makefile.vc @@ -0,0 +1,31 @@ +!include <win32.mak> + +!IFDEF DEBUG +.c.obj: + $(cc) /D FLAC_OVERFLOW_DETECT /GX $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $< +!else +.c.obj: + $(cc) $(cdebug) $(cflags) /O2 /I "..\..\include" /I ".\include" -DSTRICT -YX -DNODEBUG $< +!endif + +C_FILES= \ + bitbuffer.c \ + crc.c \ + encoder.c \ + encoder_framing.c \ + file_decoder.c \ + fixed.c \ + format.c \ + lpc.c \ + stream_decoder.c + +OBJS= $(C_FILES:.c=.obj) + +all: libFLAC.lib + +libFLAC.lib: $(OBJS) + link.exe -lib -out:../../obj/lib/$*.lib $(OBJS) + +clean: + -del *.obj *.pch + -del ..\..\obj\lib\libFLAC.lib ..\..\obj\lib\libFLAC.pdb diff --git a/src/libFLAC/bitbuffer.c b/src/libFLAC/bitbuffer.c new file mode 100644 index 00000000..5f618a98 --- /dev/null +++ b/src/libFLAC/bitbuffer.c @@ -0,0 +1,962 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for memcpy(), memset() */ +#include "private/bitbuffer.h" + +static const unsigned FLAC__BITBUFFER_DEFAULT_CAPACITY = 65536; /* bytes */ + +#ifdef min +#undef min +#endif +#define min(x,y) ((x)<(y)?(x):(y)) +#ifdef max +#undef max +#endif +#define max(x,y) ((x)>(y)?(x):(y)) + +static bool bitbuffer_resize_(FLAC__BitBuffer *bb, unsigned new_capacity) +{ + byte *new_buffer; + + assert(bb != 0); + assert(bb->buffer != 0); + + if(bb->capacity == new_capacity) + return true; + + new_buffer = (byte*)malloc(sizeof(byte) * new_capacity); + if(new_buffer == 0) + return false; + memset(new_buffer, 0, new_capacity); + memcpy(new_buffer, bb->buffer, sizeof(byte)*min(bb->bytes+(bb->bits?1:0), new_capacity)); + if(new_capacity < bb->bytes+(bb->bits?1:0)) { + bb->bytes = new_capacity; + bb->bits = 0; + bb->total_bits = (new_capacity<<3); + } + if(new_capacity < bb->consumed_bytes+(bb->consumed_bits?1:0)) { + bb->consumed_bytes = new_capacity; + bb->consumed_bits = 0; + bb->total_consumed_bits = (new_capacity<<3); + } + bb->buffer = new_buffer; + bb->capacity = new_capacity; + return true; +} + +static bool bitbuffer_grow_(FLAC__BitBuffer *bb, unsigned min_bytes_to_add) +{ + unsigned new_capacity; + + assert(min_bytes_to_add > 0); + + new_capacity = max(bb->capacity * 4, bb->capacity + min_bytes_to_add); + return bitbuffer_resize_(bb, new_capacity); +} + +static bool bitbuffer_ensure_size_(FLAC__BitBuffer *bb, unsigned bits_to_add) +{ + assert(bb != 0); + assert(bb->buffer != 0); + if((bb->capacity<<3) < bb->total_bits + bits_to_add) + return bitbuffer_grow_(bb, (bits_to_add>>3)+2); + else + return true; +} + +static bool bitbuffer_read_from_client_(FLAC__BitBuffer *bb, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + unsigned bytes; + + /* first shift the unconsumed buffer data toward the front as much as possible */ + if(bb->total_consumed_bits >= 8) { + unsigned l = 0, r = bb->consumed_bytes, r_end = bb->bytes; + for( ; r < r_end; l++, r++) + bb->buffer[l] = bb->buffer[r]; + for( ; l < r_end; l++) + bb->buffer[l] = 0; + bb->bytes -= bb->consumed_bytes; + bb->total_bits -= (bb->consumed_bytes<<3); + bb->consumed_bytes = 0; + bb->total_consumed_bits = bb->consumed_bits; + } + /* grow if we need to */ + if(bb->capacity <= 1) { + if(!bitbuffer_resize_(bb, 16)) + return false; + } + /* finally, read in some data; if OK, go back to read_bit_, else fail */ + bytes = bb->capacity - bb->bytes; + if(!read_callback(bb->buffer+bb->bytes, &bytes, client_data)) + return false; + bb->bytes += bytes; + bb->total_bits += (bytes<<3); + return true; +} + +void FLAC__bitbuffer_init(FLAC__BitBuffer *bb) +{ + assert(bb != 0); + bb->buffer = 0; + bb->capacity = 0; + bb->bytes = bb->bits = bb->total_bits = 0; + bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0; +} + +bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const byte buffer[], unsigned bytes) +{ + assert(bb != 0); + FLAC__bitbuffer_init(bb); + if(bytes == 0) + return true; + else { + assert(buffer != 0); + bb->buffer = (byte*)malloc(sizeof(byte)*bytes); + if(bb->buffer == 0) + return false; + memcpy(bb->buffer, buffer, sizeof(byte)*bytes); + bb->capacity = bb->bytes = bytes; + bb->bits = 0; + bb->total_bits = (bytes<<3); + bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0; + return true; + } +} + +bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src) +{ + static byte mask_[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + unsigned bits_to_add = src->total_bits - src->total_consumed_bits; + assert(dest != 0); + assert(src != 0); + + if(bits_to_add == 0) + return true; + if(dest->bits != src->consumed_bits) + return false; + if(!bitbuffer_ensure_size_(dest, bits_to_add)) + return false; + if(dest->bits == 0) { + memcpy(dest->buffer+dest->bytes, src->buffer+src->consumed_bytes, src->bytes-src->consumed_bytes + ((src->bits)? 1:0)); + } + else if(dest->bits + bits_to_add > 8) { + dest->buffer[dest->bytes] <<= (8 - dest->bits); + dest->buffer[dest->bytes] |= (src->buffer[src->consumed_bytes] & mask_[8-dest->bits]); + memcpy(dest->buffer+dest->bytes+1, src->buffer+src->consumed_bytes+1, src->bytes-src->consumed_bytes-1 + ((src->bits)? 1:0)); + } + else { + dest->buffer[dest->bytes] <<= bits_to_add; + dest->buffer[dest->bytes] |= (src->buffer[src->consumed_bytes] & mask_[bits_to_add]); + } + dest->bits = src->bits; + dest->total_bits += bits_to_add; + dest->bytes = dest->total_bits / 8; + + return true; +} + +void FLAC__bitbuffer_free(FLAC__BitBuffer *bb) +{ + assert(bb != 0); + if(bb->buffer != 0) + free(bb->buffer); + bb->buffer = 0; + bb->capacity = 0; + bb->bytes = bb->bits = bb->total_bits = 0; + bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0; +} + +bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb) +{ + if(bb->buffer == 0) { + bb->capacity = FLAC__BITBUFFER_DEFAULT_CAPACITY; + bb->buffer = (byte*)malloc(sizeof(byte) * bb->capacity); + if(bb->buffer == 0) + return false; + memset(bb->buffer, 0, bb->capacity); + } + else { + memset(bb->buffer, 0, bb->bytes + (bb->bits?1:0)); + } + bb->bytes = bb->bits = bb->total_bits = 0; + bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0; + return true; +} + +bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src) +{ + if(dest->capacity < src->capacity) + if(!bitbuffer_resize_(dest, src->capacity)) + return false; + memcpy(dest->buffer, src->buffer, sizeof(byte)*min(src->capacity, src->bytes+1)); + dest->bytes = src->bytes; + dest->bits = src->bits; + dest->total_bits = src->total_bits; + dest->consumed_bytes = src->consumed_bytes; + dest->consumed_bits = src->consumed_bits; + dest->total_consumed_bits = src->total_consumed_bits; + return true; +} + +bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits) +{ + unsigned n, k; + + assert(bb != 0); + assert(bb->buffer != 0); + + if(bits == 0) + return true; + if(!bitbuffer_ensure_size_(bb, bits)) + return false; + bb->total_bits += bits; + while(bits > 0) { + n = min(8 - bb->bits, bits); + k = bits - n; + bb->buffer[bb->bytes] <<= n; + bits -= n; + bb->bits += n; + if(bb->bits == 8) { + bb->bytes++; + bb->bits = 0; + } + } + return true; +} + +bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, uint32 val, unsigned bits) +{ + static uint32 mask[] = { + 0, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF + }; + unsigned n, k; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 32); + if(bits == 0) + return true; + if(!bitbuffer_ensure_size_(bb, bits)) + return false; + val &= mask[bits]; + bb->total_bits += bits; + while(bits > 0) { + n = 8 - bb->bits; + if(n == 8) { /* i.e. bb->bits == 0 */ + if(bits < 8) { + bb->buffer[bb->bytes] = val; + bb->bits = bits; + break; + } + else if(bits == 8) { + bb->buffer[bb->bytes++] = val; + break; + } + else { + k = bits - 8; + bb->buffer[bb->bytes++] = val >> k; + val &= (~(0xffffffff << k)); + bits -= 8; + } + } + else if(bits <= n) { + bb->buffer[bb->bytes] <<= bits; + bb->buffer[bb->bytes] |= val; + if(bits == n) { + bb->bytes++; + bb->bits = 0; + } + else + bb->bits += bits; + break; + } + else { + k = bits - n; + bb->buffer[bb->bytes] <<= n; + bb->buffer[bb->bytes] |= (val>>k); + val &= (~(0xffffffff << k)); + bits -= n; + bb->bytes++; + bb->bits = 0; + } + } + + return true; +} + +bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, int32 val, unsigned bits) +{ + return FLAC__bitbuffer_write_raw_uint32(bb, (uint32)val, bits); +} + +bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, uint64 val, unsigned bits) +{ + static uint64 mask[] = { + 0, + 0x0000000000000001, 0x0000000000000003, 0x0000000000000007, 0x000000000000000F, + 0x000000000000001F, 0x000000000000003F, 0x000000000000007F, 0x00000000000000FF, + 0x00000000000001FF, 0x00000000000003FF, 0x00000000000007FF, 0x0000000000000FFF, + 0x0000000000001FFF, 0x0000000000003FFF, 0x0000000000007FFF, 0x000000000000FFFF, + 0x000000000001FFFF, 0x000000000003FFFF, 0x000000000007FFFF, 0x00000000000FFFFF, + 0x00000000001FFFFF, 0x00000000003FFFFF, 0x00000000007FFFFF, 0x0000000000FFFFFF, + 0x0000000001FFFFFF, 0x0000000003FFFFFF, 0x0000000007FFFFFF, 0x000000000FFFFFFF, + 0x000000001FFFFFFF, 0x000000003FFFFFFF, 0x000000007FFFFFFF, 0x00000000FFFFFFFF, + 0x00000001FFFFFFFF, 0x00000003FFFFFFFF, 0x00000007FFFFFFFF, 0x0000000FFFFFFFFF, + 0x0000001FFFFFFFFF, 0x0000003FFFFFFFFF, 0x0000007FFFFFFFFF, 0x000000FFFFFFFFFF, + 0x000001FFFFFFFFFF, 0x000003FFFFFFFFFF, 0x000007FFFFFFFFFF, 0x00000FFFFFFFFFFF, + 0x00001FFFFFFFFFFF, 0x00003FFFFFFFFFFF, 0x00007FFFFFFFFFFF, 0x0000FFFFFFFFFFFF, + 0x0001FFFFFFFFFFFF, 0x0003FFFFFFFFFFFF, 0x0007FFFFFFFFFFFF, 0x000FFFFFFFFFFFFF, + 0x001FFFFFFFFFFFFF, 0x003FFFFFFFFFFFFF, 0x007FFFFFFFFFFFFF, 0x00FFFFFFFFFFFFFF, + 0x01FFFFFFFFFFFFFF, 0x03FFFFFFFFFFFFFF, 0x07FFFFFFFFFFFFFF, 0x0FFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF + }; + unsigned n, k; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 64); + if(bits == 0) + return true; + if(!bitbuffer_ensure_size_(bb, bits)) + return false; + val &= mask[bits]; + bb->total_bits += bits; + while(bits > 0) { + if(bb->bits == 0) { + if(bits < 8) { + bb->buffer[bb->bytes] = val; + bb->bits = bits; + break; + } + else if(bits == 8) { + bb->buffer[bb->bytes++] = val; + break; + } + else { + k = bits - 8; + bb->buffer[bb->bytes++] = val >> k; + val &= (~(0xffffffffffffffff << k)); + bits -= 8; + } + } + else { + n = min(8 - bb->bits, bits); + k = bits - n; + bb->buffer[bb->bytes] <<= n; + bb->buffer[bb->bytes] |= (val>>k); + val &= (~(0xffffffffffffffff << k)); + bits -= n; + bb->bits += n; + if(bb->bits == 8) { + bb->bytes++; + bb->bits = 0; + } + } + } + + return true; +} + +bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, int64 val, unsigned bits) +{ + return FLAC__bitbuffer_write_raw_uint64(bb, (uint64)val, bits); +} + +bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter) +{ + unsigned bits, msbs; + uint32 pattern; + + assert(bb != 0); + assert(bb->buffer != 0); + + /* init pattern with sign bit */ + if(val < 0) { + pattern = 1; + val = -val; + } + else + pattern = 0; + + msbs = val >> parameter; + bits = 2 + parameter + msbs; + + if(bits <= 32) { + pattern = (pattern << parameter) | (val & ((1<<parameter)-1)); + pattern = (pattern << (msbs+1)) | 1; + if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, bits)) + return false; + } + else { + /* write the sign bit */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, 1)) + return false; + /* write the binary LSBs */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, val & ((1<<parameter)-1), parameter)) + return false; + /* write the unary MSBs */ + if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) + return false; + /* write the end bit */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1)) + return false; + } + return true; +} + +bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, bool *overflow) +{ + unsigned bits, msbs; + uint32 pattern; + + assert(bb != 0); + assert(bb->buffer != 0); + + *overflow = false; + + /* init pattern with sign bit */ + if(val < 0) { + pattern = 1; + val = -val; + } + else + pattern = 0; + + msbs = val >> parameter; + bits = 2 + parameter + msbs; + + if(bits <= 32) { + pattern = (pattern << parameter) | (val & ((1<<parameter)-1)); + pattern = (pattern << (msbs+1)) | 1; + if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, bits)) + return false; + } + else if(bits > max_bits) { + *overflow = true; + return true; + } + else { + /* write the sign bit */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, 1)) + return false; + /* write the binary LSBs */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, val & ((1<<parameter)-1), parameter)) + return false; + /* write the unary MSBs */ + if(!FLAC__bitbuffer_write_zeroes(bb, msbs)) + return false; + /* write the end bit */ + if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1)) + return false; + } + return true; +} + +bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, uint32 val) +{ + bool ok = 1; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(!(val & 0x80000000)); /* this version only handles 31 bits */ + + if(val < 0x80) { + return FLAC__bitbuffer_write_raw_uint32(bb, val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (val>>6), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (val>>12), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (val>>18), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (val>>24), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); + } + else { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (val>>30), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>24)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8); + } + + return ok; +} + +bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, uint64 val) +{ + bool ok = 1; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(!(val & 0xFFFFFFF000000000)); /* this version only handles 36 bits */ + + if(val < 0x80) { + return FLAC__bitbuffer_write_raw_uint32(bb, (uint32)val, 8); + } + else if(val < 0x800) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (uint32)(val>>6), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + else if(val < 0x10000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (uint32)(val>>12), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + else if(val < 0x200000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (uint32)(val>>18), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + else if(val < 0x4000000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (uint32)(val>>24), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + else if(val < 0x80000000) { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (uint32)(val>>30), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + else { + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFE, 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>30)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>24)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8); + ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8); + } + + return ok; +} + +bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb) +{ + /* 0-pad to byte boundary */ + if(bb->bits != 0) + return FLAC__bitbuffer_write_zeroes(bb, 8 - bb->bits); + else + return true; +} + +bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; + + /* to avoid a drastic speed penalty we don't: + assert(bb != 0); + assert(bb->buffer != 0); + assert(bb->bits == 0); + */ + +read_bit_: + if(bb->total_consumed_bits < bb->total_bits) { + *val = (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0; + return true; + } + else { + if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) + return false; + goto read_bit_; + } +} + +bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; + + /* to avoid a drastic speed penalty we don't: + assert(bb != 0); + assert(bb->buffer != 0); + assert(bb->bits == 0); + */ + +read_bit_: + if(bb->total_consumed_bits < bb->total_bits) { + *val = (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0; + bb->consumed_bits++; + if(bb->consumed_bits == 8) { + bb->consumed_bytes++; + bb->consumed_bits = 0; + } + bb->total_consumed_bits++; + return true; + } + else { + if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) + return false; + goto read_bit_; + } +} + +bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; + + /* to avoid a drastic speed penalty we don't: + assert(bb != 0); + assert(bb->buffer != 0); + assert(bb->bits == 0); + */ + +read_bit_: + if(bb->total_consumed_bits < bb->total_bits) { + *val <<= 1; + *val |= (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0; + bb->consumed_bits++; + if(bb->consumed_bits == 8) { + bb->consumed_bytes++; + bb->consumed_bits = 0; + } + bb->total_consumed_bits++; + return true; + } + else { + if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) + return false; + goto read_bit_; + } +} + +bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; + + /* to avoid a drastic speed penalty we don't: + assert(bb != 0); + assert(bb->buffer != 0); + assert(bb->bits == 0); + */ + +read_bit_: + if(bb->total_consumed_bits < bb->total_bits) { + *val <<= 1; + *val |= (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0; + bb->consumed_bits++; + if(bb->consumed_bits == 8) { + bb->consumed_bytes++; + bb->consumed_bits = 0; + } + bb->total_consumed_bits++; + return true; + } + else { + if(!bitbuffer_read_from_client_(bb, read_callback, client_data)) + return false; + goto read_bit_; + } +} + +bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, uint32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + unsigned i; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 32); + + *val = 0; + for(i = 0; i < bits; i++) { + if(!FLAC__bitbuffer_read_bit_to_uint32(bb, val, read_callback, client_data)) + return false; + } + return true; +} + +bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, int32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + unsigned i; + uint32 x; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 32); + + x = 0; + for(i = 0; i < bits; i++) { + if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &x, read_callback, client_data)) + return false; + } + /* fix the sign */ + i = 32 - bits; + if(i) { + x <<= i; + *val = (int32)x; + *val >>= i; + } + else + *val = (int32)x; + + return true; +} + +bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, uint64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + unsigned i; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 64); + + *val = 0; + for(i = 0; i < bits; i++) { + if(!FLAC__bitbuffer_read_bit_to_uint64(bb, val, read_callback, client_data)) + return false; + } + return true; +} + +bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, int64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + unsigned i; + uint64 x; + + assert(bb != 0); + assert(bb->buffer != 0); + + assert(bits <= 64); + + x = 0; + for(i = 0; i < bits; i++) { + if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &x, read_callback, client_data)) + return false; + } + /* fix the sign */ + i = 64 - bits; + if(i) { + x <<= i; + *val = (int64)x; + *val >>= i; + } + else + *val = (int64)x; + + return true; +} + +bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data) +{ + uint32 sign = 0, lsbs, msbs = 0; + unsigned bit; + + assert(bb != 0); + assert(bb->buffer != 0); + + /* read the sign bit */ + if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &sign, read_callback, client_data)) + return false; + /* read the binary LSBs */ + if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, parameter, read_callback, client_data)) + return false; + /* read the unary MSBs and end bit */ + while(1) { + if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data)) + return false; + if(bit) + break; + else + msbs++; + } + /* compose the value */ + *val = (msbs << parameter) | lsbs; + if(sign) + *val = -(*val); + + return true; +} + +/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ +bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen) +{ + uint32 v = 0; + uint32 x; + unsigned i; + + if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) + return false; + if(raw) + raw[(*rawlen)++] = (byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else + goto invalid_; + for( ; i; i--) { + if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) + return false; + if(raw) + raw[(*rawlen)++] = (byte)x; + if(!(x & 0x80) || (x & 0x40)) /* 10xxxxxx */ + goto invalid_; + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +invalid_: + *val = 0xffffffff; + return true; +} + +/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ +bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen) +{ + uint64 v = 0; + uint32 x; + unsigned i; + + if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) + return false; + if(raw) + raw[(*rawlen)++] = (byte)x; + if(!(x & 0x80)) { /* 0xxxxxxx */ + v = x; + i = 0; + } + else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */ + v = x & 0x1F; + i = 1; + } + else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */ + v = x & 0x0F; + i = 2; + } + else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */ + v = x & 0x07; + i = 3; + } + else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */ + v = x & 0x03; + i = 4; + } + else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */ + v = x & 0x01; + i = 5; + } + else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */ + v = 0; + i = 6; + } + else + goto invalid_; + for( ; i; i--) { + if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data)) + return false; + if(raw) + raw[(*rawlen)++] = (byte)x; + if(!(x & 0x80) || (x & 0x40)) /* 10xxxxxx */ + goto invalid_; + v <<= 6; + v |= (x & 0x3F); + } + *val = v; + return true; +invalid_: + *val = 0xffffffff; + return true; +} + +void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out) +{ + unsigned i, j; + if(bb == 0) { + fprintf(out, "bitbuffer is NULL\n"); + } + else { + fprintf(out, "bitbuffer: capacity=%u bytes=%u bits=%u total_bits=%u consumed: bytes=%u, bits=%u, total_bits=%u\n", bb->capacity, bb->bytes, bb->bits, bb->total_bits, bb->consumed_bytes, bb->consumed_bits, bb->total_consumed_bits); + for(i = 0; i < bb->bytes; i++) { + fprintf(out, "%08X: ", i); + for(j = 0; j < 8; j++) + if(i*8+j < bb->total_consumed_bits) + fprintf(out, "."); + else + fprintf(out, "%01u", bb->buffer[i] & (1 << (8-j-1)) ? 1:0); + fprintf(out, "\n"); + } + if(bb->bits > 0) { + fprintf(out, "%08X: ", i); + for(j = 0; j < bb->bits; j++) + if(i*8+j < bb->total_consumed_bits) + fprintf(out, "."); + else + fprintf(out, "%01u", bb->buffer[i] & (1 << (bb->bits-j-1)) ? 1:0); + fprintf(out, "\n"); + } + } +} diff --git a/src/libFLAC/crc.c b/src/libFLAC/crc.c new file mode 100644 index 00000000..7f6cbd21 --- /dev/null +++ b/src/libFLAC/crc.c @@ -0,0 +1,65 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "private/crc.h" + +byte FLAC__crc8(const byte *data, const unsigned len) +{ + static byte const crc8_table_[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 + }; + unsigned i; + byte crc = 0; + + for(i = 0; i < len; i++) + crc = crc8_table_[crc ^ *data++]; + + return crc; +} diff --git a/src/libFLAC/encoder.c b/src/libFLAC/encoder.c new file mode 100644 index 00000000..2a6fffa3 --- /dev/null +++ b/src/libFLAC/encoder.c @@ -0,0 +1,900 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for memcpy() */ +#include "FLAC/encoder.h" +#include "private/bitbuffer.h" +#include "private/encoder_framing.h" +#include "private/fixed.h" +#include "private/lpc.h" + +#ifdef min +#undef min +#endif +#define min(x,y) ((x)<(y)?(x):(y)) + +#ifdef max +#undef max +#endif +#define max(x,y) ((x)>(y)?(x):(y)) + +#ifdef RICE_BITS +#undef RICE_BITS +#endif +#define RICE_BITS(value, parameter) (2 + (parameter) + (((unsigned)((value) < 0? -(value) : (value))) >> (parameter))) + +typedef struct FLAC__EncoderPrivate { + unsigned input_capacity; /* current size (in samples) of the signal and residual buffers */ + int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */ + int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */ + real *real_signal[FLAC__MAX_CHANNELS]; /* the floating-point version of the input signal */ + real *real_signal_mid_side[2]; /* the floating-point version of the mid-side input signal (stereo only) */ + int32 *residual[2]; /* where the candidate and best subframe residual signals will be stored */ + unsigned best_residual; /* index into the above */ + FLAC__BitBuffer frame; /* the current frame being worked on */ + FLAC__BitBuffer frame_mid_side; /* special parallel workspace for the mid-side coded version of the current frame */ + FLAC__BitBuffer frame_left_side; /* special parallel workspace for the left-side coded version of the current frame */ + FLAC__BitBuffer frame_right_side; /* special parallel workspace for the right-side coded version of the current frame */ + FLAC__SubframeHeader best_subframe, candidate_subframe; + bool current_frame_can_do_mid_side; /* encoder sets this false when any given sample of a frame's side channel exceeds 16 bits */ + FLAC__StreamMetaData metadata; + unsigned current_sample_number; + unsigned current_frame_number; + FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); + void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data); + void *client_data; +} FLAC__EncoderPrivate; + +static bool encoder_resize_buffers_(FLAC__Encoder *encoder, unsigned new_size); +static bool encoder_process_frame_(FLAC__Encoder *encoder, bool is_last_frame); +static bool encoder_process_subframes_(FLAC__Encoder *encoder, bool is_last_frame, const FLAC__FrameHeader *frame_header, unsigned channels, const int32 *integer_signal[], const real *real_signal[], FLAC__BitBuffer *bitbuffer); +static unsigned encoder_evaluate_constant_subframe_(const int32 signal, unsigned bits_per_sample, FLAC__SubframeHeader *subframe); +static unsigned encoder_evaluate_fixed_subframe_(const int32 signal[], int32 residual[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe); +static unsigned encoder_evaluate_lpc_subframe_(const int32 signal[], int32 residual[], const real lp_coeff[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe); +static unsigned encoder_evaluate_verbatim_subframe_(unsigned blocksize, unsigned bits_per_sample, FLAC__SubframeHeader *subframe); +static unsigned encoder_find_best_partition_order_(int32 residual[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, unsigned max_partition_order, unsigned *best_partition_order, unsigned best_parameters[]); +static bool encoder_generate_constant_subframe_(const FLAC__SubframeHeader *header, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer); +static bool encoder_generate_fixed_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer); +static bool encoder_generate_lpc_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer); +static bool encoder_generate_verbatim_subframe_(const FLAC__SubframeHeader *header, const int32 signal[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer); +static void encoder_promote_candidate_subframe_(FLAC__Encoder *encoder); +static bool encoder_set_partitioned_rice_(const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameter, const unsigned partition_order, unsigned parameters[], unsigned *bits); + + +bool encoder_resize_buffers_(FLAC__Encoder *encoder, unsigned new_size) +{ + bool ok; + unsigned i; + int32 *previous_is, *current_is; + real *previous_rs, *current_rs; + int32 *residual; + + assert(new_size > 0); + assert(encoder->state == FLAC__ENCODER_OK); + assert(encoder->guts->current_sample_number == 0); + + /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */ + if(new_size <= encoder->guts->input_capacity) + return true; + + ok = 1; + if(ok) { + for(i = 0; ok && i < encoder->channels; i++) { + /* integer version of the signal */ + previous_is = encoder->guts->integer_signal[i]; + current_is = (int32*)malloc(sizeof(int32) * new_size); + if(0 == current_is) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + ok = 0; + } + else { + encoder->guts->integer_signal[i] = current_is; + if(previous_is != 0) + free(previous_is); + } + /* real version of the signal */ + previous_rs = encoder->guts->real_signal[i]; + current_rs = (real*)malloc(sizeof(real) * new_size); + if(0 == current_rs) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + ok = 0; + } + else { + encoder->guts->real_signal[i] = current_rs; + if(previous_rs != 0) + free(previous_rs); + } + } + } + if(ok) { + for(i = 0; ok && i < 2; i++) { + /* integer version of the signal */ + previous_is = encoder->guts->integer_signal_mid_side[i]; + current_is = (int32*)malloc(sizeof(int32) * new_size); + if(0 == current_is) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + ok = 0; + } + else { + encoder->guts->integer_signal_mid_side[i] = current_is; + if(previous_is != 0) + free(previous_is); + } + /* real version of the signal */ + previous_rs = encoder->guts->real_signal_mid_side[i]; + current_rs = (real*)malloc(sizeof(real) * new_size); + if(0 == current_rs) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + ok = 0; + } + else { + encoder->guts->real_signal_mid_side[i] = current_rs; + if(previous_rs != 0) + free(previous_rs); + } + } + } + if(ok) { + for(i = 0; i < 2; i++) { + residual = (int32*)malloc(sizeof(int32) * new_size); + if(0 == residual) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + ok = 0; + } + else { + if(encoder->guts->residual[i] != 0) + free(encoder->guts->residual[i]); + encoder->guts->residual[i] = residual; + } + } + } + if(ok) + encoder->guts->input_capacity = new_size; + + return ok; +} + +FLAC__Encoder *FLAC__encoder_get_new_instance() +{ + FLAC__Encoder *encoder = (FLAC__Encoder*)malloc(sizeof(FLAC__Encoder)); + if(encoder != 0) { + encoder->state = FLAC__ENCODER_UNINITIALIZED; + encoder->guts = 0; + } + return encoder; +} + +void FLAC__encoder_free_instance(FLAC__Encoder *encoder) +{ + assert(encoder != 0); + free(encoder); +} + +FLAC__EncoderState FLAC__encoder_init(FLAC__Encoder *encoder, FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data), void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data), void *client_data) +{ + unsigned i; + + assert(sizeof(int) >= 4); /* we want to die right away if this is not true */ + assert(encoder != 0); + assert(write_callback != 0); + assert(metadata_callback != 0); + assert(encoder->state == FLAC__ENCODER_UNINITIALIZED); + assert(encoder->guts == 0); + + encoder->state = FLAC__ENCODER_OK; + + if(encoder->channels == 0 || encoder->channels > FLAC__MAX_CHANNELS) + return encoder->state = FLAC__ENCODER_INVALID_NUMBER_OF_CHANNELS; + + if(encoder->do_mid_side_stereo && encoder->channels != 2) + return encoder->state = FLAC__ENCODER_MID_SIDE_CHANNELS_MISMATCH; + + if(encoder->do_mid_side_stereo && encoder->bits_per_sample > 16) + return encoder->state = FLAC__ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH; + + if(encoder->bits_per_sample == 0 || encoder->bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE) + return encoder->state = FLAC__ENCODER_INVALID_BITS_PER_SAMPLE; + + if(encoder->sample_rate == 0 || encoder->sample_rate > FLAC__MAX_SAMPLE_RATE) + return encoder->state = FLAC__ENCODER_INVALID_SAMPLE_RATE; + + if(encoder->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->blocksize > FLAC__MAX_BLOCK_SIZE) + return encoder->state = FLAC__ENCODER_INVALID_BLOCK_SIZE; + + if(encoder->blocksize < encoder->max_lpc_order) + return encoder->state = FLAC__ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER; + + if(encoder->qlp_coeff_precision == 0) { + if(encoder->bits_per_sample < 16) { + /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */ + /* @@@ until then we'll make a guess */ + encoder->qlp_coeff_precision = max(5, 2 + encoder->bits_per_sample / 2); + } + else if(encoder->bits_per_sample == 16) { + if(encoder->blocksize <= 192) + encoder->qlp_coeff_precision = 7; + else if(encoder->blocksize <= 384) + encoder->qlp_coeff_precision = 8; + else if(encoder->blocksize <= 576) + encoder->qlp_coeff_precision = 9; + else if(encoder->blocksize <= 1152) + encoder->qlp_coeff_precision = 10; + else if(encoder->blocksize <= 2304) + encoder->qlp_coeff_precision = 11; + else if(encoder->blocksize <= 4608) + encoder->qlp_coeff_precision = 12; + else + encoder->qlp_coeff_precision = 13; + } + else { + encoder->qlp_coeff_precision = min(13, 8*sizeof(int32) - encoder->bits_per_sample - 1); + } + } + else if(encoder->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->qlp_coeff_precision + encoder->bits_per_sample >= 8*sizeof(uint32)) + return encoder->state = FLAC__ENCODER_INVALID_QLP_COEFF_PRECISION; + + if(encoder->streamable_subset) { + if(encoder->bits_per_sample != 8 && encoder->bits_per_sample != 12 && encoder->bits_per_sample != 16 && encoder->bits_per_sample != 20 && encoder->bits_per_sample != 24) + return encoder->state = FLAC__ENCODER_NOT_STREAMABLE; + if(encoder->sample_rate > 655350) + return encoder->state = FLAC__ENCODER_NOT_STREAMABLE; + } + + if(encoder->rice_optimization_level >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + encoder->rice_optimization_level = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1; + + encoder->guts = (FLAC__EncoderPrivate*)malloc(sizeof(FLAC__EncoderPrivate)); + if(encoder->guts == 0) + return encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + + encoder->guts->input_capacity = 0; + for(i = 0; i < encoder->channels; i++) { + encoder->guts->integer_signal[i] = 0; + encoder->guts->real_signal[i] = 0; + } + for(i = 0; i < 2; i++) { + encoder->guts->integer_signal_mid_side[i] = 0; + encoder->guts->real_signal_mid_side[i] = 0; + } + encoder->guts->residual[0] = 0; + encoder->guts->residual[1] = 0; + encoder->guts->best_residual = 0; + encoder->guts->current_frame_can_do_mid_side = true; + encoder->guts->current_sample_number = 0; + encoder->guts->current_frame_number = 0; + + if(!encoder_resize_buffers_(encoder, encoder->blocksize)) { + /* the above function sets the state for us in case of an error */ + return encoder->state; + } + FLAC__bitbuffer_init(&encoder->guts->frame); + encoder->guts->write_callback = write_callback; + encoder->guts->metadata_callback = metadata_callback; + encoder->guts->client_data = client_data; + + /* + * write the stream header + */ + if(!FLAC__bitbuffer_clear(&encoder->guts->frame)) + return encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + + if(!FLAC__bitbuffer_write_raw_uint32(&encoder->guts->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) + return encoder->state = FLAC__ENCODER_FRAMING_ERROR; + + encoder->guts->metadata.type = FLAC__METADATA_TYPE_ENCODING; + encoder->guts->metadata.is_last = true; + encoder->guts->metadata.length = FLAC__STREAM_METADATA_ENCODING_LENGTH; + encoder->guts->metadata.data.encoding.min_blocksize = encoder->blocksize; /* this encoder uses the same blocksize for the whole stream */ + encoder->guts->metadata.data.encoding.max_blocksize = encoder->blocksize; + encoder->guts->metadata.data.encoding.min_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->guts->metadata.data.encoding.max_framesize = 0; /* we don't know this yet; have to fill it in later */ + encoder->guts->metadata.data.encoding.sample_rate = encoder->sample_rate; + encoder->guts->metadata.data.encoding.channels = encoder->channels; + encoder->guts->metadata.data.encoding.bits_per_sample = encoder->bits_per_sample; + encoder->guts->metadata.data.encoding.total_samples = 0; /* we don't know this yet; have to fill it in later */ + if(!FLAC__add_metadata_block(&encoder->guts->metadata, &encoder->guts->frame)) + return encoder->state = FLAC__ENCODER_FRAMING_ERROR; + + assert(encoder->guts->frame.bits == 0); /* assert that we're byte-aligned before writing */ + assert(encoder->guts->frame.total_consumed_bits == 0); /* assert that no reading of the buffer was done */ + if(encoder->guts->write_callback(encoder, encoder->guts->frame.buffer, encoder->guts->frame.bytes, 0, encoder->guts->current_frame_number, encoder->guts->client_data) != FLAC__ENCODER_WRITE_OK) + return encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_WRITING; + + /* now that the metadata block is written, we can init this to an absurdly-high value */ + encoder->guts->metadata.data.encoding.min_framesize = (1u << FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN) - 1; + + return encoder->state; +} + +void FLAC__encoder_finish(FLAC__Encoder *encoder) +{ + unsigned i; + + assert(encoder != 0); + if(encoder->state == FLAC__ENCODER_UNINITIALIZED) + return; + if(encoder->guts->current_sample_number != 0) { + encoder->blocksize = encoder->guts->current_sample_number; + encoder_process_frame_(encoder, true); /* true => is last frame */ + } + encoder->guts->metadata_callback(encoder, &encoder->guts->metadata, encoder->guts->client_data); + if(encoder->guts != 0) { + for(i = 0; i < encoder->channels; i++) { + if(encoder->guts->integer_signal[i] != 0) { + free(encoder->guts->integer_signal[i]); + encoder->guts->integer_signal[i] = 0; + } + if(encoder->guts->real_signal[i] != 0) { + free(encoder->guts->real_signal[i]); + encoder->guts->real_signal[i] = 0; + } + } + for(i = 0; i < 2; i++) { + if(encoder->guts->integer_signal_mid_side[i] != 0) { + free(encoder->guts->integer_signal_mid_side[i]); + encoder->guts->integer_signal_mid_side[i] = 0; + } + if(encoder->guts->real_signal_mid_side[i] != 0) { + free(encoder->guts->real_signal_mid_side[i]); + encoder->guts->real_signal_mid_side[i] = 0; + } + } + for(i = 0; i < 2; i++) { + if(encoder->guts->residual[i] != 0) { + free(encoder->guts->residual[i]); + encoder->guts->residual[i] = 0; + } + } + FLAC__bitbuffer_free(&encoder->guts->frame); + free(encoder->guts); + encoder->guts = 0; + } + encoder->state = FLAC__ENCODER_UNINITIALIZED; +} + +bool FLAC__encoder_process(FLAC__Encoder *encoder, const int32 *buf[], unsigned samples) +{ + unsigned i, j, channel; + int32 x, mid, side; + const bool ms = encoder->do_mid_side_stereo && encoder->channels == 2; + const int32 min_side = -((int64)1 << (encoder->bits_per_sample-1)); + const int32 max_side = ((int64)1 << (encoder->bits_per_sample-1)) - 1; + + assert(encoder != 0); + assert(encoder->state == FLAC__ENCODER_OK); + + j = 0; + do { + for(i = encoder->guts->current_sample_number; i < encoder->blocksize && j < samples; i++, j++) { + for(channel = 0; channel < encoder->channels; channel++) { + x = buf[channel][j]; + encoder->guts->integer_signal[channel][i] = x; + encoder->guts->real_signal[channel][i] = (real)x; + } + if(ms && encoder->guts->current_frame_can_do_mid_side) { + side = buf[0][j] - buf[1][j]; + if(side < min_side || side > max_side) { + encoder->guts->current_frame_can_do_mid_side = false; + } + else { + mid = (buf[0][j] + buf[1][j]) >> 1; /* NOTE: not the same as divide-by-two ! */ + encoder->guts->integer_signal_mid_side[0][i] = mid; + encoder->guts->integer_signal_mid_side[1][i] = side; + encoder->guts->real_signal_mid_side[0][i] = (real)mid; + encoder->guts->real_signal_mid_side[1][i] = (real)side; + } + } + encoder->guts->current_sample_number++; + } + if(i == encoder->blocksize) { + if(!encoder_process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + + return true; +} + +/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */ +bool FLAC__encoder_process_interleaved(FLAC__Encoder *encoder, const int32 buf[], unsigned samples) +{ + unsigned i, j, k, channel; + int32 x, left = 0, mid, side; + const bool ms = encoder->do_mid_side_stereo && encoder->channels == 2; + const int32 min_side = -((int64)1 << (encoder->bits_per_sample-1)); + const int32 max_side = ((int64)1 << (encoder->bits_per_sample-1)) - 1; + + assert(encoder != 0); + assert(encoder->state == FLAC__ENCODER_OK); + + j = k = 0; + do { + for(i = encoder->guts->current_sample_number; i < encoder->blocksize && j < samples; i++, j++, k++) { + for(channel = 0; channel < encoder->channels; channel++, k++) { + x = buf[k]; + encoder->guts->integer_signal[channel][i] = x; + encoder->guts->real_signal[channel][i] = (real)x; + if(ms && encoder->guts->current_frame_can_do_mid_side) { + if(channel == 0) { + left = x; + } + else { + side = left - x; + if(side < min_side || side > max_side) { + encoder->guts->current_frame_can_do_mid_side = false; + } + else { + mid = (left + x) >> 1; /* NOTE: not the same as divide-by-two ! */ + encoder->guts->integer_signal_mid_side[0][i] = mid; + encoder->guts->integer_signal_mid_side[1][i] = side; + encoder->guts->real_signal_mid_side[0][i] = (real)mid; + encoder->guts->real_signal_mid_side[1][i] = (real)side; + } + } + } + } + encoder->guts->current_sample_number++; + } + if(i == encoder->blocksize) { + if(!encoder_process_frame_(encoder, false)) /* false => not last frame */ + return false; + } + } while(j < samples); + + return true; +} + +bool encoder_process_frame_(FLAC__Encoder *encoder, bool is_last_frame) +{ + FLAC__FrameHeader frame_header; + FLAC__BitBuffer *smallest_frame; + + assert(encoder->state == FLAC__ENCODER_OK); + + /* + * First do a normal encoding pass + */ + frame_header.blocksize = encoder->blocksize; + frame_header.sample_rate = encoder->sample_rate; + frame_header.channels = encoder->channels; + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */ + frame_header.bits_per_sample = encoder->bits_per_sample; + frame_header.number.frame_number = encoder->guts->current_frame_number; + + if(!FLAC__bitbuffer_clear(&encoder->guts->frame)) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame)) { + encoder->state = FLAC__ENCODER_FRAMING_ERROR; + return false; + } + + if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, encoder->guts->integer_signal, encoder->guts->real_signal, &encoder->guts->frame)) + return false; + + smallest_frame = &encoder->guts->frame; + + /* + * Now try a mid-side version if necessary; otherwise, just use the previous step's frame + */ + if(encoder->do_mid_side_stereo && encoder->guts->current_frame_can_do_mid_side) { + int32 *integer_signal[2]; + real *real_signal[2]; + + assert(encoder->channels == 2); + + /* mid-side */ + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; + if(!FLAC__bitbuffer_clear(&encoder->guts->frame_mid_side)) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_mid_side)) { + encoder->state = FLAC__ENCODER_FRAMING_ERROR; + return false; + } + integer_signal[0] = encoder->guts->integer_signal_mid_side[0]; /* mid channel */ + integer_signal[1] = encoder->guts->integer_signal_mid_side[1]; /* side channel */ + real_signal[0] = encoder->guts->real_signal_mid_side[0]; /* mid channel */ + real_signal[1] = encoder->guts->real_signal_mid_side[1]; /* side channel */ + if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_mid_side)) + return false; + if(encoder->guts->frame_mid_side.total_bits < smallest_frame->total_bits) + smallest_frame = &encoder->guts->frame_mid_side; + + /* left-side */ + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; + if(!FLAC__bitbuffer_clear(&encoder->guts->frame_left_side)) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_left_side)) { + encoder->state = FLAC__ENCODER_FRAMING_ERROR; + return false; + } + integer_signal[0] = encoder->guts->integer_signal[0]; /* left channel */ + integer_signal[1] = encoder->guts->integer_signal_mid_side[1]; /* side channel */ + real_signal[0] = encoder->guts->real_signal[0]; /* left channel */ + real_signal[1] = encoder->guts->real_signal_mid_side[1]; /* side channel */ + if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_left_side)) + return false; + if(encoder->guts->frame_left_side.total_bits < smallest_frame->total_bits) + smallest_frame = &encoder->guts->frame_left_side; + + /* right-side */ + frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; + if(!FLAC__bitbuffer_clear(&encoder->guts->frame_right_side)) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_right_side)) { + encoder->state = FLAC__ENCODER_FRAMING_ERROR; + return false; + } + integer_signal[0] = encoder->guts->integer_signal_mid_side[1]; /* side channel */ + integer_signal[1] = encoder->guts->integer_signal[1]; /* right channel */ + real_signal[0] = encoder->guts->real_signal_mid_side[1]; /* side channel */ + real_signal[1] = encoder->guts->real_signal[1]; /* right channel */ + if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_right_side)) + return false; + if(encoder->guts->frame_right_side.total_bits < smallest_frame->total_bits) + smallest_frame = &encoder->guts->frame_right_side; + } + + /* + * Zero-pad the frame to a byte_boundary + */ + if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(smallest_frame)) { + encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + /* + * Write it + */ + assert(smallest_frame->bits == 0); /* assert that we're byte-aligned before writing */ + assert(smallest_frame->total_consumed_bits == 0); /* assert that no reading of the buffer was done */ + if(encoder->guts->write_callback(encoder, smallest_frame->buffer, smallest_frame->bytes, encoder->blocksize, encoder->guts->current_frame_number, encoder->guts->client_data) != FLAC__ENCODER_WRITE_OK) { + encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_WRITING; + return false; + } + + /* + * Get ready for the next frame + */ + encoder->guts->current_frame_can_do_mid_side = true; + encoder->guts->current_sample_number = 0; + encoder->guts->current_frame_number++; + encoder->guts->metadata.data.encoding.total_samples += (uint64)encoder->blocksize; + encoder->guts->metadata.data.encoding.min_framesize = min(smallest_frame->bytes, encoder->guts->metadata.data.encoding.min_framesize); + encoder->guts->metadata.data.encoding.max_framesize = max(smallest_frame->bytes, encoder->guts->metadata.data.encoding.max_framesize); + + return true; +} + +bool encoder_process_subframes_(FLAC__Encoder *encoder, bool is_last_frame, const FLAC__FrameHeader *frame_header, unsigned channels, const int32 *integer_signal[], const real *real_signal[], FLAC__BitBuffer *frame) +{ + real fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]; + real lpc_residual_bits_per_sample; + real autoc[FLAC__MAX_LPC_ORDER+1]; + real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; + real lpc_error[FLAC__MAX_LPC_ORDER]; + unsigned channel; + unsigned min_lpc_order, max_lpc_order, lpc_order; + unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order; + unsigned max_partition_order; + unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision; + unsigned rice_parameter; + unsigned candidate_bits, best_bits; + + if(is_last_frame) { + max_partition_order = 0; + } + else { + unsigned limit = 0, b = encoder->blocksize; + while(!(b & 1)) { + limit++; + b >>= 1; + } + max_partition_order = min(encoder->rice_optimization_level, limit); + } + + for(channel = 0; channel < channels; channel++) { + /* verbatim subframe is the baseline against which we measure other compressed subframes */ + best_bits = encoder_evaluate_verbatim_subframe_(frame_header->blocksize, frame_header->bits_per_sample, &(encoder->guts->best_subframe)); + + if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) { + /* check for constant subframe */ + guess_fixed_order = FLAC__fixed_compute_best_predictor(integer_signal[channel]+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample); + if(fixed_residual_bits_per_sample[1] == 0.0) { + candidate_bits = encoder_evaluate_constant_subframe_(integer_signal[channel][0], frame_header->bits_per_sample, &(encoder->guts->candidate_subframe)); + if(candidate_bits < best_bits) { + encoder_promote_candidate_subframe_(encoder); + best_bits = candidate_bits; + } + } + else { + /* encode fixed */ + if(encoder->do_exhaustive_model_search) { + min_fixed_order = 0; + max_fixed_order = FLAC__MAX_FIXED_ORDER; + } + else { + min_fixed_order = max_fixed_order = guess_fixed_order; + } + for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) { + if(fixed_residual_bits_per_sample[fixed_order] >= (real)frame_header->bits_per_sample) + continue; /* don't even try */ + rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; + if(rice_parameter >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) + rice_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1; + candidate_bits = encoder_evaluate_fixed_subframe_(integer_signal[channel], encoder->guts->residual[!encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, fixed_order, rice_parameter, max_partition_order, &(encoder->guts->candidate_subframe)); + if(candidate_bits < best_bits) { + encoder_promote_candidate_subframe_(encoder); + best_bits = candidate_bits; + } + } + + /* encode lpc */ + if(encoder->max_lpc_order > 0) { + if(encoder->max_lpc_order >= frame_header->blocksize) + max_lpc_order = frame_header->blocksize-1; + else + max_lpc_order = encoder->max_lpc_order; + if(max_lpc_order > 0) { + FLAC__lpc_compute_autocorrelation(real_signal[channel], frame_header->blocksize, max_lpc_order+1, autoc); + FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, lp_coeff, lpc_error); + if(encoder->do_exhaustive_model_search) { + min_lpc_order = 1; + } + else { + unsigned guess_lpc_order = FLAC__lpc_compute_best_order(lpc_error, max_lpc_order, frame_header->blocksize, frame_header->bits_per_sample); + min_lpc_order = max_lpc_order = guess_lpc_order; + } + if(encoder->do_qlp_coeff_prec_search) { + min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; + max_qlp_coeff_precision = 32 - frame_header->bits_per_sample - 1; + } + else { + min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->qlp_coeff_precision; + } + for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { + lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize); + if(lpc_residual_bits_per_sample >= (real)frame_header->bits_per_sample) + continue; /* don't even try */ + rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; + if(rice_parameter >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) + rice_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1; + for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { + candidate_bits = encoder_evaluate_lpc_subframe_(integer_signal[channel], encoder->guts->residual[!encoder->guts->best_residual], lp_coeff[lpc_order-1], frame_header->blocksize, frame_header->bits_per_sample, lpc_order, qlp_coeff_precision, rice_parameter, max_partition_order, &(encoder->guts->candidate_subframe)); + if(candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ + if(candidate_bits < best_bits) { + encoder_promote_candidate_subframe_(encoder); + best_bits = candidate_bits; + } + } + } + } + } + } + } + } + + /* add the best subframe */ + switch(encoder->guts->best_subframe.type) { + case FLAC__SUBFRAME_TYPE_CONSTANT: + if(!encoder_generate_constant_subframe_(&(encoder->guts->best_subframe), frame_header->bits_per_sample, frame)) { + encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_FIXED: + if(!encoder_generate_fixed_subframe_(&(encoder->guts->best_subframe), encoder->guts->residual[encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, frame)) { + encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_LPC: + if(!encoder_generate_lpc_subframe_(&(encoder->guts->best_subframe), encoder->guts->residual[encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, frame)) { + encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING; + return false; + } + break; + case FLAC__SUBFRAME_TYPE_VERBATIM: + if(!encoder_generate_verbatim_subframe_(&(encoder->guts->best_subframe), integer_signal[channel], frame_header->blocksize, frame_header->bits_per_sample, frame)) { + encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING; + return false; + } + break; + } + } + + return true; +} + +unsigned encoder_evaluate_constant_subframe_(const int32 signal, unsigned bits_per_sample, FLAC__SubframeHeader *subframe) +{ + subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT; + subframe->data.constant.value = signal; + + return 8 + bits_per_sample; +} + +unsigned encoder_evaluate_fixed_subframe_(const int32 signal[], int32 residual[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe) +{ + unsigned i, residual_bits; + const unsigned residual_samples = blocksize - order; + + FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_FIXED; + + subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + + residual_bits = encoder_find_best_partition_order_(residual, residual_samples, order, rice_parameter, max_partition_order, &subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters); + + subframe->data.fixed.order = order; + for(i = 0; i < order; i++) + subframe->data.fixed.warmup[i] = signal[i]; + + return 8 + (order * bits_per_sample) + residual_bits; +} + +unsigned encoder_evaluate_lpc_subframe_(const int32 signal[], int32 residual[], const real lp_coeff[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe) +{ + int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; + unsigned i, residual_bits; + int quantization, ret; + const unsigned residual_samples = blocksize - order; + + ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, bits_per_sample, qlp_coeff, &quantization); + if(ret != 0) + return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */ + + FLAC__lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual); + + subframe->type = FLAC__SUBFRAME_TYPE_LPC; + + subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE; + + residual_bits = encoder_find_best_partition_order_(residual, residual_samples, order, rice_parameter, max_partition_order, &subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.parameters); + + subframe->data.lpc.order = order; + subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision; + subframe->data.lpc.quantization_level = quantization; + memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(int32)*FLAC__MAX_LPC_ORDER); + for(i = 0; i < order; i++) + subframe->data.lpc.warmup[i] = signal[i]; + + return 8 + 9 + (order * (qlp_coeff_precision + bits_per_sample)) + residual_bits; +} + +unsigned encoder_evaluate_verbatim_subframe_(unsigned blocksize, unsigned bits_per_sample, FLAC__SubframeHeader *subframe) +{ + subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM; + + return 8 + (blocksize * bits_per_sample); +} + +unsigned encoder_find_best_partition_order_(int32 residual[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, unsigned max_partition_order, unsigned *best_partition_order, unsigned best_parameters[]) +{ + unsigned residual_bits, best_residual_bits = 0; + unsigned partition_order; + unsigned best_parameters_index = 0, parameters[2][1 << FLAC__MAX_RICE_PARTITION_ORDER]; + + for(partition_order = 0; partition_order <= max_partition_order; partition_order++) { + if(!encoder_set_partitioned_rice_(residual, residual_samples, predictor_order, rice_parameter, partition_order, parameters[!best_parameters_index], &residual_bits)) { + assert(best_residual_bits != 0); + break; + } + if(best_residual_bits == 0 || residual_bits < best_residual_bits) { + best_residual_bits = residual_bits; + *best_partition_order = partition_order; + best_parameters_index = !best_parameters_index; + } + } + memcpy(best_parameters, parameters[best_parameters_index], sizeof(unsigned)*(1<<(*best_partition_order))); + + return best_residual_bits; +} + +bool encoder_generate_constant_subframe_(const FLAC__SubframeHeader *header, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer) +{ + assert(header->type == FLAC__SUBFRAME_TYPE_CONSTANT); + return FLAC__subframe_add_constant(bits_per_sample, header, bitbuffer); +} + +bool encoder_generate_fixed_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer) +{ + assert(header->type == FLAC__SUBFRAME_TYPE_FIXED); + return FLAC__subframe_add_fixed(residual, blocksize - header->data.fixed.order, bits_per_sample, header, bitbuffer); +} + +bool encoder_generate_lpc_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer) +{ + assert(header->type == FLAC__SUBFRAME_TYPE_LPC); + return FLAC__subframe_add_lpc(residual, blocksize - header->data.lpc.order, bits_per_sample, header, bitbuffer); +} + +bool encoder_generate_verbatim_subframe_(const FLAC__SubframeHeader *header, const int32 signal[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer) +{ + assert(header->type == FLAC__SUBFRAME_TYPE_VERBATIM); +#ifdef NDEBUG + (void)header; /* silence compiler warning about unused parameter */ +#endif + return FLAC__subframe_add_verbatim(signal, blocksize, bits_per_sample, bitbuffer); +} + +void encoder_promote_candidate_subframe_(FLAC__Encoder *encoder) +{ + assert(encoder->state == FLAC__ENCODER_OK); + encoder->guts->best_subframe = encoder->guts->candidate_subframe; + encoder->guts->best_residual = !encoder->guts->best_residual; +} + +bool encoder_set_partitioned_rice_(const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameter, const unsigned partition_order, unsigned parameters[], unsigned *bits) +{ + unsigned bits_ = 2 + 3; + + if(partition_order == 0) { + unsigned i; + parameters[0] = rice_parameter; + bits_ += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + for(i = 0; i < residual_samples; i++) + bits_ += RICE_BITS(residual[i], rice_parameter); + } + else { + unsigned i, j, k = 0, k_last = 0, z; + unsigned mean; + unsigned parameter, partition_samples; + const unsigned max_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1; + for(i = 0; i < (1u<<partition_order); i++) { + partition_samples = (residual_samples+predictor_order) >> partition_order; + if(i == 0) { + if(partition_samples <= predictor_order) + return false; + else + partition_samples -= predictor_order; + } + mean = partition_samples >> 1; + for(j = 0; j < partition_samples; j++, k++) + mean += ((residual[k] < 0)? (unsigned)(-residual[k]) : (unsigned)residual[k]); + mean /= partition_samples; + z = 0x80000000; + for(j = 0; j < 32; j++, z >>= 1) + if(mean & z) + break; + parameter = j > 31? 0 : 32 - j - 1; + if(parameter > max_parameter) + parameter = max_parameter; + parameters[i] = parameter; + bits_ += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; + for(j = k_last; j < k; j++) + bits_ += RICE_BITS(residual[j], parameter); + k_last = k; + } + } + + *bits = bits_; + return true; +} diff --git a/src/libFLAC/encoder_framing.c b/src/libFLAC/encoder_framing.c new file mode 100644 index 00000000..69201d75 --- /dev/null +++ b/src/libFLAC/encoder_framing.c @@ -0,0 +1,340 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdio.h> +#include "private/encoder_framing.h" +#include "private/crc.h" + +#ifdef max +#undef max +#endif +#define max(x,y) ((x)>(y)?(x):(y)) + +static bool subframe_add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method); +static bool subframe_add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned partition_order); + +bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuffer *bb) +{ + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) + return false; + + assert(metadata->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->length, FLAC__STREAM_METADATA_LENGTH_LEN)) + return false; + + switch(metadata->type) { + case FLAC__METADATA_TYPE_ENCODING: + assert(metadata->data.encoding.min_blocksize < (1u << FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.min_blocksize, FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN)) + return false; + assert(metadata->data.encoding.max_blocksize < (1u << FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.max_blocksize, FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN)) + return false; + assert(metadata->data.encoding.min_framesize < (1u << FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.min_framesize, FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN)) + return false; + assert(metadata->data.encoding.max_framesize < (1u << FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.max_framesize, FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN)) + return false; + assert(metadata->data.encoding.sample_rate > 0); + assert(metadata->data.encoding.sample_rate < (1u << FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.sample_rate, FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN)) + return false; + assert(metadata->data.encoding.channels > 0); + assert(metadata->data.encoding.channels <= (1u << FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.channels-1, FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN)) + return false; + assert(metadata->data.encoding.bits_per_sample > 0); + assert(metadata->data.encoding.bits_per_sample <= (1u << FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN)); + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.bits_per_sample-1, FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN)) + return false; + if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.encoding.total_samples, FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN)) + return false; + break; + default: + assert(0); + } + + return true; +} + +bool FLAC__frame_add_header(const FLAC__FrameHeader *header, bool streamable_subset, bool is_last_block, FLAC__BitBuffer *bb) +{ + unsigned u, crc_start, blocksize_hint, sample_rate_hint; + byte crc; + + assert(bb->bits == 0); /* assert that we're byte-aligned before writing */ + + crc_start = bb->bytes; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) + return false; + + assert(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); + blocksize_hint = 0; + switch(header->blocksize) { + case 192: u = 1; break; + case 576: u = 2; break; + case 1152: u = 3; break; + case 2304: u = 4; break; + case 4608: u = 5; break; + default: + if(streamable_subset || is_last_block) { + if(header->blocksize <= 0x100) + blocksize_hint = u = 6; + else + blocksize_hint = u = 7; + } + else + u = 0; + break; + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) + return false; + + assert(header->sample_rate > 0 && header->sample_rate < (1u << FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN)); + sample_rate_hint = 0; + switch(header->sample_rate) { + case 8000: u = 4; break; + case 16000: u = 5; break; + case 22050: u = 6; break; + case 24000: u = 7; break; + case 32000: u = 8; break; + case 44100: u = 9; break; + case 48000: u = 10; break; + case 96000: u = 11; break; + default: + if(streamable_subset) { + if(header->sample_rate % 1000 == 0) + sample_rate_hint = u = 12; + else if(header->sample_rate % 10 == 0) + sample_rate_hint = u = 14; + else + sample_rate_hint = u = 13; + } + else + u = 0; + break; + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) + return false; + + assert(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); + switch(header->channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + u = header->channels - 1; + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + assert(header->channels == 2); + u = 8; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + assert(header->channels == 2); + u = 9; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + assert(header->channels == 2); + u = 10; + break; + default: + assert(0); + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) + return false; + + assert(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN)); + switch(header->bits_per_sample) { + case 8 : u = 1; break; + case 12: u = 2; break; + case 16: u = 4; break; + case 20: u = 5; break; + case 24: u = 6; break; + default: u = 0; break; + } + if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) + return false; + + if(!FLAC__bitbuffer_write_utf8_uint32(bb, header->number.frame_number)) + return false; + + if(blocksize_hint) + if(!FLAC__bitbuffer_write_raw_uint32(bb, header->blocksize-1, (blocksize_hint==6)? 8:16)) + return false; + + switch(sample_rate_hint) { + case 12: + if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 1000, 8)) + return false; + break; + case 13: + if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate, 16)) + return false; + break; + case 14: + if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 10, 16)) + return false; + break; + } + + /* write the CRC */ + assert(bb->buffer[crc_start] == 0xff); /* MAGIC NUMBER for the first byte of the sync code */ + assert(bb->bits == 0); /* assert that we're byte-aligned */ + crc = FLAC__crc8(bb->buffer+crc_start, bb->bytes-crc_start); + if(!FLAC__bitbuffer_write_raw_uint32(bb, crc, FLAC__FRAME_HEADER_CRC8_LEN)) + return false; + + return true; +} + +bool FLAC__subframe_add_constant(unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb) +{ + bool ok; + + ok = + FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_CONSTANT, FLAC__SUBFRAME_HEADER_TYPE_LEN) && + FLAC__bitbuffer_write_raw_int32(bb, subframe->data.constant.value, bits_per_sample) + ; + + return ok; +} + +bool FLAC__subframe_add_fixed(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb) +{ + unsigned i; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_FIXED | (subframe->data.fixed.order<<1), FLAC__SUBFRAME_HEADER_TYPE_LEN)) + return false; + + for(i = 0; i < subframe->data.fixed.order; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.fixed.warmup[i], bits_per_sample)) + return false; + + if(!subframe_add_entropy_coding_method_(bb, &subframe->data.fixed.entropy_coding_method)) + return false; + switch(subframe->data.fixed.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!subframe_add_residual_partitioned_rice_(bb, residual, residual_samples, subframe->data.fixed.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order)) + return false; + break; + default: + assert(0); + } + + return true; +} + +bool FLAC__subframe_add_lpc(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb) +{ + unsigned i; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_LPC | ((subframe->data.lpc.order-1)<<1), FLAC__SUBFRAME_HEADER_TYPE_LEN)) + return false; + + for(i = 0; i < subframe->data.lpc.order; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.warmup[i], bits_per_sample)) + return false; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, subframe->data.lpc.qlp_coeff_precision-1, FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN)) + return false; + if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.quantization_level, FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN)) + return false; + for(i = 0; i < subframe->data.lpc.order; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.qlp_coeff[i], subframe->data.lpc.qlp_coeff_precision)) + return false; + + if(!subframe_add_entropy_coding_method_(bb, &subframe->data.lpc.entropy_coding_method)) + return false; + switch(subframe->data.lpc.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!subframe_add_residual_partitioned_rice_(bb, residual, residual_samples, subframe->data.lpc.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order)) + return false; + break; + default: + assert(0); + } + + return true; +} + +bool FLAC__subframe_add_verbatim(const int32 signal[], unsigned samples, unsigned bits_per_sample, FLAC__BitBuffer *bb) +{ + unsigned i; + + if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_VERBATIM, FLAC__SUBFRAME_HEADER_TYPE_LEN)) + return false; + + for(i = 0; i < samples; i++) + if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], bits_per_sample)) + return false; + + return true; +} + +bool subframe_add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method) +{ + if(!FLAC__bitbuffer_write_raw_uint32(bb, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) + return false; + switch(method->type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!FLAC__bitbuffer_write_raw_uint32(bb, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) + return false; + break; + default: + assert(0); + } + return true; +} + +bool subframe_add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned partition_order) +{ + if(partition_order == 0) { + unsigned i; + if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) + return false; + for(i = 0; i < residual_samples; i++) { + if(!FLAC__bitbuffer_write_rice_signed(bb, residual[i], rice_parameters[0])) + return false; + } + return true; + } + else { + unsigned i, j, k = 0, k_last = 0; + unsigned partition_samples; + for(i = 0; i < (1u<<partition_order); i++) { + if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)) + return false; + partition_samples = (residual_samples+predictor_order) >> partition_order; + if(i == 0) + partition_samples -= predictor_order; + k += partition_samples; + for(j = k_last; j < k; j++) + if(!FLAC__bitbuffer_write_rice_signed(bb, residual[j], rice_parameters[i])) + return false; + k_last = k; + } + return true; + } +} diff --git a/src/libFLAC/file_decoder.c b/src/libFLAC/file_decoder.c new file mode 100644 index 00000000..aed796c5 --- /dev/null +++ b/src/libFLAC/file_decoder.c @@ -0,0 +1,403 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for strcmp() */ +#include "FLAC/file_decoder.h" +#include "protected/stream_decoder.h" + +typedef struct FLAC__FileDecoderPrivate { + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); + void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); + void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + void *client_data; + FILE *file; + FLAC__StreamDecoder *stream; + /* the rest of these are only used for seeking: */ + FLAC__StreamMetaData_Encoding metadata; /* we keep this around so we can figure out how to seek quickly */ + FLAC__FrameHeader last_frame_header; /* holds the info of the last frame we seeked to */ + uint64 target_sample; +} FLAC__FileDecoderPrivate; + +static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample); + +FLAC__FileDecoder *FLAC__file_decoder_get_new_instance() +{ + FLAC__FileDecoder *decoder = (FLAC__FileDecoder*)malloc(sizeof(FLAC__FileDecoder)); + if(decoder != 0) { + decoder->state = FLAC__FILE_DECODER_UNINITIALIZED; + decoder->guts = 0; + } + return decoder; +} + +void FLAC__file_decoder_free_instance(FLAC__FileDecoder *decoder) +{ + free(decoder); +} + +FLAC__FileDecoderState FLAC__file_decoder_init( + FLAC__FileDecoder *decoder, + const char *filename, + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data), + void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data), + void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data), + void *client_data +) +{ + assert(sizeof(int) >= 4); /* we want to die right away if this is not true */ + assert(decoder != 0); + assert(write_callback != 0); + assert(metadata_callback != 0); + assert(error_callback != 0); + assert(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED); + assert(decoder->guts == 0); + + decoder->state = FLAC__FILE_DECODER_OK; + + decoder->guts = (FLAC__FileDecoderPrivate*)malloc(sizeof(FLAC__FileDecoderPrivate)); + if(decoder->guts == 0) + return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; + + decoder->guts->write_callback = write_callback; + decoder->guts->metadata_callback = metadata_callback; + decoder->guts->error_callback = error_callback; + decoder->guts->client_data = client_data; + decoder->guts->stream = 0; + + if(0 == strcmp(filename, "-")) + decoder->guts->file = stdin; + else + decoder->guts->file = fopen(filename, "rb"); + if(decoder->guts->file == 0) + return decoder->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE; + + decoder->guts->stream = FLAC__stream_decoder_get_new_instance(); + if(FLAC__stream_decoder_init(decoder->guts->stream, read_callback_, write_callback_, metadata_callback_, error_callback_, decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) + return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; /* this is based on internal knowledge of FLAC__stream_decoder_init() */ + + return decoder->state; +} + +void FLAC__file_decoder_finish(FLAC__FileDecoder *decoder) +{ + assert(decoder != 0); + if(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED) + return; + if(decoder->guts != 0) { + if(decoder->guts->file != 0 && decoder->guts->file != stdin) + fclose(decoder->guts->file); + if(decoder->guts->stream != 0) { + FLAC__stream_decoder_finish(decoder->guts->stream); + FLAC__stream_decoder_free_instance(decoder->guts->stream); + } + free(decoder->guts); + decoder->guts = 0; + } + decoder->state = FLAC__FILE_DECODER_UNINITIALIZED; +} + +bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder) +{ + bool ret; + assert(decoder != 0); + + if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + assert(decoder->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__stream_decoder_process_whole_stream(decoder->guts->stream); + if(!ret) + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + + return ret; +} + +bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder) +{ + bool ret; + assert(decoder != 0); + + if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + assert(decoder->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__stream_decoder_process_metadata(decoder->guts->stream); + if(!ret) + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + + return ret; +} + +bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder) +{ + bool ret; + assert(decoder != 0); + + if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + assert(decoder->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__stream_decoder_process_one_frame(decoder->guts->stream); + if(!ret) + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + + return ret; +} + +bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder) +{ + bool ret; + assert(decoder != 0); + + if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + assert(decoder->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__stream_decoder_process_remaining_frames(decoder->guts->stream); + if(!ret) + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + + return ret; +} + +bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, uint64 sample) +{ + long filesize; + + assert(decoder != 0); + assert(decoder->state == FLAC__FILE_DECODER_OK); + + decoder->state = FLAC__FILE_DECODER_SEEKING; + + if(!FLAC__stream_decoder_reset(decoder->guts->stream)) { + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + return false; + } + /* get the file length */ + if(0 != fseek(decoder->guts->file, 0, SEEK_END)) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + fflush(decoder->guts->file); + if(-1 == (filesize = ftell(decoder->guts->file))) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + /* rewind */ + if(0 != fseek(decoder->guts->file, 0, SEEK_SET)) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_process_metadata(decoder->guts->stream)) { + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + return false; + } + if(sample > decoder->guts->metadata.total_samples) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + + return seek_to_absolute_sample_(decoder, filesize, sample); +} + +FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + if(feof(file_decoder->guts->file)) { + file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE; + return FLAC__STREAM_DECODER_READ_END_OF_STREAM; + } + else if(*bytes > 0) { + size_t bytes_read = fread(buffer, sizeof(byte), *bytes, file_decoder->guts->file); + if(bytes_read == 0) { + if(feof(file_decoder->guts->file)) { + file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE; + return FLAC__STREAM_DECODER_READ_END_OF_STREAM; + } + else + return FLAC__STREAM_DECODER_READ_ABORT; + } + else { + *bytes = (unsigned)bytes_read; + return FLAC__STREAM_DECODER_READ_CONTINUE; + } + } + else + return FLAC__STREAM_DECODER_READ_ABORT; /* abort to avoid a deadlock */ +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + if(file_decoder->state == FLAC__FILE_DECODER_SEEKING) { + uint64 this_frame_sample = header->number.sample_number; + uint64 next_frame_sample = this_frame_sample + (uint64)header->blocksize; + uint64 target_sample = file_decoder->guts->target_sample; + + file_decoder->guts->last_frame_header = *header; /* save the header in the guts */ + if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ + unsigned delta = (unsigned)(target_sample - this_frame_sample); + /* kick out of seek mode */ + file_decoder->state = FLAC__FILE_DECODER_OK; + /* shift out the samples before target_sample */ + if(delta > 0) { + unsigned channel; + const int32 *newbuffer[FLAC__MAX_CHANNELS]; + for(channel = 0; channel < header->channels; channel++) + newbuffer[channel] = buffer[channel] + delta; + file_decoder->guts->last_frame_header.blocksize -= delta; + file_decoder->guts->last_frame_header.number.sample_number += (uint64)delta; + /* write the relevant samples */ + return file_decoder->guts->write_callback(file_decoder, &file_decoder->guts->last_frame_header, newbuffer, file_decoder->guts->client_data); + } + else { + /* write the relevant samples */ + return file_decoder->guts->write_callback(file_decoder, header, buffer, file_decoder->guts->client_data); + } + } + else { + return FLAC__STREAM_DECODER_WRITE_CONTINUE; + } + } + else { + return file_decoder->guts->write_callback(file_decoder, header, buffer, file_decoder->guts->client_data); + } +} + +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + if(metadata->type == FLAC__METADATA_TYPE_ENCODING) + file_decoder->guts->metadata = metadata->data.encoding; + if(file_decoder->state != FLAC__FILE_DECODER_SEEKING) + file_decoder->guts->metadata_callback(file_decoder, metadata, file_decoder->guts->client_data); +} + +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + if(file_decoder->state != FLAC__FILE_DECODER_SEEKING) + file_decoder->guts->error_callback(file_decoder, status, file_decoder->guts->client_data); +} + +bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample) +{ + long l, r, pos, last_pos = -1; + unsigned approx_bytes_per_frame; + uint64 last_frame_sample = 0xffffffffffffffff; + bool needs_seek; + const bool is_variable_blocksize_stream = (decoder->guts->metadata.min_blocksize != decoder->guts->metadata.max_blocksize); + + if(!is_variable_blocksize_stream) { + /* we are just guessing here, but we want to guess high, not low */ + /* note there are no () around 'decoder->guts->metadata.bits_per_sample/8' to keep precision up since it's an integer calulation */ + approx_bytes_per_frame = decoder->guts->metadata.min_blocksize * decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample/8 + 64; + } + else + approx_bytes_per_frame = 1152 * decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample/8 + 64; + + /* Now we need to use the metadata and the filelength to search to the frame with the correct sample */ + if(-1 == (l = ftell(decoder->guts->file))) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + l -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream); +#ifdef _MSC_VER + /* with VC++ you have to spoon feed it the casting */ + pos = l + (long)((double)(int64)target_sample / (double)(int64)decoder->guts->metadata.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame; +#else + pos = l + (long)((double)target_sample / (double)decoder->guts->metadata.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame; +#endif + r = filesize - ((decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample * FLAC__MAX_BLOCK_SIZE) / 8 + 64); + if(pos >= r) + pos = r-1; + if(pos < l) + pos = l; + needs_seek = true; + + decoder->guts->target_sample = target_sample; + while(1) { + if(needs_seek) { + if(-1 == fseek(decoder->guts->file, pos, SEEK_SET)) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder->guts->stream)) { + decoder->state = FLAC__FILE_DECODER_STREAM_ERROR; + return false; + } + } + if(!FLAC__stream_decoder_process_one_frame(decoder->guts->stream)) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + /* our write callback will change the state when it gets to the target frame */ + if(decoder->state != FLAC__FILE_DECODER_SEEKING) { + break; + } + else { /* we need to narrow the search */ + uint64 this_frame_sample = decoder->guts->last_frame_header.number.sample_number; + if(this_frame_sample == last_frame_sample) { + /* our last move backwards wasn't big enough */ + pos -= (last_pos - pos); + needs_seek = true; + } + else { + if(target_sample < this_frame_sample) { + last_pos = pos; + approx_bytes_per_frame = decoder->guts->last_frame_header.blocksize * decoder->guts->last_frame_header.channels * decoder->guts->last_frame_header.bits_per_sample/8 + 64; + pos -= approx_bytes_per_frame; + needs_seek = true; + } + else { + last_pos = pos; + if(-1 == (pos = ftell(decoder->guts->file))) { + decoder->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + pos -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream); + needs_seek = false; + } + } + if(pos < l) + pos = l; + last_frame_sample = this_frame_sample; + } + } + + return true; +} diff --git a/src/libFLAC/fixed.c b/src/libFLAC/fixed.c new file mode 100644 index 00000000..1b762bcc --- /dev/null +++ b/src/libFLAC/fixed.c @@ -0,0 +1,159 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <math.h> +#include "private/fixed.h" + +#ifndef M_LN2 +/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ +#define M_LN2 0.69314718055994530942 +#endif + +#ifdef min +#undef min +#endif +#define min(x,y) ((x) < (y)? (x) : (y)) + +#ifdef local_abs +#undef local_abs +#endif +#define local_abs(x) ((x)<0? -(x) : (x)) + +unsigned FLAC__fixed_compute_best_predictor(const int32 data[], unsigned data_len, real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) +{ + int32 last_error_0 = data[-1]; + int32 last_error_1 = data[-1] - data[-2]; + int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); + int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); + int32 error_0, error_1, error_2, error_3, error_4; + int32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; + unsigned i, order; + + for(i = 0; i < data_len; i++) { + error_0 = data[i] ; total_error_0 += local_abs(error_0); + error_1 = error_0 - last_error_0; total_error_1 += local_abs(error_1); + error_2 = error_1 - last_error_1; total_error_2 += local_abs(error_2); + error_3 = error_2 - last_error_2; total_error_3 += local_abs(error_3); + error_4 = error_3 - last_error_3; total_error_4 += local_abs(error_4); + + last_error_0 = error_0; + last_error_1 = error_1; + last_error_2 = error_2; + last_error_3 = error_3; + } + + if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4)) + order = 0; + else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) + order = 1; + else if(total_error_2 < min(total_error_3, total_error_4)) + order = 2; + else if(total_error_3 < total_error_4) + order = 3; + else + order = 4; + + /* Estimate the expected number of bits per residual signal sample. */ + /* 'total_error*' is linearly related to the variance of the residual */ + /* signal, so we use it directly to compute E(|x|) */ + residual_bits_per_sample[0] = (real)((total_error_0 > 0 && data_len > 0) ? log(M_LN2 * total_error_0 / (real) data_len) / M_LN2 : 0.0); + residual_bits_per_sample[1] = (real)((total_error_1 > 0 && data_len > 0) ? log(M_LN2 * total_error_1 / (real) data_len) / M_LN2 : 0.0); + residual_bits_per_sample[2] = (real)((total_error_2 > 0 && data_len > 0) ? log(M_LN2 * total_error_2 / (real) data_len) / M_LN2 : 0.0); + residual_bits_per_sample[3] = (real)((total_error_3 > 0 && data_len > 0) ? log(M_LN2 * total_error_3 / (real) data_len) / M_LN2 : 0.0); + residual_bits_per_sample[4] = (real)((total_error_4 > 0 && data_len > 0) ? log(M_LN2 * total_error_4 / (real) data_len) / M_LN2 : 0.0); + + return order; +} + +void FLAC__fixed_compute_residual(const int32 data[], unsigned data_len, unsigned order, int32 residual[]) +{ + unsigned i; + + switch(order) { + case 0: + for(i = 0; i < data_len; i++) { + residual[i] = data[i]; + } + break; + case 1: + for(i = 0; i < data_len; i++) { + residual[i] = data[i] - data[i-1]; + } + break; + case 2: + for(i = 0; i < data_len; i++) { + /* == data[i] - 2*data[i-1] + data[i-2] */ + residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; + } + break; + case 3: + for(i = 0; i < data_len; i++) { + /* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */ + residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; + } + break; + case 4: + for(i = 0; i < data_len; i++) { + /* == data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4] */ + residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; + } + break; + default: + assert(0); + } +} + +void FLAC__fixed_restore_signal(const int32 residual[], unsigned data_len, unsigned order, int32 data[]) +{ + unsigned i; + + switch(order) { + case 0: + for(i = 0; i < data_len; i++) { + data[i] = residual[i]; + } + break; + case 1: + for(i = 0; i < data_len; i++) { + data[i] = residual[i] + data[i-1]; + } + break; + case 2: + for(i = 0; i < data_len; i++) { + /* == residual[i] + 2*data[i-1] - data[i-2] */ + data[i] = residual[i] + (data[i-1]<<1) - data[i-2]; + } + break; + case 3: + for(i = 0; i < data_len; i++) { + /* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */ + data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3]; + } + break; + case 4: + for(i = 0; i < data_len; i++) { + /* == residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4] */ + data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4]; + } + break; + default: + assert(0); + } +} diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c new file mode 100644 index 00000000..ed209413 --- /dev/null +++ b/src/libFLAC/format.c @@ -0,0 +1,66 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdio.h> +#include "FLAC/format.h" + +const unsigned FLAC__MAJOR_VERSION = 0; +const unsigned FLAC__MINOR_VERSION = 2; + +const byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; +const unsigned FLAC__STREAM_SYNC = 0x664C6143; +const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */; + +const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN = 16; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN = 16; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN = 24; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN = 24; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN = 20; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN = 3; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN = 5; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN = 36; /* bits */ +const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH = 18; /* bytes */ + +const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ +const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ +const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ + +const unsigned FLAC__FRAME_HEADER_SYNC = 0x1fe; +const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 9; /* bits */ +const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 3; /* bits */ +const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ +const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ +const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ +const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ +const unsigned FLAC__FRAME_HEADER_CRC8_LEN = 8; /* bits */ + +const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ +const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ +const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ + +const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */ +const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN = 5; /* bits */ +const unsigned FLAC__SUBFRAME_HEADER_LPC_RICE_PARAMETER_LEN = 4; /* bits */ + +const unsigned FLAC__SUBFRAME_HEADER_TYPE_CONSTANT = 0x00; +const unsigned FLAC__SUBFRAME_HEADER_TYPE_VERBATIM = 0x02; +const unsigned FLAC__SUBFRAME_HEADER_TYPE_FIXED = 0x10; +const unsigned FLAC__SUBFRAME_HEADER_TYPE_LPC = 0x40; +const unsigned FLAC__SUBFRAME_HEADER_TYPE_LEN = 8; /* bits */ diff --git a/src/libFLAC/include/private/all.h b/src/libFLAC/include/private/all.h new file mode 100644 index 00000000..b05a4b1f --- /dev/null +++ b/src/libFLAC/include/private/all.h @@ -0,0 +1,29 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__ALL_H +#define FLAC__PRIVATE__ALL_H + +#include "bitbuffer.h" +#include "crc.h" +#include "encoder_framing.h" +#include "fixed.h" +#include "lpc.h" + +#endif diff --git a/src/libFLAC/include/private/bitbuffer.h b/src/libFLAC/include/private/bitbuffer.h new file mode 100644 index 00000000..192b6c9f --- /dev/null +++ b/src/libFLAC/include/private/bitbuffer.h @@ -0,0 +1,64 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__BITBUFFER_H +#define FLAC__PRIVATE__BITBUFFER_H + +#include <stdio.h> /* for FILE */ +#include "FLAC/ordinals.h" + +typedef struct { + byte *buffer; + unsigned capacity; /* in bytes */ + unsigned bytes, bits; + unsigned total_bits; /* must always == 8*bytes+bits */ + unsigned consumed_bytes, consumed_bits; + unsigned total_consumed_bits; /* must always == 8*consumed_bytes+consumed_bits */ +} FLAC__BitBuffer; + +void FLAC__bitbuffer_init(FLAC__BitBuffer *bb); +bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const byte buffer[], unsigned bytes); +bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src); +void FLAC__bitbuffer_free(FLAC__BitBuffer *bb); /* does not 'free(buffer)' */ +bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb); +bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src); +bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits); +bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, uint32 val, unsigned bits); +bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, int32 val, unsigned bits); +bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, uint64 val, unsigned bits); +bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, int64 val, unsigned bits); +bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter); +bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, bool *overflow); +bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, uint32 val); +bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, uint64 val); +bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb); +bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, uint32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, int32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, uint64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, int64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data); +bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen); +bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen); +void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out); + +#endif diff --git a/src/libFLAC/include/private/crc.h b/src/libFLAC/include/private/crc.h new file mode 100644 index 00000000..742d9bc3 --- /dev/null +++ b/src/libFLAC/include/private/crc.h @@ -0,0 +1,30 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__CRC_H +#define FLAC__PRIVATE__CRC_H + +#include "FLAC/ordinals.h" + +/* 8 bit CRC generator, MSB shifted first +** polynomial = x^8 + x^2 + x^1 + 1 +*/ +byte FLAC__crc8(const byte *data, const unsigned len); + +#endif diff --git a/src/libFLAC/include/private/encoder_framing.h b/src/libFLAC/include/private/encoder_framing.h new file mode 100644 index 00000000..bf266497 --- /dev/null +++ b/src/libFLAC/include/private/encoder_framing.h @@ -0,0 +1,33 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__ENCODER_FRAMING_H +#define FLAC__PRIVATE__ENCODER_FRAMING_H + +#include "FLAC/format.h" +#include "bitbuffer.h" + +bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuffer *bb); +bool FLAC__frame_add_header(const FLAC__FrameHeader *header, bool streamable_subset, bool is_last_block, FLAC__BitBuffer *bb); +bool FLAC__subframe_add_constant(unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb); +bool FLAC__subframe_add_fixed(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb); +bool FLAC__subframe_add_lpc(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb); +bool FLAC__subframe_add_verbatim(const int32 signal[], unsigned samples, unsigned bits_per_sample, FLAC__BitBuffer *bb); + +#endif diff --git a/src/libFLAC/include/private/fixed.h b/src/libFLAC/include/private/fixed.h new file mode 100644 index 00000000..e018da62 --- /dev/null +++ b/src/libFLAC/include/private/fixed.h @@ -0,0 +1,65 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__FIXED_H +#define FLAC__PRIVATE__FIXED_H + +#include "FLAC/format.h" + +/* + * FLAC__fixed_compute_best_predictor() + * -------------------------------------------------------------------- + * Compute the best fixed predictor and the expected bits-per-sample + * of the residual signal for each order. + * + * IN data[0,data_len-1] + * IN data_len + * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] + */ +unsigned FLAC__fixed_compute_best_predictor(const int32 data[], unsigned data_len, real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); + +/* + * FLAC__fixed_compute_residual() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * OUT residual[0,data_len-1] residual signal + */ +void FLAC__fixed_compute_residual(const int32 data[], unsigned data_len, unsigned order, int32 residual[]); + +/* + * FLAC__fixed_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +void FLAC__fixed_restore_signal(const int32 residual[], unsigned data_len, unsigned order, int32 data[]); + +#endif diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h new file mode 100644 index 00000000..c30871bf --- /dev/null +++ b/src/libFLAC/include/private/lpc.h @@ -0,0 +1,142 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PRIVATE__LPC_H +#define FLAC__PRIVATE__LPC_H + +#include "FLAC/ordinals.h" + +#define FLAC__MAX_LPC_ORDER (32u) + +/* + * FLAC__lpc_compute_autocorrelation() + * -------------------------------------------------------------------- + * Compute the autocorrelation for lags between 0 and lag-1. + * Assumes data[] outside of [0,data_len-1] == 0. + * Asserts that lag > 0. + * + * IN data[0,data_len-1] + * IN data_len + * IN 0 < lag <= data_len + * OUT autoc[0,lag-1] + */ +void FLAC__lpc_compute_autocorrelation(const real data[], unsigned data_len, unsigned lag, real autoc[]); + +/* + * FLAC__lpc_compute_lp_coefficients() + * -------------------------------------------------------------------- + * Computes LP coefficients for orders 1..max_order. + * Do not call if autoc[0] == 0.0. This means the signal is zero + * and there is no point in calculating a predictor. + * + * IN autoc[0,max_order] autocorrelation values + * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute + * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order + * *** IMPORTANT: + * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched + * OUT error[0,max_order-1] error for each order + * + * Example: if max_order is 9, the LP coefficients for order 9 will be + * in lp_coeff[8][0,8], the LP coefficients for order 8 will be + * in lp_coeff[7][0,7], etc. + */ +void FLAC__lpc_compute_lp_coefficients(const real autoc[], unsigned max_order, real lp_coeff[][FLAC__MAX_LPC_ORDER], real error[]); + +/* + * FLAC__lpc_quantize_coefficients() + * -------------------------------------------------------------------- + * Quantizes the LP coefficients. NOTE: precision + bits_per_sample + * must be less than 32 (sizeof(int32)*8). + * + * IN lp_coeff[0,order-1] LP coefficients + * IN order LP order + * IN FLAC__MIN_QLP_COEFF_PRECISION < precision + * desired precision (in bits, including sign + * bit) of largest coefficient + * IN bits_per_sample > 0 bits per sample of the originial signal + * OUT qlp_coeff[0,order-1] quantized coefficients + * OUT bits # of bits to shift right to get approximated + * LP coefficients. NOTE: could be negative, + * but |*bits| will always be <= precision + * RETURN 0 => quantization OK + * 1 => coefficients vary too much to quantize to the desired + * precision. 'bits' is unset + * 2 => coefficients are all zero, which is bad. 'bits' is unset + */ +int FLAC__lpc_quantize_coefficients(const real lp_coeff[], unsigned order, unsigned precision, unsigned bits_per_sample, int32 qlp_coeff[], int *bits); + +/* + * FLAC__lpc_compute_residual_from_qlp_coefficients() + * -------------------------------------------------------------------- + * Compute the residual signal obtained from sutracting the predicted + * signal from the original. + * + * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP order + * IN lp_quantization quantization of LP coefficients in bits + * OUT residual[0,data_len-1] residual signal + */ +void FLAC__lpc_compute_residual_from_qlp_coefficients(const int32 data[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 residual[]); + +/* + * FLAC__lpc_restore_signal() + * -------------------------------------------------------------------- + * Restore the original signal by summing the residual and the + * predictor. + * + * IN residual[0,data_len-1] residual signal + * IN data_len length of original signal + * IN qlp_coeff[0,order-1] quantized LP coefficients + * IN order > 0 LP order + * IN lp_quantization quantization of LP coefficients in bits + * *** IMPORTANT: the caller must pass in the historical samples: + * IN data[-order,-1] previously-reconstructed historical samples + * OUT data[0,data_len-1] original signal + */ +void FLAC__lpc_restore_signal(const int32 residual[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 data[]); + +/* + * FLAC__lpc_compute_expected_bits_per_residual_sample() + * -------------------------------------------------------------------- + * Compute the expected number of bits per residual signal sample + * based on the LP error (which is related to the residual variance). + * + * IN lpc_error >= 0.0 error returned from calculating LP coefficients + * IN total_samples > 0 # of samples in residual signal + * RETURN expected bits per sample + */ +real FLAC__lpc_compute_expected_bits_per_residual_sample(real lpc_error, unsigned total_samples); + +/* + * FLAC__lpc_compute_best_order() + * -------------------------------------------------------------------- + * Compute the best order from the array of signal errors returned + * during coefficient computation. + * + * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients + * IN max_order > 0 max LP order + * IN total_samples > 0 # of samples in residual signal + * IN bits_per_signal_sample # of bits per sample in the original signal + * RETURN [1,max_order] best order + */ +unsigned FLAC__lpc_compute_best_order(const real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample); + +#endif diff --git a/src/libFLAC/include/protected/stream_decoder.h b/src/libFLAC/include/protected/stream_decoder.h new file mode 100644 index 00000000..be6e541e --- /dev/null +++ b/src/libFLAC/include/protected/stream_decoder.h @@ -0,0 +1,28 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__PROTECTED__STREAM_DECODER_H +#define FLAC__PROTECTED__STREAM_DECODER_H + +#include "FLAC/stream_decoder.h" + +/* only useful to the file_decoder */ +unsigned FLAC__stream_decoder_input_bytes_unconsumed(FLAC__StreamDecoder *decoder); + +#endif diff --git a/src/libFLAC/lpc.c b/src/libFLAC/lpc.c new file mode 100644 index 00000000..615a7342 --- /dev/null +++ b/src/libFLAC/lpc.c @@ -0,0 +1,238 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include "FLAC/format.h" +#include "private/lpc.h" + +#ifndef M_LN2 +/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ +#define M_LN2 0.69314718055994530942 +#endif + +void FLAC__lpc_compute_autocorrelation(const real data[], unsigned data_len, unsigned lag, real autoc[]) +{ + real d; + unsigned i; + + assert(lag > 0); + assert(lag <= data_len); + + while(lag--) { + for(i = lag, d = 0.0; i < data_len; i++) + d += data[i] * data[i - lag]; + autoc[lag] = d; + } +} + +void FLAC__lpc_compute_lp_coefficients(const real autoc[], unsigned max_order, real lp_coeff[][FLAC__MAX_LPC_ORDER], real error[]) +{ + unsigned i, j; + real r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER]; + + assert(0 < max_order); + assert(max_order <= FLAC__MAX_LPC_ORDER); + assert(autoc[0] != 0.0); + + err = autoc[0]; + + for(i = 0; i < max_order; i++) { + /* Sum up this iteration's reflection coefficient. */ + r =- autoc[i+1]; + for(j = 0; j < i; j++) + r -= lpc[j] * autoc[i-j]; + ref[i] = (r/=err); + + /* Update LPC coefficients and total error. */ + lpc[i]=r; + for(j = 0; j < (i>>1); j++) { + real tmp = lpc[j]; + lpc[j] += r * lpc[i-1-j]; + lpc[i-1-j] += r * tmp; + } + if(i & 1) + lpc[j] += lpc[j] * r; + + err *= (1.0 - r * r); + + /* save this order */ + for(j = 0; j <= i; j++) + lp_coeff[i][j] = -lpc[j]; /* N.B. why do we have to negate here? */ + error[i] = err; + } +} + +int FLAC__lpc_quantize_coefficients(const real lp_coeff[], unsigned order, unsigned precision, unsigned bits_per_sample, int32 qlp_coeff[], int *bits) +{ + unsigned i; + real d, rprecision = (real)precision, maxlog = -1e99, minlog = 1e99; + + assert(bits_per_sample > 0); + assert(bits_per_sample <= sizeof(int32)*8); + assert(precision >= FLAC__MIN_QLP_COEFF_PRECISION); + assert(precision + bits_per_sample < sizeof(int32)*8); +#ifdef NDEBUG + (void)bits_per_sample; /* silence compiler warning about unused parameter */ +#endif + + for(i = 0; i < order; i++) { + if(lp_coeff[i] == 0.0) + continue; + d = log(fabs(lp_coeff[i])) / M_LN2; + if(d > maxlog) + maxlog = d; + if(d < minlog) + minlog = d; + } + if(maxlog < minlog) + return 2; + else if(maxlog - minlog >= (real)(precision+1)) + return 1; + else if((rprecision-1.0) - maxlog >= (real)(precision+1)) + rprecision = (real)precision + maxlog + 1.0; + + *bits = (int)floor((rprecision-1.0) - maxlog); /* '-1' because bits can be negative and the sign bit costs 1 bit */ + if(*bits > (int)precision || *bits <= -(int)precision) { + fprintf(stderr, "@@@ FLAC__lpc_quantize_coefficients(): ERROR: *bits=%d, maxlog=%f, minlog=%f, precision=%u, rprecision=%f\n", *bits, maxlog, minlog, precision, rprecision); + return 1; + } + + if(*bits != 0) { /* just to avoid wasting time... */ + for(i = 0; i < order; i++) + qlp_coeff[i] = (int32)floor(lp_coeff[i] * (real)(1 << *bits)); + } + return 0; +} + +void FLAC__lpc_compute_residual_from_qlp_coefficients(const int32 data[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 residual[]) +{ +#ifdef FLAC_OVERFLOW_DETECT + int64 sumo; +#endif + unsigned i, j; + int32 sum; + const int32 *history; + +#ifdef FLAC_OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i<order;i++) + fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]); + fprintf(stderr,"\n"); +#endif + assert(order > 0); + + for(i = 0; i < data_len; i++) { +#ifdef FLAC_OVERFLOW_DETECT + sumo = 0; +#endif + sum = 0; + history = data; + for(j = 0; j < order; j++) { + sum += qlp_coeff[j] * (*(--history)); +#ifdef FLAC_OVERFLOW_DETECT + sumo += (int64)qlp_coeff[j] * (int64)(*history); + if(sumo > 2147483647ll || sumo < -2147483648ll) + fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, sumo=%lld\n",sumo); +#endif + } + *(residual++) = *(data++) - (sum >> lp_quantization); + } + + /* Here's a slightly slower but clearer version: + for(i = 0; i < data_len; i++) { + sum = 0; + history = &(data[i]); + for(j = 0; j < order; j++) + sum += qlp_coeff[j] * (*(--history)); + residual[i] = data[i] - (sum >> lp_quantization); + } + */ +} + +void FLAC__lpc_restore_signal(const int32 residual[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 data[]) +{ +#ifdef FLAC_OVERFLOW_DETECT + int64 sumo; +#endif + unsigned i, j; + int32 sum, *history; + +#ifdef FLAC_OVERFLOW_DETECT_VERBOSE + fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); + for(i=0;i<order;i++) + fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]); + fprintf(stderr,"\n"); +#endif + assert(order > 0); + + for(i = 0; i < data_len; i++) { +#ifdef FLAC_OVERFLOW_DETECT + sumo = 0; +#endif + sum = 0; + history = data+i; + for(j = 0; j < order; j++) { + sum += qlp_coeff[j] * (*(--history)); +#ifdef FLAC_OVERFLOW_DETECT + sumo += (int64)qlp_coeff[j] * (int64)(*history); + if(sumo > 2147483647ll || sumo < -2147483648ll) + fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, sumo=%lld\n",sumo); +#endif + } + data[i] = residual[i] + (sum >> lp_quantization); + } +} + +real FLAC__lpc_compute_expected_bits_per_residual_sample(real lpc_error, unsigned total_samples) +{ + real escale; + + assert(lpc_error >= 0.0); /* the error can never be negative */ + assert(total_samples > 0); + + escale = 0.5 * M_LN2 * M_LN2 / (real)total_samples; + + if(lpc_error > 0.0) + return 0.5 * log(escale * lpc_error) / M_LN2; + else + return 0.0; +} + +unsigned FLAC__lpc_compute_best_order(const real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample) +{ + unsigned order, best_order; + real best_bits, tmp_bits; + + assert(max_order > 0); + + best_order = 0; + best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[0], total_samples) * (real)total_samples; + + for(order = 1; order < max_order; order++) { + tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[order], total_samples) * (real)(total_samples - order) + (real)(order * bits_per_signal_sample); + if(tmp_bits < best_bits) { + best_order = order; + best_bits = tmp_bits; + } + } + + return best_order+1; /* +1 since index of lpc_error[] is order-1 */ +} diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c new file mode 100644 index 00000000..eaf35bf7 --- /dev/null +++ b/src/libFLAC/stream_decoder.c @@ -0,0 +1,1114 @@ +/* libFLAC - Free Lossless Audio Coder library + * Copyright (C) 2000 Josh Coalson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> /* for malloc() */ +#include "FLAC/stream_decoder.h" +#include "private/bitbuffer.h" +#include "private/crc.h" +#include "private/fixed.h" +#include "private/lpc.h" + +typedef struct FLAC__StreamDecoderPrivate { + FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data); + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); + void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); + void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + void *client_data; + FLAC__BitBuffer input; + int32 *output[FLAC__MAX_CHANNELS]; + int32 *residual; + unsigned output_capacity; + uint32 last_frame_number; + uint64 samples_decoded; + bool has_stream_header; + FLAC__StreamMetaData stream_header; + FLAC__FrameHeader frame_header; +} FLAC__StreamDecoderPrivate; + +static byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; + +static bool stream_decoder_allocate_output(FLAC__StreamDecoder *decoder, unsigned size); +static bool stream_decoder_find_metadata_(FLAC__StreamDecoder *decoder); +static bool stream_decoder_read_metadata_(FLAC__StreamDecoder *decoder); +static bool stream_decoder_skip_id3v2_tag_(FLAC__StreamDecoder *decoder); +static bool stream_decoder_frame_sync_(FLAC__StreamDecoder *decoder); +static bool stream_decoder_read_frame_(FLAC__StreamDecoder *decoder, bool *got_a_frame); +static bool stream_decoder_read_frame_header_(FLAC__StreamDecoder *decoder); +static bool stream_decoder_read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel); +static bool stream_decoder_read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel); +static bool stream_decoder_read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order); +static bool stream_decoder_read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order); +static bool stream_decoder_read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel); +static bool stream_decoder_read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order); +static bool stream_decoder_read_zero_padding_(FLAC__StreamDecoder *decoder); +static bool read_callback_(byte buffer[], unsigned *bytes, void *client_data); + +FLAC__StreamDecoder *FLAC__stream_decoder_get_new_instance() +{ + FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)malloc(sizeof(FLAC__StreamDecoder)); + if(decoder != 0) { + decoder->state = FLAC__STREAM_DECODER_UNINITIALIZED; + decoder->guts = 0; + } + return decoder; +} + +void FLAC__stream_decoder_free_instance(FLAC__StreamDecoder *decoder) +{ + free(decoder); +} + +FLAC__StreamDecoderState FLAC__stream_decoder_init( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data), + FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data), + void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data), + void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data), + void *client_data +) +{ + unsigned i; + + assert(sizeof(int) >= 4); /* we want to die right away if this is not true */ + assert(decoder != 0); + assert(read_callback != 0); + assert(write_callback != 0); + assert(metadata_callback != 0); + assert(error_callback != 0); + assert(decoder->state == FLAC__STREAM_DECODER_UNINITIALIZED); + assert(decoder->guts == 0); + + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; + + decoder->guts = (FLAC__StreamDecoderPrivate*)malloc(sizeof(FLAC__StreamDecoderPrivate)); + if(decoder->guts == 0) + return decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + + decoder->guts->read_callback = read_callback; + decoder->guts->write_callback = write_callback; + decoder->guts->metadata_callback = metadata_callback; + decoder->guts->error_callback = error_callback; + decoder->guts->client_data = client_data; + + FLAC__bitbuffer_init(&decoder->guts->input); + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) + decoder->guts->output[i] = 0; + decoder->guts->residual = 0; + + decoder->guts->output_capacity = 0; + decoder->guts->last_frame_number = 0; + decoder->guts->samples_decoded = 0; + decoder->guts->has_stream_header = false; + + return decoder->state; +} + +void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +{ + unsigned i; + assert(decoder != 0); + if(decoder->state == FLAC__STREAM_DECODER_UNINITIALIZED) + return; + if(decoder->guts != 0) { + FLAC__bitbuffer_free(&decoder->guts->input); + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + if(decoder->guts->output[i] != 0) { + free(decoder->guts->output[i]); + decoder->guts->output[i] = 0; + } + } + if(decoder->guts->residual != 0) { + free(decoder->guts->residual); + decoder->guts->residual = 0; + } + free(decoder->guts); + decoder->guts = 0; + } + decoder->state = FLAC__STREAM_DECODER_UNINITIALIZED; +} + +bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) +{ + assert(decoder != 0); + + if(!FLAC__bitbuffer_clear(&decoder->guts->input)) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + return true; +} + +bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) +{ + assert(decoder != 0); + + if(!FLAC__stream_decoder_flush(decoder)) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; + + return true; +} + +bool FLAC__stream_decoder_process_whole_stream(FLAC__StreamDecoder *decoder) +{ + bool dummy; + assert(decoder != 0); + + if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM) + return true; + + assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA); + + if(!FLAC__stream_decoder_reset(decoder)) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + while(1) { + switch(decoder->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!stream_decoder_find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!stream_decoder_read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!stream_decoder_frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!stream_decoder_read_frame_(decoder, &dummy)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + return true; + default: + assert(0); + } + } +} + +bool FLAC__stream_decoder_process_metadata(FLAC__StreamDecoder *decoder) +{ + assert(decoder != 0); + + if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM) + return true; + + assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA); + + if(!FLAC__stream_decoder_reset(decoder)) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + + while(1) { + switch(decoder->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!stream_decoder_find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!stream_decoder_read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + return true; + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + return true; + default: + assert(0); + } + } +} + +bool FLAC__stream_decoder_process_one_frame(FLAC__StreamDecoder *decoder) +{ + bool got_a_frame; + assert(decoder != 0); + + if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM) + return true; + + assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC); + + while(1) { + switch(decoder->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!stream_decoder_frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!stream_decoder_read_frame_(decoder, &got_a_frame)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + return true; + default: + assert(0); + } + } +} + +bool FLAC__stream_decoder_process_remaining_frames(FLAC__StreamDecoder *decoder) +{ + bool dummy; + assert(decoder != 0); + + if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM) + return true; + + assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC); + + while(1) { + switch(decoder->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!stream_decoder_frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!stream_decoder_read_frame_(decoder, &dummy)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + return true; + default: + assert(0); + } + } +} + +unsigned FLAC__stream_decoder_input_bytes_unconsumed(FLAC__StreamDecoder *decoder) +{ + assert(decoder != 0); + return decoder->guts->input.bytes - decoder->guts->input.consumed_bytes; +} + +bool stream_decoder_allocate_output(FLAC__StreamDecoder *decoder, unsigned size) +{ + unsigned i; + int32 *tmp; + + if(size <= decoder->guts->output_capacity) + return true; + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + if(decoder->guts->output[i] != 0) { + free(decoder->guts->output[i]); + decoder->guts->output[i] = 0; + } + } + if(decoder->guts->residual != 0) { + free(decoder->guts->residual); + decoder->guts->residual = 0; + } + + for(i = 0; i < decoder->guts->frame_header.channels; i++) { + tmp = (int32*)malloc(sizeof(int32)*size); + if(tmp == 0) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->guts->output[i] = tmp; + } + tmp = (int32*)malloc(sizeof(int32)*size); + if(tmp == 0) { + decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->guts->residual = tmp; + + decoder->guts->output_capacity = size; + + return true; +} + +bool stream_decoder_find_metadata_(FLAC__StreamDecoder *decoder) +{ + uint32 x; + unsigned i, id; + bool first = 1; + + assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */ + + for(i = id = 0; i < 4; ) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(x == FLAC__STREAM_SYNC_STRING[i]) { + first = 1; + i++; + id = 0; + continue; + } + if(x == ID3V2_TAG_[id]) { + id++; + i = 0; + if(id == 3) { + if(!stream_decoder_skip_id3v2_tag_(decoder)) + return false; /* the read_callback_ sets the state for us */ + } + continue; + } + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + unsigned y; + if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!y) { /* MAGIC NUMBER for the last sync bit */ + decoder->state = FLAC__STREAM_DECODER_READ_FRAME; + return true; + } + } + i = 0; + if(first) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + first = 0; + } + } + + decoder->state = FLAC__STREAM_DECODER_READ_METADATA; + return true; +} + +bool stream_decoder_read_metadata_(FLAC__StreamDecoder *decoder) +{ + uint32 i, x, last_block, type, length; + + assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */ + + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &last_block, FLAC__STREAM_METADATA_IS_LAST_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &type, FLAC__STREAM_METADATA_TYPE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(type == FLAC__METADATA_TYPE_ENCODING) { + decoder->guts->stream_header.type = type; + decoder->guts->stream_header.is_last = last_block; + decoder->guts->stream_header.length = length; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.min_blocksize = x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.max_blocksize = x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.min_framesize = x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.max_framesize = x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.sample_rate = x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.channels = x+1; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->stream_header.data.encoding.bits_per_sample = x+1; + if(!FLAC__bitbuffer_read_raw_uint64(&decoder->guts->input, &decoder->guts->stream_header.data.encoding.total_samples, FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->has_stream_header = true; + decoder->guts->metadata_callback(decoder, &decoder->guts->stream_header, decoder->guts->client_data); + } + else { + /* skip other metadata blocks */ + for(i = 0; i < length; i++) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + } + } + + if(last_block) + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + + return true; +} + +bool stream_decoder_skip_id3v2_tag_(FLAC__StreamDecoder *decoder) +{ + uint32 x; + unsigned i, skip; + + /* skip the version and flags bytes */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 24, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + /* get the size (in bytes) to skip */ + skip = 0; + for(i = 0; i < 4; i++) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + skip <<= 7; + skip |= (x & 0x7f); + } + /* skip the rest of the tag */ + for(i = 0; i < skip; i++) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + } + return true; +} + +bool stream_decoder_frame_sync_(FLAC__StreamDecoder *decoder) +{ + uint32 x; + bool first = 1; + + /* If we know the total number of samples in the stream, stop if we've read that many. */ + /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */ + if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.total_samples) { + if(decoder->guts->samples_decoded >= decoder->guts->stream_header.data.encoding.total_samples) { + decoder->state = FLAC__STREAM_DECODER_END_OF_STREAM; + return true; + } + } + + /* make sure we're byte aligned */ + if(decoder->guts->input.consumed_bits != 0) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8-decoder->guts->input.consumed_bits, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + } + + while(1) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ + unsigned y; + if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!y) { /* MAGIC NUMBER for the last sync bit */ + decoder->state = FLAC__STREAM_DECODER_READ_FRAME; + return true; + } + } + if(first) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + first = 0; + } + } + + return true; +} + +bool stream_decoder_read_frame_(FLAC__StreamDecoder *decoder, bool *got_a_frame) +{ + unsigned channel; + unsigned i; + int32 mid, side, left, right; + + *got_a_frame = false; + + if(!stream_decoder_read_frame_header_(decoder)) + return false; + if(decoder->state != FLAC__STREAM_DECODER_READ_FRAME) { + if(decoder->state == FLAC__STREAM_DECODER_RESYNC_IN_HEADER) + decoder->state = FLAC__STREAM_DECODER_READ_FRAME; + else + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + if(!stream_decoder_allocate_output(decoder, decoder->guts->frame_header.blocksize)) + return false; + for(channel = 0; channel < decoder->guts->frame_header.channels; channel++) { + if(!stream_decoder_read_subframe_(decoder, channel)) + return false; + if(decoder->state != FLAC__STREAM_DECODER_READ_FRAME) { + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + if(!stream_decoder_read_zero_padding_(decoder)) + return false; + + /* Undo any special channel coding */ + switch(decoder->guts->frame_header.channel_assignment) { + case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: + /* do nothing */ + break; + case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: + assert(decoder->guts->frame_header.channels == 2); + for(i = 0; i < decoder->guts->frame_header.blocksize; i++) + decoder->guts->output[1][i] = decoder->guts->output[0][i] - decoder->guts->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: + assert(decoder->guts->frame_header.channels == 2); + for(i = 0; i < decoder->guts->frame_header.blocksize; i++) + decoder->guts->output[0][i] += decoder->guts->output[1][i]; + break; + case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: + assert(decoder->guts->frame_header.channels == 2); + for(i = 0; i < decoder->guts->frame_header.blocksize; i++) { + mid = decoder->guts->output[0][i]; + side = decoder->guts->output[1][i]; + mid <<= 1; + if(side & 1) /* i.e. if 'side' is odd... */ + mid++; + left = mid + side; + right = mid - side; + decoder->guts->output[0][i] = left >> 1; + decoder->guts->output[1][i] = right >> 1; + } + break; + default: + assert(0); + break; + } + + *got_a_frame = true; + + /* put the latest values into the public section of the decoder instance */ + decoder->channels = decoder->guts->frame_header.channels; + decoder->channel_assignment = decoder->guts->frame_header.channel_assignment; + decoder->bits_per_sample = decoder->guts->frame_header.bits_per_sample; + decoder->sample_rate = decoder->guts->frame_header.sample_rate; + decoder->blocksize = decoder->guts->frame_header.blocksize; + + decoder->guts->samples_decoded += decoder->guts->frame_header.blocksize; + + /* write it */ + if(decoder->guts->write_callback(decoder, &decoder->guts->frame_header, decoder->guts->output, decoder->guts->client_data) != FLAC__STREAM_DECODER_WRITE_CONTINUE) + return false; + + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; +} + +bool stream_decoder_read_frame_header_(FLAC__StreamDecoder *decoder) +{ + uint32 x; + uint64 xx; + unsigned i, blocksize_hint = 0, sample_rate_hint = 0; + byte crc, raw_header[15]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */ + unsigned raw_header_len; + bool is_unparseable = false; + + assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */ + + /* init the raw header with the first 8 bits of the sync code */ + raw_header[0] = 0xff; /* MAGIC NUMBER for the first 8 frame sync bits */ + raw_header_len = 1; + + /* + * read in the raw header as bytes so we can CRC it, and parse it on the way + */ + for(i = 0; i < 2; i++) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + else if(x == 0xff) { /* MAGIC NUMBER for the first part of the sync code */ + /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */ + uint32 y; + if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!y) { /* MAGIC NUMBER for the last sync bit */ + decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER; + return true; + } + else { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + raw_header[raw_header_len++] = (byte)x; + } + assert(!(raw_header[1] & 0x80)); /* last sync bit should be confirmed zero before we get here */ + + switch(x = raw_header[1] >> 4) { + case 0: + if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.min_blocksize == decoder->guts->stream_header.data.encoding.max_blocksize) /* i.e. it's a fixed-blocksize stream */ + decoder->guts->frame_header.blocksize = decoder->guts->stream_header.data.encoding.min_blocksize; + else + is_unparseable = true; + break; + case 1: + decoder->guts->frame_header.blocksize = 192; + break; + case 2: + case 3: + case 4: + case 5: + decoder->guts->frame_header.blocksize = 576 << (x-2); + break; + case 6: + case 7: + blocksize_hint = x; + break; + default: + assert(0); + break; + } + + switch(x = raw_header[1] & 0x0f) { + case 0: + if(decoder->guts->has_stream_header) + decoder->guts->frame_header.sample_rate = decoder->guts->stream_header.data.encoding.sample_rate; + else + is_unparseable = true; + break; + case 1: + case 2: + case 3: + is_unparseable = true; + break; + case 4: + decoder->guts->frame_header.sample_rate = 8000; + break; + case 5: + decoder->guts->frame_header.sample_rate = 16000; + break; + case 6: + decoder->guts->frame_header.sample_rate = 22050; + break; + case 7: + decoder->guts->frame_header.sample_rate = 24000; + break; + case 8: + decoder->guts->frame_header.sample_rate = 32000; + break; + case 9: + decoder->guts->frame_header.sample_rate = 44100; + break; + case 10: + decoder->guts->frame_header.sample_rate = 48000; + break; + case 11: + decoder->guts->frame_header.sample_rate = 96000; + break; + case 12: + case 13: + case 14: + sample_rate_hint = x; + break; + case 15: + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + default: + assert(0); + } + + x = (unsigned)(raw_header[2] >> 4); + if(x & 8) { + decoder->guts->frame_header.channels = 2; + switch(x & 7) { + case 0: + decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; + break; + case 1: + decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; + break; + case 2: + decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; + break; + default: + is_unparseable = true; + break; + } + } + else { + decoder->guts->frame_header.channels = (unsigned)x + 1; + decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; + } + + switch(x = (unsigned)(raw_header[2] & 0x0e) >> 1) { + case 0: + if(decoder->guts->has_stream_header) + decoder->guts->frame_header.bits_per_sample = decoder->guts->stream_header.data.encoding.bits_per_sample; + else + is_unparseable = true; + break; + case 1: + decoder->guts->frame_header.bits_per_sample = 8; + break; + case 2: + decoder->guts->frame_header.bits_per_sample = 12; + break; + case 4: + decoder->guts->frame_header.bits_per_sample = 16; + break; + case 5: + decoder->guts->frame_header.bits_per_sample = 20; + break; + case 6: + decoder->guts->frame_header.bits_per_sample = 24; + break; + case 3: + case 7: + is_unparseable = true; + break; + default: + assert(0); + break; + } + + if(raw_header[2] & 0x01) { /* this should be a zero padding bit */ + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + if(blocksize_hint) { + if(!FLAC__bitbuffer_read_utf8_uint64(&decoder->guts->input, &xx, read_callback_, decoder, raw_header, &raw_header_len)) + return false; /* the read_callback_ sets the state for us */ + if(xx == 0xffffffffffffffff) { + if(raw_header[raw_header_len-1] == 0xff) { /* MAGIC NUMBER for sync code */ + uint32 y; + if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!y) { /* MAGIC NUMBER for the last sync bit */ + decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER; + return true; + } + else { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + else { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.min_blocksize == decoder->guts->stream_header.data.encoding.max_blocksize) /* i.e. it's a fixed-blocksize stream */ + decoder->guts->frame_header.number.sample_number = (uint64)decoder->guts->last_frame_number * (int64)decoder->guts->stream_header.data.encoding.min_blocksize + xx; + else + decoder->guts->frame_header.number.sample_number = xx; + } + else { + if(!FLAC__bitbuffer_read_utf8_uint32(&decoder->guts->input, &x, read_callback_, decoder, raw_header, &raw_header_len)) + return false; /* the read_callback_ sets the state for us */ + if(x == 0xffffffff) { + if(raw_header[raw_header_len-1] == 0xff) { /* MAGIC NUMBER for sync code */ + uint32 y; + if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(!y) { /* MAGIC NUMBER for the last sync bit */ + decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER; + return true; + } + else { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + else { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + } + decoder->guts->last_frame_number = x; + if(decoder->guts->has_stream_header) { + decoder->guts->frame_header.number.sample_number = (int64)decoder->guts->stream_header.data.encoding.min_blocksize * (int64)x; + } + else { + is_unparseable = true; + } + } + + if(blocksize_hint) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (byte)x; + if(blocksize_hint == 7) { + uint32 _x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &_x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (byte)_x; + x = (x << 8) | _x; + } + decoder->guts->frame_header.blocksize = x+1; + } + + if(sample_rate_hint) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (byte)x; + if(sample_rate_hint != 12) { + uint32 _x; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &_x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + raw_header[raw_header_len++] = (byte)_x; + x = (x << 8) | _x; + } + if(sample_rate_hint == 12) + decoder->guts->frame_header.sample_rate = x*1000; + else if(sample_rate_hint == 13) + decoder->guts->frame_header.sample_rate = x; + else + decoder->guts->frame_header.sample_rate = x*10; + } + + /* read the crc byte */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + crc = (byte)x; + + if(FLAC__crc8(raw_header, raw_header_len) != crc) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + + if(is_unparseable) { + decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + + return true; +} + +bool stream_decoder_read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel) +{ + uint32 x; + + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__SUBFRAME_HEADER_TYPE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(x & 0x01 || x & 0x80) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + else if(x == 0) { + return stream_decoder_read_subframe_constant_(decoder, channel); + } + else if(x == 2) { + return stream_decoder_read_subframe_verbatim_(decoder, channel); + } + else if(x < 16) { + decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + else if(x <= 24) { + return stream_decoder_read_subframe_fixed_(decoder, channel, (x>>1)&7); + } + else if(x < 64) { + decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + else { + return stream_decoder_read_subframe_lpc_(decoder, channel, ((x>>1)&31)+1); + } +} + +bool stream_decoder_read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel) +{ + int32 x; + unsigned i; + + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &x, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + + for(i = 0; i < decoder->guts->frame_header.blocksize; i++) + decoder->guts->output[channel][i] = x; + + return true; +} + +bool stream_decoder_read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order) +{ + FLAC__SubframeHeader_Fixed subframe_header; + int32 i32; + uint32 u32; + unsigned u; + + subframe_header.order = order; + + /* read warm-up samples */ + for(u = 0; u < order; u++) { + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->output[channel][u] = i32; + } + + /* read entropy coding method info */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.entropy_coding_method.type = u32; + switch(subframe_header.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.entropy_coding_method.data.partitioned_rice.order = u32; + break; + default: + decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + + /* read residual */ + switch(subframe_header.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!stream_decoder_read_residual_partitioned_rice_(decoder, order, subframe_header.entropy_coding_method.data.partitioned_rice.order)) + return false; + break; + default: + assert(0); + } + + /* decode the subframe */ + FLAC__fixed_restore_signal(decoder->guts->residual, decoder->guts->frame_header.blocksize-order, order, decoder->guts->output[channel]+order); + + return true; +} + +bool stream_decoder_read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order) +{ + FLAC__SubframeHeader_LPC subframe_header; + int32 i32; + uint32 u32; + unsigned u; + + subframe_header.order = order; + + /* read warm-up samples */ + for(u = 0; u < order; u++) { + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->output[channel][u] = i32; + } + + /* read qlp coeff precision */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(u32 == 15) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + return true; + } + subframe_header.qlp_coeff_precision = u32+1; + + /* read qlp shift */ + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.quantization_level = i32; + + /* read quantized lp coefficiencts */ + for(u = 0; u < order; u++) { + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, subframe_header.qlp_coeff_precision, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.qlp_coeff[u] = i32; + } + + /* read entropy coding method info */ + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.entropy_coding_method.type = u32; + switch(subframe_header.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + subframe_header.entropy_coding_method.data.partitioned_rice.order = u32; + break; + default: + decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM; + return false; + } + + /* read residual */ + switch(subframe_header.entropy_coding_method.type) { + case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: + if(!stream_decoder_read_residual_partitioned_rice_(decoder, order, subframe_header.entropy_coding_method.data.partitioned_rice.order)) + return false; + break; + default: + assert(0); + } + + /* decode the subframe */ + FLAC__lpc_restore_signal(decoder->guts->residual, decoder->guts->frame_header.blocksize-order, subframe_header.qlp_coeff, order, subframe_header.quantization_level, decoder->guts->output[channel]+order); + + return true; +} + +bool stream_decoder_read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel) +{ + int32 x; + unsigned i; + + for(i = 0; i < decoder->guts->frame_header.blocksize; i++) { + if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &x, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->output[channel][i] = x; + } + + return true; +} + +bool stream_decoder_read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order) +{ + uint32 rice_parameter; + int i; + unsigned partition, sample, u; + const unsigned partitions = 1u << partition_order; + const unsigned partition_samples = partition_order > 0? decoder->guts->frame_header.blocksize >> partition_order : decoder->guts->frame_header.blocksize - predictor_order; + + sample = 0; + for(partition = 0; partition < partitions; partition++) { + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { + if(!FLAC__bitbuffer_read_rice_signed(&decoder->guts->input, &i, rice_parameter, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + decoder->guts->residual[sample] = i; + } + } + + return true; +} + +bool stream_decoder_read_zero_padding_(FLAC__StreamDecoder *decoder) +{ + if(decoder->guts->input.consumed_bits != 0) { + uint32 zero; + if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &zero, 8-decoder->guts->input.consumed_bits, read_callback_, decoder)) + return false; /* the read_callback_ sets the state for us */ + if(zero != 0) { + decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data); + decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + } + } + return true; +} + +bool read_callback_(byte buffer[], unsigned *bytes, void *client_data) +{ + FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data; + FLAC__StreamDecoderReadStatus status; + status = decoder->guts->read_callback(decoder, buffer, bytes, decoder->guts->client_data); + if(status == FLAC__STREAM_DECODER_READ_END_OF_STREAM) + decoder->state = FLAC__STREAM_DECODER_END_OF_STREAM; + else if(status == FLAC__STREAM_DECODER_READ_ABORT) + decoder->state = FLAC__STREAM_DECODER_ABORTED; + return status == FLAC__STREAM_DECODER_READ_CONTINUE; +} diff --git a/src/plugin_winamp2/Makefile.vc b/src/plugin_winamp2/Makefile.vc new file mode 100644 index 00000000..38a99ee4 --- /dev/null +++ b/src/plugin_winamp2/Makefile.vc @@ -0,0 +1,23 @@ +!include <win32.mak> + +!IFNDEF NODEBUG +.c.obj: + $(cc) /GX $(cdebug) $(cflags) $(cvarsdll) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $< +!else +.c.obj: + $(cc) $(cdebug) $(cflags) $(cvarsdll) /I "..\..\include" /I ".\include" -DSTRICT -YX -DNODEBUG $< +!endif + +C_FILES= \ + in_flac.c + +OBJS= $(C_FILES:.c=.obj) + +all: in_flac.dll + +in_flac.dll: $(OBJS) + link.exe /dll /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.dll $(OBJS) libFLAC.lib user32.lib kernel32.lib + +clean: + -del *.obj *.pch + -del ..\..\obj\bin\in_flac.* diff --git a/src/plugin_winamp2/in2.h b/src/plugin_winamp2/in2.h new file mode 100644 index 00000000..dcac5ba0 --- /dev/null +++ b/src/plugin_winamp2/in2.h @@ -0,0 +1,104 @@ +/* Standard Winamp input-plugin header + */ + +#include "out.h" + +// note: exported symbol is now winampGetInModule2. + +#define IN_VER 0x100 + +typedef struct +{ + int version; // module type (IN_VER) + char *description; // description of module, with version string + + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp) + + char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0" + // May be altered from Config, so the user can select what they want + + int is_seekable; // is this stream seekable? + int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :) + + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog + + void (*Init)(); // called at program init + void (*Quit)(); // called at program quit + + void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used + int (*InfoBox)(char *file, HWND hwndParent); + + int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc + // playback stuff + int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error + void (*Pause)(); // pause stream + void (*UnPause)(); // unpause stream + int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not + void (*Stop)(); // stop (unload) stream + + // time stuff + int (*GetLength)(); // get length in ms + int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime() + void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush().. + + // volume stuff + void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume + void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan + + // in-window builtin vis stuff + + void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open() + // call after opening audio device with max latency in ms and samplerate + void (*SAVSADeInit)(); // call in Stop() + + + // simple vis supplying mode + void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); + // sets the spec data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) + + // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff. + int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) + // use when calling SAAdd() + void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp + + + // vis stuff (plug-in) + // simple vis supplying mode + void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) + + // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff. + int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd + void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in + + + // call this in Play() to tell the vis plug-ins the current output params. + void (*VSASetInfo)(int nch, int srate); + + + // dsp plug-in processing: + // (filled in by winamp, called by input plug) + + // returns 1 if active (which means that the number of samples returned by dsp_dosamples + // could be greater than went in.. Use it to estimate if you'll have enough room in the + // output buffer + int (*dsp_isactive)(); + + // returns number of samples to output. This can be as much as twice numsamples. + // be sure to allocate enough buffer for samples, then. + int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate); + + + // eq stuff + void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore. + + // info setting (filled in by winamp) + void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :) + + Out_Module *outMod; // filled in by winamp, optionally used :) +} In_Module; diff --git a/src/plugin_winamp2/in_flac.c b/src/plugin_winamp2/in_flac.c new file mode 100644 index 00000000..fb021c84 --- /dev/null +++ b/src/plugin_winamp2/in_flac.c @@ -0,0 +1,425 @@ +/* in_flac - Winamp FLAC input plugin + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <windows.h> +#include <mmreg.h> +#include <msacm.h> +#include <math.h> +#include <assert.h> + +#include "in2.h" +#include "FLAC/all.h" + +BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + return TRUE; +} + +/* post this to the main window at end of file (after playback as stopped) */ +#define WM_WA_MPEG_EOF WM_USER+2 + +typedef struct { + bool abort_flag; + unsigned total_samples; + unsigned bits_per_sample; + unsigned channels; + unsigned sample_rate; + unsigned length_in_ms; +} stream_info_struct; + +static bool stream_init(const char *infile); +static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); +static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); +static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +In_Module mod; /* the output module (declared near the bottom of this file) */ +char lastfn[MAX_PATH]; /* currently playing file (used for getting info on the current file) */ +int decode_pos_ms; /* current decoding position, in milliseconds */ +int paused; /* are we paused? */ +int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */ +int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2]; /* 2 for max channels */ +char sample_buffer[576 * 2 * (16/8) * 2]; /* 2 for max channels, (16/8) for max bytes per sample, and 2 for who knows what */ +unsigned samples_in_reservoir; +static stream_info_struct stream_info; +static FLAC__FileDecoder *decoder; + +int killDecodeThread=0; /* the kill switch for the decode thread */ +HANDLE thread_handle=INVALID_HANDLE_VALUE; /* the handle to the decode thread */ + +DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */ + +void config(HWND hwndParent) +{ + MessageBox(hwndParent, "No configuration.", "Configuration", MB_OK); + /* if we had a configuration we'd want to write it here :) */ +} +void about(HWND hwndParent) +{ + MessageBox(hwndParent,"Winamp FLAC Plugin v0.2, by Josh Coalson\nSee http://flac.sourceforge.net/","About FLAC Plugin",MB_OK); +} + +void init() +{ + decoder = FLAC__file_decoder_get_new_instance(); +} + +void quit() +{ + if(decoder) + FLAC__file_decoder_free_instance(decoder); +} + +int isourfile(char *fn) { return 0; } +/* used for detecting URL streams.. unused here. strncmp(fn,"http://",7) to detect HTTP streams, etc */ + +int play(char *fn) +{ + int maxlatency; + int thread_id; + HANDLE input_file=INVALID_HANDLE_VALUE; + + if(0 == decoder) { + return 1; + } + + input_file = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (input_file == INVALID_HANDLE_VALUE) { + return 1; + } + CloseHandle(input_file); + + if(!stream_init(fn)) { + return 1; + } + + strcpy(lastfn,fn); + paused=0; + decode_pos_ms=0; + seek_needed=-1; + samples_in_reservoir = 0; + + maxlatency = mod.outMod->Open(stream_info.sample_rate, stream_info.channels, stream_info.bits_per_sample, -1,-1); + if (maxlatency < 0) { /* error opening device */ + return 1; + } + + /* dividing by 1000 for the first parameter of setinfo makes it */ + /* display 'H'... for hundred.. i.e. 14H Kbps. */ + mod.SetInfo((stream_info.sample_rate*stream_info.bits_per_sample*stream_info.channels)/1000,stream_info.sample_rate/1000,stream_info.channels,1); + + /* initialize vis stuff */ + mod.SAVSAInit(maxlatency,stream_info.sample_rate); + mod.VSASetInfo(stream_info.sample_rate,stream_info.channels); + + mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */ + + killDecodeThread=0; + thread_handle = (HANDLE) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,(void *) &killDecodeThread,0,&thread_id); + + return 0; +} + +void pause() +{ + paused=1; + mod.outMod->Pause(1); +} + +void unpause() +{ + paused=0; + mod.outMod->Pause(0); +} +int ispaused() +{ + return paused; +} + +void stop() +{ + if (thread_handle != INVALID_HANDLE_VALUE) { + killDecodeThread=1; + if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT) { + MessageBox(mod.hMainWindow,"error asking thread to die!\n","error killing decode thread",0); + TerminateThread(thread_handle,0); + } + CloseHandle(thread_handle); + thread_handle = INVALID_HANDLE_VALUE; + } + if(decoder) { + if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder); + } + + mod.outMod->Close(); + + mod.SAVSADeInit(); +} + +int getlength() +{ + return (int)stream_info.length_in_ms; +} + +int getoutputtime() +{ + return decode_pos_ms+(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime()); +} + +void setoutputtime(int time_in_ms) +{ + seek_needed=time_in_ms; +} + +void setvolume(int volume) { mod.outMod->SetVolume(volume); } +void setpan(int pan) { mod.outMod->SetPan(pan); } + +int infoDlg(char *fn, HWND hwnd) +{ + /* TODO: implement info dialog. */ + return 0; +} + +void getfileinfo(char *filename, char *title, int *length_in_ms) +{ + if (!filename || !*filename) { /* currently playing file */ + if (length_in_ms) + *length_in_ms=getlength(); + if (title) { + char *p=lastfn+strlen(lastfn); + while (*p != '\\' && p >= lastfn) p--; + strcpy(title,++p); + } + } + else { /* some other file */ + if (length_in_ms) { + FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_get_new_instance(); + stream_info_struct tmp_stream_info; + tmp_stream_info.abort_flag = false; + if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback, metadata_callback, error_callback, &tmp_stream_info) != FLAC__FILE_DECODER_OK) + return; + if(!FLAC__file_decoder_process_metadata(tmp_decoder)) + return; + + *length_in_ms = (int)tmp_stream_info.length_in_ms; + + if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(tmp_decoder); + FLAC__file_decoder_free_instance(tmp_decoder); + } + if (title) { + char *p=filename+strlen(filename); + while (*p != '\\' && p >= filename) p--; + strcpy(title,++p); + } + } +} + +void eq_set(int on, char data[10], int preamp) +{ +} + +DWORD WINAPI __stdcall DecodeThread(void *b) +{ + int done=0; + + while (! *((int *)b) ) { + unsigned channels = stream_info.channels; + unsigned bits_per_sample = stream_info.bits_per_sample; + unsigned bytes_per_sample = (bits_per_sample+7)/8; + unsigned sample_rate = stream_info.sample_rate; + if (seek_needed != -1) { + const double distance = (double)seek_needed / (double)getlength(); + unsigned target_sample = (unsigned)(distance * (double)stream_info.total_samples); + if(FLAC__file_decoder_seek_absolute(decoder, (uint64)target_sample)) { + decode_pos_ms = (int)(distance * (double)getlength()); + seek_needed=-1; + done=0; + mod.outMod->Flush(decode_pos_ms); + } + } + if (done) { + if (!mod.outMod->IsPlaying()) { + PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0); + return 0; + } + Sleep(10); + } + else if (mod.outMod->CanWrite() >= ((int)(576*channels*bytes_per_sample) << (mod.dsp_isactive()?1:0))) { + while(samples_in_reservoir < 576) { + if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) { + done = 1; + break; + } + else if(!FLAC__file_decoder_process_one_frame(decoder)) + break; + } + + if (samples_in_reservoir == 0) { + done=1; + } + else { + unsigned i, n = min(samples_in_reservoir, 576), delta; + int l; + signed short *ssbuffer = (signed short *)sample_buffer; + + for(i = 0; i < n*channels; i++) + ssbuffer[i] = reservoir[i]; + delta = i; + for( ; i < samples_in_reservoir*channels; i++) + reservoir[i-delta] = reservoir[i]; + samples_in_reservoir -= n; + l = n * channels * bytes_per_sample; + + mod.SAAddPCMData((char *)sample_buffer,channels,bits_per_sample,decode_pos_ms); + mod.VSAAddPCMData((char *)sample_buffer,channels,bits_per_sample,decode_pos_ms); + decode_pos_ms+=(576*1000)/sample_rate; + if (mod.dsp_isactive()) + l=mod.dsp_dosamples((short *)sample_buffer,n/channels/bytes_per_sample,bits_per_sample,channels,sample_rate) * (channels*bytes_per_sample); + mod.outMod->Write(sample_buffer,l); + } + } + else Sleep(20); + } + return 0; +} + + + +In_Module mod = +{ + IN_VER, + "Reference FLAC Player v0.0" +#ifdef __alpha + "(AXP)" +#else + "(x86)" +#endif + , + 0, /* hMainWindow */ + 0, /* hDllInstance */ + "FLAC\0FLAC Audio File (*.FLAC)\0" + , + 1, /* is_seekable */ + 1, /* uses output */ + config, + about, + init, + quit, + getfileinfo, + infoDlg, + isourfile, + play, + pause, + unpause, + ispaused, + stop, + + getlength, + getoutputtime, + setoutputtime, + + setvolume, + setpan, + + 0,0,0,0,0,0,0,0,0, /* vis stuff */ + + + 0,0, /* dsp */ + + eq_set, + + NULL, /* setinfo */ + + 0 /* out_mod */ + +}; + +__declspec( dllexport ) In_Module * winampGetInModule2() +{ + return &mod; +} + + +/*********************************************************************** + * local routines + **********************************************************************/ +bool stream_init(const char *infile) +{ + if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, &stream_info) != FLAC__FILE_DECODER_OK) { + MessageBox(mod.hMainWindow,"ERROR initializing decoder, state = %d\n","ERROR initializing decoder",0); + return false; + } + + stream_info.abort_flag = false; + if(!FLAC__file_decoder_process_metadata(decoder)) { + return false; + } + + return true; +} + +FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + unsigned bps = stream_info->bits_per_sample, channels = stream_info->channels; + unsigned wide_samples = header->blocksize, wide_sample, sample, channel, offset; + + (void)decoder; + + if(stream_info->abort_flag) + return FLAC__STREAM_DECODER_WRITE_ABORT; + + offset = samples_in_reservoir * channels; + + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + reservoir[offset+sample] = (int16)buffer[channel][wide_sample]; + + samples_in_reservoir += wide_samples; + + return FLAC__STREAM_DECODER_WRITE_CONTINUE; +} + +void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + (void)decoder; + if(metadata->type == FLAC__METADATA_TYPE_ENCODING) { + assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */ + stream_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff); + stream_info->bits_per_sample = metadata->data.encoding.bits_per_sample; + stream_info->channels = metadata->data.encoding.channels; + stream_info->sample_rate = metadata->data.encoding.sample_rate; + + if(stream_info->bits_per_sample != 16) { + MessageBox(mod.hMainWindow,"ERROR: plugin can only handle 16-bit samples\n","ERROR: plugin can only handle 16-bit samples",0); + stream_info->abort_flag = true; + return; + } + stream_info->length_in_ms = stream_info->total_samples * 10 / (stream_info->sample_rate / 100); + } +} + +void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + stream_info_struct *stream_info = (stream_info_struct *)client_data; + (void)decoder; + if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC) + stream_info->abort_flag = true; +} diff --git a/src/plugin_winamp2/out.h b/src/plugin_winamp2/out.h new file mode 100644 index 00000000..f82708a1 --- /dev/null +++ b/src/plugin_winamp2/out.h @@ -0,0 +1,55 @@ +/* Standard Winamp output-plugin header + */ + +#define OUT_VER 0x10 + +typedef struct +{ + int version; // module version (OUT_VER) + char *description; // description of module, with version string + int id; // module id. each input module gets its own. non-nullsoft modules should + // be >= 65536. + + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp) + + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog + + void (*Init)(); // called when loaded + void (*Quit)(); // called when unloaded + + int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); + // returns >=0 on success, <0 on failure + // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins. + // ... so don't expect the max latency returned to be what you asked for. + // returns max latency in ms (0 for diskwriters, etc) + // bufferlenms and prebufferms must be in ms. 0 to use defaults. + // prebufferms must be <= bufferlenms + + void (*Close)(); // close the ol' output device. + + int (*Write)(char *buf, int len); + // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data. + // 1 returns not able to write (yet). Non-blocking, always. + + int (*CanWrite)(); // returns number of bytes possible to write at a given time. + // Never will decrease unless you call Write (or Close, heh) + + int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be + // written (i.e. closing while IsPlaying() returns 1 would truncate the song + + int (*Pause)(int pause); // returns previous pause state + + void (*SetVolume)(int volume); // volume is 0-255 + void (*SetPan)(int pan); // pan is -128 to 128 + + void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms) + // (used for seeking) + + int (*GetOutputTime)(); // returns played time in MS + int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff) + +} Out_Module; + + diff --git a/src/plugin_xmms/Makefile b/src/plugin_xmms/Makefile new file mode 100644 index 00000000..a50821c2 --- /dev/null +++ b/src/plugin_xmms/Makefile @@ -0,0 +1,14 @@ +# +# GNU makefile +# + +LIB_NAME = libxmms-flac +INCLUDES = $(shell xmms-config --cflags) -I./include -I../../include +LIBS = ../../obj/lib/libFLAC.a + +OBJS = \ + plugin.o + +include ../../build/lib.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/plugin_xmms/plugin.c b/src/plugin_xmms/plugin.c new file mode 100644 index 00000000..43b4ac53 --- /dev/null +++ b/src/plugin_xmms/plugin.c @@ -0,0 +1,393 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <glib.h> + +#include "xmms/plugin.h" +#include "xmms/util.h" +#include "FLAC/all.h" + +typedef struct { + byte raw[128]; + char title[31]; + char artist[31]; + char album[31]; + char comment[31]; + unsigned year; + unsigned track; /* may be 0 if v1 (not v1.1) tag */ + unsigned genre; + char description[1024]; /* the formatted description passed to xmms */ +} id3v1_struct; + +typedef struct { + bool abort_flag; + bool is_playing; + bool eof; + unsigned total_samples; + unsigned bits_per_sample; + unsigned channels; + unsigned sample_rate; + unsigned length_in_msec; + int seek_to_in_sec; +} file_info_struct; + +static void FLAC_XMMS__init(); +static int FLAC_XMMS__is_our_file(char *filename); +static void FLAC_XMMS__play_file(char *filename); +static void FLAC_XMMS__stop(); +static void FLAC_XMMS__pause(short p); +static void FLAC_XMMS__seek(int time); +static int FLAC_XMMS__get_time(); +static void FLAC_XMMS__cleanup(); +static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length); + +static void *play_loop_(void *arg); +static bool decoder_init_(const char *filename); +static bool get_id3v1_tag_(const char *filename, id3v1_struct *tag); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data); +static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data); +static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + + +InputPlugin flac_ip = +{ + NULL, + NULL, + "FLAC Player v" FLAC__VERSION_STRING, + FLAC_XMMS__init, + NULL, + NULL, + FLAC_XMMS__is_our_file, + NULL, + FLAC_XMMS__play_file, + FLAC_XMMS__stop, + FLAC_XMMS__pause, + FLAC_XMMS__seek, + NULL, + FLAC_XMMS__get_time, + NULL, + NULL, + FLAC_XMMS__cleanup, + NULL, + NULL, + NULL, + NULL, + FLAC_XMMS__get_song_info, + NULL, /* file_info_box */ + NULL +}; + +static int16 reservoir_[FLAC__MAX_BLOCK_SIZE * 2]; /* 2 for max channels */ +static unsigned reservoir_samples_; +static FLAC__FileDecoder *decoder_; +static file_info_struct file_info_; +static pthread_t decode_thread_; +static bool audio_error_ = false; + +InputPlugin *get_iplugin_info() +{ + flac_ip.description = g_strdup_printf("FLAC Player v%u.%u", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION); + return &flac_ip; +} + +void FLAC_XMMS__init() +{ + decoder_ = FLAC__file_decoder_get_new_instance(); +} + +int FLAC_XMMS__is_our_file(char *filename) +{ + char *ext; + + ext = strrchr(filename, '.'); + if (ext) + if (!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla")) + return 1; + return 0; +} + +void FLAC_XMMS__play_file(char *filename) +{ + FILE *f; + id3v1_struct tag; + + if(0 == (f = fopen(filename, "r"))) + return; + fclose(f); + + if(!decoder_init_(filename)) + return; + + reservoir_samples_ = 0; + audio_error_ = false; + file_info_.is_playing = true; + file_info_.eof = false; + + if (flac_ip.output->open_audio(FMT_S16_NE, file_info_.sample_rate, file_info_.channels) == 0) { + audio_error_ = true; + if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder_); + return; + } + + (void)get_id3v1_tag_(filename, &tag); + flac_ip.set_info(tag.description, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels); + + file_info_.seek_to_in_sec = -1; + pthread_create(&decode_thread_, NULL, play_loop_, NULL); +} + +void FLAC_XMMS__stop() +{ + if(file_info_.is_playing) { + file_info_.is_playing = false; + pthread_join(decode_thread_, NULL); + flac_ip.output->close_audio(); + if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder_); + } +} + +void FLAC_XMMS__pause(short p) +{ + flac_ip.output->pause(p); +} + +void FLAC_XMMS__seek(int time) +{ + file_info_.seek_to_in_sec = time; + file_info_.eof = false; + + while(file_info_.seek_to_in_sec != -1) + xmms_usleep(10000); +} + +int FLAC_XMMS__get_time() +{ + if(audio_error_) + return -2; + if(!file_info_.is_playing || (file_info_.eof && !flac_ip.output->buffer_playing())) + return -1; + else + return flac_ip.output->output_time(); +} + +void FLAC_XMMS__cleanup() +{ + if(decoder_) + FLAC__file_decoder_free_instance(decoder_); +} + +void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) +{ + id3v1_struct tag; + + if(title) { + (void)get_id3v1_tag_(filename, &tag); + *title = g_malloc(strlen(tag.description)+1); + strcpy(*title, tag.description); + } + if(length_in_msec) { + FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_get_new_instance(); + file_info_struct tmp_file_info; + if(0 == tmp_decoder) { + *length_in_msec = -1; + return; + } + tmp_file_info.abort_flag = false; + if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback_, metadata_callback_, error_callback_, &tmp_file_info) != FLAC__FILE_DECODER_OK) { + *length_in_msec = -1; + return; + } + if(!FLAC__file_decoder_process_metadata(tmp_decoder)) { + *length_in_msec = -1; + return; + } + + *length_in_msec = (int)tmp_file_info.length_in_msec; + + if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(tmp_decoder); + FLAC__file_decoder_free_instance(tmp_decoder); + } +} + +/*********************************************************************** + * local routines + **********************************************************************/ + +void *play_loop_(void *arg) +{ + + (void)arg; + + while(file_info_.is_playing) { + if(!file_info_.eof) { + (void)FLAC__file_decoder_process_one_frame(decoder_); + if(reservoir_samples_ > 0) { + unsigned bytes = reservoir_samples_ * ((file_info_.bits_per_sample+7)/8) * file_info_.channels; + flac_ip.add_vis_pcm(flac_ip.output->written_time(), FMT_S16_NE, file_info_.channels, bytes, (char*)reservoir_); + while(flac_ip.output->buffer_free() < (int)bytes && file_info_.is_playing && file_info_.seek_to_in_sec == -1) + xmms_usleep(10000); + if(file_info_.is_playing && file_info_.seek_to_in_sec == -1) + flac_ip.output->write_audio((char*)reservoir_, bytes); + reservoir_samples_ = 0; + } + else { + file_info_.eof = true; + xmms_usleep(10000); + } + } + else + xmms_usleep(10000); + if (file_info_.seek_to_in_sec != -1) { + const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec; + unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples); + if(FLAC__file_decoder_seek_absolute(decoder_, (uint64)target_sample)) { + flac_ip.output->flush(file_info_.seek_to_in_sec * 1000); + file_info_.seek_to_in_sec = -1; + file_info_.eof = false; + } + } + + } + if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED) + FLAC__file_decoder_finish(decoder_); + + /* are these two calls necessary? */ + flac_ip.output->buffer_free(); + flac_ip.output->buffer_free(); + + pthread_exit(NULL); + return 0; /* to silence the compiler warning about not returning a value */ +} + +bool decoder_init_(const char *filename) +{ + if(decoder_ == 0) + return false; + + if(FLAC__file_decoder_init(decoder_, filename, write_callback_, metadata_callback_, error_callback_, &file_info_) != FLAC__FILE_DECODER_OK) + return false; + + file_info_.abort_flag = false; + + if(!FLAC__file_decoder_process_metadata(decoder_)) + return false; + + return true; +} + +bool get_id3v1_tag_(const char *filename, id3v1_struct *tag) +{ + const char *temp; + FILE *f = fopen(filename, "rb"); + memset(tag, 0, sizeof(id3v1_struct)); + + /* set the description to the filename by default */ + temp = strrchr(filename, '/'); + if(!temp) + temp = filename; + else + temp++; + strcpy(tag->description, temp); + *strrchr(tag->description, '.') = '\0'; + + if(0 == f) + return false; + if(-1 == fseek(f, -128, SEEK_END)) { + fclose(f); + return false; + } + if(fread(tag->raw, 1, 128, f) < 128) { + fclose(f); + return false; + } + fclose(f); + if(strncmp(tag->raw, "TAG", 3)) + return false; + else { + char year_str[5]; + + memcpy(tag->title, tag->raw+3, 30); + memcpy(tag->artist, tag->raw+33, 30); + memcpy(tag->album, tag->raw+63, 30); + memcpy(year_str, tag->raw+93, 4); year_str[4] = '\0'; tag->year = atoi(year_str); + memcpy(tag->comment, tag->raw+97, 30); + tag->genre = (unsigned)((byte)tag->raw[127]); + tag->track = (unsigned)((byte)tag->raw[126]); + + sprintf(tag->description, "%s - %s", tag->artist, tag->title); + + return true; + } +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data) +{ + file_info_struct *file_info = (file_info_struct *)client_data; + unsigned bps = file_info->bits_per_sample, channels = file_info->channels; + unsigned wide_samples = header->blocksize, wide_sample, sample, channel; + + (void)decoder; + + if(file_info->abort_flag) + return FLAC__STREAM_DECODER_WRITE_ABORT; + + assert(bps == 16); + + for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) + for(channel = 0; channel < channels; channel++, sample++) + reservoir_[sample] = (int16)buffer[channel][wide_sample]; + + reservoir_samples_ = wide_samples; + + return FLAC__STREAM_DECODER_WRITE_CONTINUE; +} + +void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data) +{ + file_info_struct *file_info = (file_info_struct *)client_data; + (void)decoder; + if(metadata->type == FLAC__METADATA_TYPE_ENCODING) { + assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */ + file_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff); + file_info->bits_per_sample = metadata->data.encoding.bits_per_sample; + file_info->channels = metadata->data.encoding.channels; + file_info->sample_rate = metadata->data.encoding.sample_rate; + + if(file_info->bits_per_sample != 16) { + file_info->abort_flag = true; + return; + } + file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100); + } +} + +void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + file_info_struct *file_info = (file_info_struct *)client_data; + (void)decoder; + if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC) + file_info->abort_flag = true; +} diff --git a/src/test_streams/Makefile b/src/test_streams/Makefile new file mode 100644 index 00000000..e64e3d13 --- /dev/null +++ b/src/test_streams/Makefile @@ -0,0 +1,13 @@ +# +# GNU makefile +# + +PROGRAM_NAME = test_streams +INCLUDES = -I./include -I../../include +LIBS = -lm +OBJS = \ + main.o + +include ../../build/exe.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/test_streams/main.c b/src/test_streams/main.c new file mode 100644 index 00000000..42165205 --- /dev/null +++ b/src/test_streams/main.c @@ -0,0 +1,258 @@ +/* test_streams - Simple test pattern generator + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include "FLAC/ordinals.h" + +#ifdef _WIN32 + static const char *mode = "wb"; +#else + static const char *mode = "w"; +#endif + +static bool is_big_endian_host; + +static void swap16(int16 *i) +{ + unsigned char *x = (unsigned char *)i, b; + if(!is_big_endian_host) { + b = x[0]; + x[0] = x[1]; + x[1] = b; + } +} + +/* a mono one-sample 16bps stream */ +static bool generate_01() +{ + FILE *f; + int16 x = -32768; + + if(0 == (f = fopen("test01.raw", mode))) + return false; + + swap16(&x); + if(fwrite(&x, sizeof(x), 1, f) < 1) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo one-sample 16bps stream */ +static bool generate_02() +{ + FILE *f; + int16 xl = -32768, xr = 32767; + + if(0 == (f = fopen("test02.raw", mode))) + return false; + + swap16(&xl); + swap16(&xr); + + if(fwrite(&xl, sizeof(xl), 1, f) < 1) + goto foo; + if(fwrite(&xr, sizeof(xr), 1, f) < 1) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono five-sample 16bps stream */ +static bool generate_03() +{ + FILE *f; + int16 x[] = { -25, 0, 25, 50, 100 }; + unsigned i; + + if(0 == (f = fopen("test03.raw", mode))) + return false; + + for(i = 0; i < 5; i++) + swap16(x+i); + + if(fwrite(&x, sizeof(int16), 5, f) < 5) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a stereo five-sample 16bps stream */ +static bool generate_04() +{ + FILE *f; + int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 }; + unsigned i; + + if(0 == (f = fopen("test04.raw", mode))) + return false; + + for(i = 0; i < 10; i++) + swap16(x+i); + + if(fwrite(&x, sizeof(int16), 10, f) < 10) + goto foo; + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 8bps stream */ +static bool generate_fsd8(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + assert(pattern != 0); + + if(0 == (f = fopen(fn, mode))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + signed char x = pattern[p] > 0? 127 : -128; + if(fwrite(&x, sizeof(x), 1, f) < 1) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono full-scale deflection 16bps stream */ +static bool generate_fsd16(const char *fn, const int pattern[], unsigned reps) +{ + FILE *f; + unsigned rep, p; + + assert(pattern != 0); + + if(0 == (f = fopen(fn, mode))) + return false; + + for(rep = 0; rep < reps; rep++) { + for(p = 0; pattern[p]; p++) { + int16 x = pattern[p] > 0? 32767 : -32768; + swap16(&x); + if(fwrite(&x, sizeof(x), 1, f) < 1) + goto foo; + } + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +/* a mono sine-wave 16bps stream */ +static bool generate_sine16(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2) +{ + const signed short full_scale = 32767; + const double delta1 = 2.0 * M_PI / ( sample_rate / f1); + const double delta2 = 2.0 * M_PI / ( sample_rate / f2); + FILE *f; + double theta1, theta2; + unsigned i; + + if(0 == (f = fopen(fn, mode))) + return false; + + for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) { + double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale; + int16 v = (int16)(val + 0.5); + swap16(&v); + if(fwrite(&v, sizeof(v), 1, f) < 1) + goto foo; + } + + fclose(f); + return true; +foo: + fclose(f); + return false; +} + +int main(int argc, char *argv[]) +{ + uint32 test = 1; + + int pattern01[] = { 1, -1, 0 }; + int pattern02[] = { 1, 1, -1, 0 }; + int pattern03[] = { 1, -1, -1, 0 }; + int pattern04[] = { 1, -1, 1, -1, 0 }; + int pattern05[] = { 1, -1, -1, 1, 0 }; + int pattern06[] = { 1, -1, 1, 1, -1, 0 }; + int pattern07[] = { 1, -1, -1, 1, -1, 0 }; + + (void)argc; + (void)argv; + is_big_endian_host = (*((byte*)(&test)))? false : true; + + if(!generate_01()) return 1; + if(!generate_02()) return 1; + if(!generate_03()) return 1; + if(!generate_04()) return 1; + + if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1; + if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1; + if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1; + if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1; + if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1; + if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1; + if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1; + + if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1; + if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1; + if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1; + if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1; + if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1; + if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1; + if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1; + + if(!generate_sine16("sine-01.raw", 44100.0, 80000, 441.0, 0.50, 441.0, 0.49)) return 1; + if(!generate_sine16("sine-02.raw", 44100.0, 80000, 441.0, 0.61, 661.5, 0.37)) return 1; + if(!generate_sine16("sine-03.raw", 44100.0, 80000, 441.0, 0.50, 882.0, 0.49)) return 1; + if(!generate_sine16("sine-04.raw", 44100.0, 80000, 441.0, 0.50, 4410.0, 0.49)) return 1; + if(!generate_sine16("sine-05.raw", 44100.0, 50000, 8820.0, 0.70, 4410.0, 0.29)) return 1; + + return 0; +} diff --git a/src/test_unit/Makefile b/src/test_unit/Makefile new file mode 100644 index 00000000..b1892eab --- /dev/null +++ b/src/test_unit/Makefile @@ -0,0 +1,14 @@ +# +# GNU makefile +# + +PROGRAM_NAME = test_unit +INCLUDES = -I../libFLAC/include -I../../include +LIBS = -lFLAC -lm +OBJS = \ + bitbuffer.o \ + main.o + +include ../../build/exe.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/test_unit/bitbuffer.c b/src/test_unit/bitbuffer.c new file mode 100644 index 00000000..c5279ae5 --- /dev/null +++ b/src/test_unit/bitbuffer.c @@ -0,0 +1,629 @@ +/* test_unit - Simple FLAC unit tester + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "private/bitbuffer.h" /* from the libFLAC private include area */ + +static bool dummy_read_callback(byte buffer[], unsigned *bytes, void *client_data) +{ + (void)buffer, (void)bytes, (void)client_data; + return true; +} + +int test_bitbuffer() +{ + FLAC__BitBuffer bb, bb_zero, bb_one, bbcopy; + bool ok; + unsigned i, j; + static byte test_pattern1[19] = { 0xaa, 0xf0, 0xaa, 0xbe, 0xaa, 0xaa, 0xaa, 0xa8, 0x30, 0x0a, 0xaa, 0xaa, 0xaa, 0xad, 0xea, 0xdb, 0xee, 0xfa, 0xce }; + + printf("testing init... OK\n"); + FLAC__bitbuffer_init(&bb); + FLAC__bitbuffer_init(&bb_zero); + FLAC__bitbuffer_init(&bb_one); + FLAC__bitbuffer_init(&bbcopy); + + printf("testing clear... "); + ok = FLAC__bitbuffer_clear(&bb) && FLAC__bitbuffer_clear(&bb_zero) && FLAC__bitbuffer_clear(&bb_one) && FLAC__bitbuffer_clear(&bbcopy); + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) + return 1; + + printf("setting up bb_one... "); + ok = FLAC__bitbuffer_write_raw_uint32(&bb_one, 1, 7) && FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 6, dummy_read_callback, 0); + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) + return 1; + FLAC__bitbuffer_dump(&bb_one, stdout); + + printf("capacity = %u\n", bb.capacity); + + printf("testing zeroes, raw_uint32*... "); + ok = + FLAC__bitbuffer_write_raw_uint32(&bb, 0x1, 1) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0x1, 2) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0xa, 5) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0xf0, 8) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0x2aa, 10) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0xf, 4) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0xaaaaaaaa, 32) && + FLAC__bitbuffer_write_zeroes(&bb, 4) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0x3, 2) && + FLAC__bitbuffer_write_zeroes(&bb, 8) && + FLAC__bitbuffer_write_raw_uint64(&bb, 0xaaaaaaaadeadbeef, 64) && + FLAC__bitbuffer_write_raw_uint32(&bb, 0xace, 12) + ; + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 0) { + printf("FAILED bit count %u != 0\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing raw_uint32 some more... "); + ok = FLAC__bitbuffer_write_raw_uint32(&bb, 0x3d, 6); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 6) { + printf("FAILED bit count %u != 6\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x3d) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_zero)... "); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_zero); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 6) { + printf("FAILED bit count %u != 6\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x3d) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_one)... "); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 7) { + printf("FAILED bit count %u != 7\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x7b) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_one again)... "); + (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 1, 1); + (void)FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 1, dummy_read_callback, 0); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)+1) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+1); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 0) { + printf("FAILED bit count %u != 0\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-1] != 0xf7) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_four)... "); + (void)FLAC__bitbuffer_clear(&bb_one); + (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 8, 4); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)+1) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+1); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 4) { + printf("FAILED bit count %u != 4\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x08) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_eight)... "); + (void)FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 4, dummy_read_callback, 0); + (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 0xaa, 8); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)+2) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+2); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 4) { + printf("FAILED bit count %u != 4\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-1] != 0x8a || bb.buffer[bb.bytes] != 0x0a) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing concatenate_aligned (bb_seventeen)... "); + (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 0x155, 9); + ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bytes != sizeof(test_pattern1)+4) { + printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+4); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.bits != 5) { + printf("FAILED bit count %u != 5\n", bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(bb.total_bits != 8*bb.bytes+bb.bits) { + printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-3] != 0x8a || bb.buffer[bb.bytes-2] != 0xaa || bb.buffer[bb.bytes-1] != 0xaa || bb.buffer[bb.bytes] != 0x15) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("OK\n"); + FLAC__bitbuffer_dump(&bb, stdout); + + printf("testing utf8_uint32(0x00000000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000000); + ok = bb.total_bits == 8 && bb.buffer[0] == 0; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x0000007F)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x0000007F); + ok = bb.total_bits == 8 && bb.buffer[0] == 0x7F; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x00000080)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000080); + ok = bb.total_bits == 16 && bb.buffer[0] == 0xC2 && bb.buffer[1] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x000007FF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x000007FF); + ok = bb.total_bits == 16 && bb.buffer[0] == 0xDF && bb.buffer[1] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x00000800)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000800); + ok = bb.total_bits == 24 && bb.buffer[0] == 0xE0 && bb.buffer[1] == 0xA0 && bb.buffer[2] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x0000FFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x0000FFFF); + ok = bb.total_bits == 24 && bb.buffer[0] == 0xEF && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x00010000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00010000); + ok = bb.total_bits == 32 && bb.buffer[0] == 0xF0 && bb.buffer[1] == 0x90 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x001FFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x001FFFFF); + ok = bb.total_bits == 32 && bb.buffer[0] == 0xF7 && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x00200000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00200000); + ok = bb.total_bits == 40 && bb.buffer[0] == 0xF8 && bb.buffer[1] == 0x88 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x03FFFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x03FFFFFF); + ok = bb.total_bits == 40 && bb.buffer[0] == 0xFB && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x04000000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x04000000); + ok = bb.total_bits == 48 && bb.buffer[0] == 0xFC && bb.buffer[1] == 0x84 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint32(0x7FFFFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint32(&bb, 0x7FFFFFFF); + ok = bb.total_bits == 48 && bb.buffer[0] == 0xFD && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000000000000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000000); + ok = bb.total_bits == 8 && bb.buffer[0] == 0; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x000000000000007F)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000000000007F); + ok = bb.total_bits == 8 && bb.buffer[0] == 0x7F; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000000000080)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000080); + ok = bb.total_bits == 16 && bb.buffer[0] == 0xC2 && bb.buffer[1] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x00000000000007FF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x00000000000007FF); + ok = bb.total_bits == 16 && bb.buffer[0] == 0xDF && bb.buffer[1] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000000000800)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000800); + ok = bb.total_bits == 24 && bb.buffer[0] == 0xE0 && bb.buffer[1] == 0xA0 && bb.buffer[2] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x000000000000FFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000000000FFFF); + ok = bb.total_bits == 24 && bb.buffer[0] == 0xEF && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000000010000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000010000); + ok = bb.total_bits == 32 && bb.buffer[0] == 0xF0 && bb.buffer[1] == 0x90 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x00000000001FFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x00000000001FFFFF); + ok = bb.total_bits == 32 && bb.buffer[0] == 0xF7 && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000000200000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000200000); + ok = bb.total_bits == 40 && bb.buffer[0] == 0xF8 && bb.buffer[1] == 0x88 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000003FFFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000003FFFFFF); + ok = bb.total_bits == 40 && bb.buffer[0] == 0xFB && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000004000000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000004000000); + ok = bb.total_bits == 48 && bb.buffer[0] == 0xFC && bb.buffer[1] == 0x84 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x000000007FFFFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000007FFFFFFF); + ok = bb.total_bits == 48 && bb.buffer[0] == 0xFD && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000080000000)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000080000000); + ok = bb.total_bits == 56 && bb.buffer[0] == 0xFE && bb.buffer[1] == 0x82 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80 && bb.buffer[6] == 0x80; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing utf8_uint64(0x0000000FFFFFFFFF)... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000FFFFFFFFF); + ok = bb.total_bits == 56 && bb.buffer[0] == 0xFE && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF && bb.buffer[6] == 0xBF; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + + printf("testing grow... "); + FLAC__bitbuffer_clear(&bb); + FLAC__bitbuffer_write_raw_uint32(&bb, 0xa, 4); + j = bb.capacity; + for(i = 0; i < j; i++) + FLAC__bitbuffer_write_raw_uint32(&bb, 0xaa, 8); + ok = bb.total_bits = i*8+4 && bb.buffer[0] == 0xaa && bb.buffer[i] == 0xa; + printf("%s\n", ok?"OK":"FAILED"); + if(!ok) { + FLAC__bitbuffer_dump(&bb, stdout); + return 1; + } + printf("capacity = %u\n", bb.capacity); + + printf("testing clone... "); + ok = FLAC__bitbuffer_clone(&bbcopy, &bb); + if(!ok) { + printf("FAILED\n"); + FLAC__bitbuffer_dump(&bb, stdout); + FLAC__bitbuffer_dump(&bbcopy, stdout); + return 1; + } + if(bb.bytes != bbcopy.bytes) { + printf("FAILED byte count %u != %u\n", bb.bytes, bbcopy.bytes); + FLAC__bitbuffer_dump(&bb, stdout); + FLAC__bitbuffer_dump(&bbcopy, stdout); + return 1; + } + if(bb.bits != bbcopy.bits) { + printf("FAILED bit count %u != %u\n", bb.bits, bbcopy.bits); + FLAC__bitbuffer_dump(&bb, stdout); + FLAC__bitbuffer_dump(&bbcopy, stdout); + return 1; + } + if(bb.total_bits != bbcopy.total_bits) { + printf("FAILED total_bits count %u != %u\n", bb.total_bits, bbcopy.total_bits); + FLAC__bitbuffer_dump(&bb, stdout); + FLAC__bitbuffer_dump(&bbcopy, stdout); + return 1; + } + if(memcmp(bb.buffer, bbcopy.buffer, sizeof(byte)*bb.capacity) != 0) { + printf("FAILED pattern match\n"); + FLAC__bitbuffer_dump(&bb, stdout); + FLAC__bitbuffer_dump(&bbcopy, stdout); + return 1; + } + printf("OK\n"); + + printf("testing free... OK\n"); + FLAC__bitbuffer_free(&bb); + FLAC__bitbuffer_free(&bbcopy); + + printf("\nPASSED!\n"); + return 0; +} diff --git a/src/test_unit/bitbuffer.h b/src/test_unit/bitbuffer.h new file mode 100644 index 00000000..5a6de2b3 --- /dev/null +++ b/src/test_unit/bitbuffer.h @@ -0,0 +1,24 @@ +/* test_unit - Simple FLAC unit tester + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FLAC__TEST_UNIT_BITBUFFER_H +#define FLAC__TEST_UNIT_BITBUFFER_H + +int test_bitbuffer(); + +#endif diff --git a/src/test_unit/main.c b/src/test_unit/main.c new file mode 100644 index 00000000..8d172bc0 --- /dev/null +++ b/src/test_unit/main.c @@ -0,0 +1,26 @@ +/* test_unit - Simple FLAC unit tester + * Copyright (C) 2000 Josh Coalson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "bitbuffer.h" + +int main(int argc, char *argv[]) +{ + if(0 != test_bitbuffer()) + return 1; + return 0; +} diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..e19548ae --- /dev/null +++ b/test/Makefile @@ -0,0 +1,13 @@ +# +# GNU makefile +# +all: clean + ./test_unit.sh + ./test_streams.sh + +debug: all + +release: all + +clean: + rm -f *.raw *.flac *.cmp *.log diff --git a/test/test_streams.sh b/test/test_streams.sh new file mode 100755 index 00000000..8f67d822 --- /dev/null +++ b/test/test_streams.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../obj/lib +export LD_LIBRARY_PATH + +if ../obj/bin/test_streams ; then : ; else + echo "ERROR during test_streams" 1>&2 + exit 1 +fi + +FLAC=../obj/bin/flac + +test_file () +{ + name=$1 + channels=$2 + bps=$3 + encode_options="$4" + + echo "### ENCODE $name ########################################" >> ./encode.log + echo -n "$name: encode..." + if $FLAC -s -fb -fs 44100 -fp $bps -fc $channels -0 -l 8 -m -e $encode_options $name.raw $name.flac 2>>./encode.log ; then : ; else + echo "ERROR during encode of $name" 1>&2 + exit 1 + fi + echo "### DECODE $name ########################################" >> ./decode.log + echo -n "decode..." + if $FLAC -s -fb -d -fr $name.flac $name.cmp 2>>./decode.log ; then : ; else + echo "ERROR during decode of $name" 1>&2 + exit 1 + fi + echo -n "compare..." + if cmp $name.raw $name.cmp ; then : ; else + echo "ERROR during compare of $name" 1>&2 + exit 1 + fi + echo OK +} + +echo "Testing small files..." +test_file test01 1 16 +test_file test02 2 16 +test_file test03 1 16 +test_file test04 2 16 + +echo "Testing 8-bit full-scale deflection streams..." +for b in 01 02 03 04 05 06 07 ; do + test_file fsd8-$b 1 8 "-q 15" +done + +echo "Testing 16-bit full-scale deflection streams..." +for b in 01 02 03 04 05 06 07 ; do + test_file fsd16-$b 1 16 "-q 15" +done + +echo "Testing sine wave streams..." +for b in 01 02 03 04 05 ; do + test_file sine-$b 1 16 "" +done + +echo "Testing some frame header variations..." +test_file sine-02 1 16 "--lax -b 16" +test_file sine-02 1 16 "--lax -b 65535" +test_file sine-02 1 16 "-b 16" +test_file sine-02 1 16 "-b 65535" +test_file sine-02 1 16 "--lax -fs 9" +test_file sine-02 1 16 "--lax -fs 90" +test_file sine-02 1 16 "--lax -fs 90000" +test_file sine-02 1 16 "-fs 9" +test_file sine-02 1 16 "-fs 90" +test_file sine-02 1 16 "-fs 90000" diff --git a/test/test_unit.sh b/test/test_unit.sh new file mode 100755 index 00000000..efc5a723 --- /dev/null +++ b/test/test_unit.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../obj/lib +export LD_LIBRARY_PATH + +if ../obj/bin/test_unit ; then : ; else + echo "ERROR during testgen" 1>&2 + exit 1 +fi |