diff --git a/libraries/ESP32-audioI2S/.github/workflows/stale.yml b/libraries/ESP32-audioI2S/.github/workflows/stale.yml new file mode 100644 index 0000000..923368f --- /dev/null +++ b/libraries/ESP32-audioI2S/.github/workflows/stale.yml @@ -0,0 +1,24 @@ +name: Close inactive issues +on: + schedule: + - cron: "30 1 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v9 + with: + days-before-issue-stale: 30 + days-before-issue-close: 14 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." + days-before-pr-stale: 45 + days-before-pr-close: 10 + stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' + diff --git a/libraries/ESP32-audioI2S/CMakeLists.txt b/libraries/ESP32-audioI2S/CMakeLists.txt new file mode 100644 index 0000000..2ac4dd4 --- /dev/null +++ b/libraries/ESP32-audioI2S/CMakeLists.txt @@ -0,0 +1,9 @@ + +get_filename_component(dir ${CMAKE_CURRENT_LIST_FILE} PATH) +FILE(GLOB_RECURSE app_sources ${dir}/src/*.cpp) + +idf_component_register(SRCS ${app_sources} + REQUIRES "ESP32-audioI2S" + INCLUDE_DIRS "src" + REQUIRES wear_levelling Arduino +) diff --git a/libraries/ESP32-audioI2S/LICENSE b/libraries/ESP32-audioI2S/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/libraries/ESP32-audioI2S/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/libraries/ESP32-audioI2S/README.md b/libraries/ESP32-audioI2S/README.md new file mode 100644 index 0000000..9595ee4 --- /dev/null +++ b/libraries/ESP32-audioI2S/README.md @@ -0,0 +1,97 @@ +# ESP32-audioI2S + +:warning: **This library only works on multi-core chips like ESP32, ESP32-S3 and ESP32-P4. Your board must have PSRAM! It does not work on the ESP32-S2, ESP32-C3 etc** :warning: + +Plays mp3, m4a and wav files from SD card via I2S with external hardware. +HELIX-mp3 and faad2-aac decoder is included. There is also an OPUS decoder for Fullband, an VORBIS decoder and a FLAC decoder. +Works with MAX98357A (3 Watt amplifier with DAC), connected three lines (DOUT, BLCK, LRC) to I2S. The I2S output frequency is always 48kHz, regardless of the input source, so Bluetooth devices can also be connected without any problems. +For stereo are two MAX98357A necessary. AudioI2S works with UDA1334A (Adafruit I2S Stereo Decoder Breakout Board), PCM5102A and CS4344. +Other HW may work but not tested. Plays also icy-streams, GoogleTTS and OpenAIspeech. Can be compiled with Arduino IDE. [WIKI](https://github.com/schreibfaul1/ESP32-audioI2S/wiki) + +```` c++ +#include "Arduino.h" +#include "WiFi.h" +#include "Audio.h" + +// Digital I/O used +#define I2S_DOUT 25 +#define I2S_BCLK 27 +#define I2S_LRC 26 + +String ssid = "*******"; +String password = "*******"; + +Audio audio; + +// callbacks +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; // optional + Serial.begin(115200); + WiFi.begin(ssid.c_str(), password.c_str()); + while (WiFi.status() != WL_CONNECTED) delay(1500); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(21); // default 0...21 + audio.connecttohost("http://stream.antennethueringen.de/live/aac-64/stream.antennethueringen.de/"); +} + +void loop(){ + audio.loop(); + vTaskDelay(1); +} + +```` +You can find more examples here: https://github.com/schreibfaul1/ESP32-audioI2S/tree/master/examples + +````c++ +// detailed cb output +void my_audio_info(Audio::msg_t m) { + switch(m.e){ + case Audio::evt_info: Serial.printf("info: ....... %s\n", m.msg); break; + case Audio::evt_eof: Serial.printf("end of file: %s\n", m.msg); break; + case Audio::evt_bitrate: Serial.printf("bitrate: .... %s\n", m.msg); break; // icy-bitrate or bitrate from metadata + case Audio::evt_icyurl: Serial.printf("icy URL: .... %s\n", m.msg); break; + case Audio::evt_id3data: Serial.printf("ID3 data: ... %s\n", m.msg); break; // id3-data or metadata + case Audio::evt_lasthost: Serial.printf("last URL: ... %s\n", m.msg); break; + case Audio::evt_name: Serial.printf("station name: %s\n", m.msg); break; // station name or icy-name + case Audio::evt_streamtitle: Serial.printf("stream title: %s\n", m.msg); break; + case Audio::evt_icylogo: Serial.printf("icy logo: ... %s\n", m.msg); break; + case Audio::evt_icydescription: Serial.printf("icy descr: .. %s\n", m.msg); break; + case Audio::evt_image: for(int i = 0; i < m.vec.size(); i += 2){ + Serial.printf("cover image: segment %02i, pos %07lu, len %05lu\n", i / 2, m.vec[i], m.vec[i + 1]);} break; // APIC + case Audio::evt_lyrics: Serial.printf("sync lyrics: %s\n", m.msg); break; + case Audio::evt_log : Serial.printf("audio_logs: %s\n", m.msg); break; + default: Serial.printf("message:..... %s\n", m.msg); break; + } +} +```` +
+ +|Codec | ESP32 |ESP32-S3 or ESP32-P4 | | +|------------|-------------|-----------------------------|--------------------------| +| mp3 | y | y | | +| aac | y | y | | +| aacp | y (mono) | y (+SBR, +Parametric Stereo)| | +| wav | y | y | | +| flac | y | y |blocksize max 24576 bytes | +| vorbis | y | y | <=196Kbit/s | +| m4a | y | y | | +| opus | y | y | | + +
+ +*** +Wiring +![schematic](https://github.com/user-attachments/assets/77ce30d2-acb1-4b5d-a9d6-4f1e3d56e385) + +*** +Impulse diagram +![Impulse diagram](https://github.com/schreibfaul1/ESP32-audioI2S/blob/master/additional_info/Impulsdiagramm.jpg) +*** +Yellobyte has developed an all-in-one board. It includes an ESP32-S3 N8R2, 2x MAX98357 and an SD card adapter. +Documentation, circuit diagrams and examples can be found here: https://github.com/yellobyte/ESP32-DevBoards-Getting-Started +![image](https://github.com/user-attachments/assets/4002d09e-8e76-4e08-9265-188fed7628d3) + diff --git a/libraries/ESP32-audioI2S/additional_info/Arduino Library.png b/libraries/ESP32-audioI2S/additional_info/Arduino Library.png new file mode 100644 index 0000000..d8e13c7 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Arduino Library.png differ diff --git a/libraries/ESP32-audioI2S/additional_info/Audio Duration.png b/libraries/ESP32-audioI2S/additional_info/Audio Duration.png new file mode 100644 index 0000000..83d829a Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Audio Duration.png differ diff --git a/libraries/ESP32-audioI2S/additional_info/Breadboard.jpg b/libraries/ESP32-audioI2S/additional_info/Breadboard.jpg new file mode 100644 index 0000000..a5bbe2a Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Breadboard.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/DAC CS4344.jpg b/libraries/ESP32-audioI2S/additional_info/DAC CS4344.jpg new file mode 100644 index 0000000..e7eb418 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/DAC CS4344.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/DAC PCM5102A.jpg b/libraries/ESP32-audioI2S/additional_info/DAC PCM5102A.jpg new file mode 100644 index 0000000..72dd2eb Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/DAC PCM5102A.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_MAX98357A .JPG b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_MAX98357A .JPG new file mode 100644 index 0000000..3721ca8 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_MAX98357A .JPG differ diff --git a/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A.JPG b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A.JPG new file mode 100644 index 0000000..5d64a31 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A.JPG differ diff --git a/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A_ONLY.JPG b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A_ONLY.JPG new file mode 100644 index 0000000..f0c5dcd Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_PCM5102A_ONLY.JPG differ diff --git a/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_UDA1334A.JPG b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_UDA1334A.JPG new file mode 100644 index 0000000..2769427 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/ESP32_I2S_UDA1334A.JPG differ diff --git a/libraries/ESP32-audioI2S/additional_info/FLAC Metadata Picture Block.jpg b/libraries/ESP32-audioI2S/additional_info/FLAC Metadata Picture Block.jpg new file mode 100644 index 0000000..57a393f Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/FLAC Metadata Picture Block.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/ID3 Attatched Picture Frame.jpg b/libraries/ESP32-audioI2S/additional_info/ID3 Attatched Picture Frame.jpg new file mode 100644 index 0000000..87d63f5 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/ID3 Attatched Picture Frame.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/Impulsdiagramm.jpg b/libraries/ESP32-audioI2S/additional_info/Impulsdiagramm.jpg new file mode 100644 index 0000000..447d88d Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Impulsdiagramm.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/M4A Coverart Block.jpg b/libraries/ESP32-audioI2S/additional_info/M4A Coverart Block.jpg new file mode 100644 index 0000000..b1fa16e Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/M4A Coverart Block.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/Ogg_Metadatapicture.png b/libraries/ESP32-audioI2S/additional_info/Ogg_Metadatapicture.png new file mode 100644 index 0000000..f88b064 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Ogg_Metadatapicture.png differ diff --git a/libraries/ESP32-audioI2S/additional_info/Partition Scheme.png b/libraries/ESP32-audioI2S/additional_info/Partition Scheme.png new file mode 100644 index 0000000..7267a3e Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Partition Scheme.png differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/Collide.ogg b/libraries/ESP32-audioI2S/additional_info/Testfiles/Collide.ogg new file mode 100644 index 0000000..f829117 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/Collide.ogg differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/Miss-Marple.m4a b/libraries/ESP32-audioI2S/additional_info/Testfiles/Miss-Marple.m4a new file mode 100644 index 0000000..90773d7 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/Miss-Marple.m4a differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/Olsen-Banden.mp3 b/libraries/ESP32-audioI2S/additional_info/Testfiles/Olsen-Banden.mp3 new file mode 100644 index 0000000..e25afd3 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/Olsen-Banden.mp3 differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/Pink-Panther.wav b/libraries/ESP32-audioI2S/additional_info/Testfiles/Pink-Panther.wav new file mode 100644 index 0000000..b603144 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/Pink-Panther.wav differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/Santiano-Wellerman.flac b/libraries/ESP32-audioI2S/additional_info/Testfiles/Santiano-Wellerman.flac new file mode 100644 index 0000000..53df53f Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/Santiano-Wellerman.flac differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/myPlaylist.m3u b/libraries/ESP32-audioI2S/additional_info/Testfiles/myPlaylist.m3u new file mode 100644 index 0000000..023c12f --- /dev/null +++ b/libraries/ESP32-audioI2S/additional_info/Testfiles/myPlaylist.m3u @@ -0,0 +1,5 @@ +#EXTM3U +#EXTINF:18,Bjarne Liller - Olsen Banden (Titelmusik der Olsenbande) - Olsen-Banden.mp3 +https://raw.githubusercontent.com/schreibfaul1/ESP32-audioI2S/master/additional_info/Testfiles/Olsen-Banden.mp3 +#EXTINF:10,Santiano-Wellermann - Santiano-Wellerman.flac +https://raw.githubusercontent.com/schreibfaul1/ESP32-audioI2S/master/additional_info/Testfiles/Santiano-Wellerman.flac diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/sample.opus b/libraries/ESP32-audioI2S/additional_info/Testfiles/sample.opus new file mode 100644 index 0000000..3eea946 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/sample.opus differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-CBR.mp3 b/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-CBR.mp3 new file mode 100644 index 0000000..c5ac91d Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-CBR.mp3 differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-VBR.mp3 b/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-VBR.mp3 new file mode 100644 index 0000000..1abc713 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/seconds-VBR.mp3 differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_mono.wav b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_mono.wav new file mode 100644 index 0000000..08abecf Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_mono.wav differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_stereo.wav b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_stereo.wav new file mode 100644 index 0000000..9c2d693 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_16bit_stereo.wav differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_mono.wav b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_mono.wav new file mode 100644 index 0000000..44d0ce3 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_mono.wav differ diff --git a/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_stereo.wav b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_stereo.wav new file mode 100644 index 0000000..e94b092 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Testfiles/test_8bit_stereo.wav differ diff --git a/libraries/ESP32-audioI2S/additional_info/Volume_Settings_Dynamics.jpg b/libraries/ESP32-audioI2S/additional_info/Volume_Settings_Dynamics.jpg new file mode 100644 index 0000000..225278c Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/Volume_Settings_Dynamics.jpg differ diff --git a/libraries/ESP32-audioI2S/additional_info/lowpass.png b/libraries/ESP32-audioI2S/additional_info/lowpass.png new file mode 100644 index 0000000..e6b6774 Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/lowpass.png differ diff --git a/libraries/ESP32-audioI2S/additional_info/minimal.JPG b/libraries/ESP32-audioI2S/additional_info/minimal.JPG new file mode 100644 index 0000000..935dc8a Binary files /dev/null and b/libraries/ESP32-audioI2S/additional_info/minimal.JPG differ diff --git a/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.cpp_ b/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.cpp_ new file mode 100644 index 0000000..59af973 --- /dev/null +++ b/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.cpp_ @@ -0,0 +1,10261 @@ +/* + * aac_decoder.cpp + * libhelix_HAACDECODER + * + * Created on: 26.10.2018 + * Updated on: 22.05.2024 + ************************************************************************************/ + +#include "aac_decoder.h" + +const uint32_t SQRTHALF = 0x5a82799a; /* sqrt(0.5), format = Q31 */ +const uint32_t Q28_2 = 0x20000000; /* Q28: 2.0 */ +const uint32_t Q28_15 = 0x30000000; /* Q28: 1.5 */ +const uint8_t NUM_ITER_IRN = 5; +const uint8_t NUM_TERMS_RPI = 5; +const uint32_t LOG2_EXP_INV = 0x58b90bfc; /* 1/log2(e), Q31 */ +const uint8_t SF_OFFSET = 100; +const uint8_t AAC_PROFILE_LC = 1; +const uint8_t NUM_TIME_SLOTS = 16; +const uint8_t SAMPLES_PER_SLOT = 2; /* RATE in spec */ +const uint8_t SYNCWORDH = 0xff; /* 12-bit syncword */ +const uint8_t SYNCWORDL = 0xf0; +const uint8_t NUM_SAMPLE_RATES = 12; +const uint8_t NUM_DEF_CHAN_MAPS = 8; +const uint32_t NSAMPS_LONG = 1024; +const uint8_t NSAMPS_SHORT = 128; +const uint8_t NUM_SYN_ID_BITS = 3; +const uint8_t NUM_INST_TAG_BITS = 4; +const uint8_t NWINDOWS_LONG = 1; +const uint8_t NWINDOWS_SHORT = 8; +const uint8_t AAC_MAX_NCHANS = 2; /* set to default max number of channels */ +const uint16_t AAC_MAX_NSAMPS = 1024; +const uint8_t MAX_NCHANS_ELEM = 2; /* max number of channels in any single bitstream element */ +const uint8_t MAX_NUM_PCE_ADIF = 16; +const uint8_t ADIF_COPYID_SIZE = 9; +const uint8_t HUFFTAB_SPEC_OFFSET = 1; +const uint8_t FBITS_OUT_DQ_OFF = 20 - 15; /* (FBITS_OUT_DQ - SF_DQ_OFFSET) */ +const uint8_t GBITS_IN_DCT4 = 4; /* min guard bits in for DCT4 */ +const uint8_t FBITS_LOST_DCT4 = 1; /* number of fraction bits lost (>> out) in DCT-IV */ +const uint8_t FBITS_OUT_IMDCT = 3; +const uint8_t NUM_IMDCT_SIZES = 2; +const uint8_t FBITS_LPC_COEFS = 20; +const uint8_t NUM_ITER_INVSQRT = 4; +const uint32_t X0_COEF_2 = 0xc0000000; /* Q29: -2.0 */ +const uint32_t X0_OFF_2 = 0x60000000; /* Q29: 3.0 */ +const uint32_t Q26_3 = 0x0c000000; /* Q26: 3.0 */ +const uint8_t EXT_SBR_DATA = 0x0d; +const uint8_t EXT_SBR_DATA_CRC = 0x0e; +const uint8_t NUM_SAMPLE_RATES_SBR = 9; /* downsampled (single-rate) mode unsupported */ +const uint8_t MAX_NUM_PATCHES = 5; +const uint8_t MAX_QMF_BANDS = 48; /* max QMF subbands covered by SBR (4.6.18.3.6) */ +const uint8_t MAX_NUM_ENV = 5; +const uint8_t NUM_QMF_DELAY_BUFS = 10; +const uint8_t FBITS_IN_QMFA = 14; +const uint8_t NOISE_FLOOR_OFFSET = 6; +const uint8_t FBITS_OUT_DQ_NOISE = 24; /* range of Q_orig = [2^-24, 2^6] */ +const uint8_t FBITS_LOST_QMFA = (1 + 2 + 3 + 2 + 1); +const uint8_t FBITS_OUT_QMFA = (FBITS_IN_QMFA - FBITS_LOST_QMFA); +const uint8_t FBITS_IN_QMFS = FBITS_OUT_QMFA; +const uint8_t FBITS_LOST_DCT4_64 = (2 + 3 + 2); /* 2 in premul, 3 in FFT, 2 in postmul */ +const uint8_t FBITS_OUT_QMFS = (FBITS_IN_QMFS - FBITS_LOST_DCT4_64 + 6 - 1); +const uint8_t RND_VAL = (1 << (FBITS_OUT_QMFS-1)); +const uint8_t HF_ADJ = 2; +const uint8_t HF_GEN = 8; +const uint8_t FBITS_LPCOEFS = 29; /* Q29 for range of (-4, 4) */ +const uint32_t MAG_16 = (16 * (1 << (32 - (2*(32-FBITS_LPCOEFS))))); /* i.e. 16 in Q26 format */ +const uint32_t RELAX_COEF = 0x7ffff79c; /* 1.0 / (1.0 + 1e-6), Q31 */ +const uint8_t MAX_NUM_SMOOTH_COEFS = 5; +const uint8_t FBITS_OUT_DQ_ENV = 29; /* dequantized env scalefactors are Q(29 - envDataDequantScale) */ +const uint8_t FBITS_GLIM_BOOST = 24; +const uint8_t FBITS_QLIM_BOOST = 14; +const uint8_t MIN_GBITS_IN_QMFS = 2; +const uint16_t nmdctTab[2] = {128, 1024}; +const uint8_t postSkip[2] = {15, 1}; +const uint16_t nfftTab[2] = {64, 512}; +const uint8_t nfftlog2Tab[2] = {6, 9}; +const uint8_t cos4sin4tabOffset[2] = {0, 128}; + +PSInfoBase_t *m_PSInfoBase; +AACDecInfo_t *m_AACDecInfo; +AACFrameInfo_t m_AACFrameInfo; +ADTSHeader_t m_fhADTS; +ADIFHeader_t m_fhADIF; +ProgConfigElement_t *m_pce[16]; +PulseInfo_t m_pulseInfo[2]; // [MAX_NCHANS_ELEM] +aac_BitStreamInfo_t m_aac_BitStreamInfo; +PSInfoSBR_t *m_PSInfoSBR; + +//---------------------------------------------------------------------------------------------------------------------- +inline int32_t MULSHIFT32(int32_t x, int32_t y){ + int32_t z; z = (int64_t)x * (int64_t)y >> 32; + return z; +} +inline int32_t CLZ(int32_t x){ +#ifdef __XTENSA__ + return __builtin_clz(x); +#else + int32_t numZeros; + if(!x) return 32; /* count leading zeros with binary search (function should be 17 ARM instructions total) */ + numZeros = 1; + if (!((uint32_t)x >> 16)) { numZeros += 16; x <<= 16; } + if (!((uint32_t)x >> 24)) { numZeros += 8; x <<= 8; } + if (!((uint32_t)x >> 28)) { numZeros += 4; x <<= 4; } + if (!((uint32_t)x >> 30)) { numZeros += 2; x <<= 2; } + numZeros -= ((uint32_t)x >> 31); + return numZeros; +#endif +} +inline int32_t FASTABS(int32_t x){ +#ifdef __XTENSA__ //fb + return __builtin_abs(x); +#else + int32_t sign; + sign = x >> (sizeof(int32_t) * 8 - 1); + x ^= sign; x -= sign; return x; +#endif +} +inline int64_t MADD64(int64_t sum64, int32_t x, int32_t y){ + sum64 += (int64_t)x * (int64_t)y; + return sum64; +} +inline int16_t CLIPTOSHORT(int32_t x){ +#ifdef __XTENSA__ //fb + asm ("clamps %0, %1, 15" : "=a" (x) : "a" (x) : ); + return x; +#else + int32_t sign; /* clip to [-32768, 32767] */ + sign = x >> 31; + if (sign != (x >> 15)) x = sign ^ ((1 << 15) - 1); + return (int16_t)x; +#endif +} +inline int32_t CLIP_2N(int32_t y, int32_t n){ +#ifdef __XTENSA__ //fb + int32_t x = 1 << n; \ + if (y < -x) y = -x; \ + x--; \ + if (y > x) y = x; \ + return y; +#else + int32_t sign = y >> 31; + if(sign != (y >> n)) + y = sign ^ ((1 << n) - 1); + return y; +#endif +} +inline int32_t CLIP_2N_SHIFT30(int32_t y, int32_t n){ + int32_t sign = y >> 31; + if(sign != (y >> (30 - n))) + y = sign ^ (0x3fffffff); + else + y = (y << n); + return y; +} +//---------------------------------------------------------------------------------------------------------------------- + +const uint32_t cos4sin4tab[128 + 1024] PROGMEM = { +/* 128 - format = Q30 * 2^-7 */ +0xbf9bc731, 0xff9b783c, 0xbed5332c, 0xc002c697, 0xbe112251, 0xfe096c8d, 0xbd4f9c30, 0xc00f1c4a, +0xbc90a83f, 0xfc77ae5e, 0xbbd44dd9, 0xc0254e27, 0xbb1a9443, 0xfae67ba2, 0xba6382a6, 0xc04558c0, +0xb9af200f, 0xf9561237, 0xb8fd7373, 0xc06f3726, 0xb84e83ac, 0xf7c6afdc, 0xb7a25779, 0xc0a2e2e3, +0xb6f8f57c, 0xf6389228, 0xb652643e, 0xc0e05401, 0xb5aeaa2a, 0xf4abf67e, 0xb50dcd90, 0xc1278104, +0xb46fd4a4, 0xf3211a07, 0xb3d4c57c, 0xc1785ef4, 0xb33ca614, 0xf19839a6, 0xb2a77c49, 0xc1d2e158, +0xb2154dda, 0xf01191f3, 0xb186206b, 0xc236fa3b, 0xb0f9f981, 0xee8d5f29, 0xb070de82, 0xc2a49a2e, +0xafead4b9, 0xed0bdd25, 0xaf67e14f, 0xc31bb049, 0xaee80952, 0xeb8d475b, 0xae6b51ae, 0xc39c2a2f, +0xadf1bf34, 0xea11d8c8, 0xad7b5692, 0xc425f410, 0xad081c5a, 0xe899cbf1, 0xac9814fd, 0xc4b8f8ad, +0xac2b44cc, 0xe7255ad1, 0xabc1aff9, 0xc555215a, 0xab5b5a96, 0xe5b4bed8, 0xaaf84896, 0xc5fa5603, +0xaa987dca, 0xe44830dd, 0xaa3bfde3, 0xc6a87d2d, 0xa9e2cc73, 0xe2dfe917, 0xa98cece9, 0xc75f7bfe, +0xa93a6296, 0xe17c1f15, 0xa8eb30a7, 0xc81f363d, 0xa89f5a2b, 0xe01d09b4, 0xa856e20e, 0xc8e78e5b, +0xa811cb1b, 0xdec2df18, 0xa7d017fc, 0xc9b86572, 0xa791cb39, 0xdd6dd4a2, 0xa756e73a, 0xca919b4e, +0xa71f6e43, 0xdc1e1ee9, 0xa6eb6279, 0xcb730e70, 0xa6bac5dc, 0xdad3f1b1, 0xa68d9a4c, 0xcc5c9c14, +0xa663e188, 0xd98f7fe6, 0xa63d9d2b, 0xcd4e2037, 0xa61aceaf, 0xd850fb8e, 0xa5fb776b, 0xce47759a, +0xa5df9894, 0xd71895c9, 0xa5c7333e, 0xcf4875ca, 0xa5b2485a, 0xd5e67ec1, 0xa5a0d8b5, 0xd050f926, +0xa592e4fd, 0xd4bae5ab, 0xa5886dba, 0xd160d6e5, 0xa5817354, 0xd395f8ba, 0xa57df60f, 0xd277e518, +/* 1024 - format = Q30 * 2^-10 */ +0xbff3703e, 0xfff36f02, 0xbfda5824, 0xc0000b1a, 0xbfc149ed, 0xffc12b16, 0xbfa845a0, 0xc0003c74, +0xbf8f4b3e, 0xff8ee750, 0xbf765acc, 0xc0009547, 0xbf5d744e, 0xff5ca3d0, 0xbf4497c8, 0xc0011594, +0xbf2bc53d, 0xff2a60b4, 0xbf12fcb2, 0xc001bd5c, 0xbefa3e2a, 0xfef81e1d, 0xbee189a8, 0xc0028c9c, +0xbec8df32, 0xfec5dc28, 0xbeb03eca, 0xc0038356, 0xbe97a875, 0xfe939af5, 0xbe7f1c36, 0xc004a188, +0xbe669a10, 0xfe615aa3, 0xbe4e2209, 0xc005e731, 0xbe35b423, 0xfe2f1b50, 0xbe1d5062, 0xc0075452, +0xbe04f6cb, 0xfdfcdd1d, 0xbdeca760, 0xc008e8e8, 0xbdd46225, 0xfdcaa027, 0xbdbc2720, 0xc00aa4f3, +0xbda3f652, 0xfd98648d, 0xbd8bcfbf, 0xc00c8872, 0xbd73b36d, 0xfd662a70, 0xbd5ba15d, 0xc00e9364, +0xbd439995, 0xfd33f1ed, 0xbd2b9c17, 0xc010c5c7, 0xbd13a8e7, 0xfd01bb24, 0xbcfbc00a, 0xc0131f9b, +0xbce3e182, 0xfccf8634, 0xbccc0d53, 0xc015a0dd, 0xbcb44382, 0xfc9d533b, 0xbc9c8411, 0xc018498c, +0xbc84cf05, 0xfc6b2259, 0xbc6d2461, 0xc01b19a7, 0xbc558428, 0xfc38f3ac, 0xbc3dee5f, 0xc01e112b, +0xbc266309, 0xfc06c754, 0xbc0ee22a, 0xc0213018, 0xbbf76bc4, 0xfbd49d70, 0xbbdfffdd, 0xc024766a, +0xbbc89e77, 0xfba2761e, 0xbbb14796, 0xc027e421, 0xbb99fb3e, 0xfb70517d, 0xbb82b972, 0xc02b7939, +0xbb6b8235, 0xfb3e2fac, 0xbb54558d, 0xc02f35b1, 0xbb3d337b, 0xfb0c10cb, 0xbb261c04, 0xc0331986, +0xbb0f0f2b, 0xfad9f4f8, 0xbaf80cf4, 0xc03724b6, 0xbae11561, 0xfaa7dc52, 0xbaca2878, 0xc03b573f, +0xbab3463b, 0xfa75c6f8, 0xba9c6eae, 0xc03fb11d, 0xba85a1d4, 0xfa43b508, 0xba6edfb1, 0xc044324f, +0xba582849, 0xfa11a6a3, 0xba417b9e, 0xc048dad1, 0xba2ad9b5, 0xf9df9be6, 0xba144291, 0xc04daaa1, +0xb9fdb635, 0xf9ad94f0, 0xb9e734a4, 0xc052a1bb, 0xb9d0bde4, 0xf97b91e1, 0xb9ba51f6, 0xc057c01d, +0xb9a3f0de, 0xf94992d7, 0xb98d9aa0, 0xc05d05c3, 0xb9774f3f, 0xf91797f0, 0xb9610ebe, 0xc06272aa, +0xb94ad922, 0xf8e5a14d, 0xb934ae6d, 0xc06806ce, 0xb91e8ea3, 0xf8b3af0c, 0xb90879c7, 0xc06dc22e, +0xb8f26fdc, 0xf881c14b, 0xb8dc70e7, 0xc073a4c3, 0xb8c67cea, 0xf84fd829, 0xb8b093ea, 0xc079ae8c, +0xb89ab5e8, 0xf81df3c5, 0xb884e2e9, 0xc07fdf85, 0xb86f1af0, 0xf7ec143e, 0xb8595e00, 0xc08637a9, +0xb843ac1d, 0xf7ba39b3, 0xb82e0549, 0xc08cb6f5, 0xb818698a, 0xf7886442, 0xb802d8e0, 0xc0935d64, +0xb7ed5351, 0xf756940a, 0xb7d7d8df, 0xc09a2af3, 0xb7c2698e, 0xf724c92a, 0xb7ad0561, 0xc0a11f9d, +0xb797ac5b, 0xf6f303c0, 0xb7825e80, 0xc0a83b5e, 0xb76d1bd2, 0xf6c143ec, 0xb757e455, 0xc0af7e33, +0xb742b80d, 0xf68f89cb, 0xb72d96fd, 0xc0b6e815, 0xb7188127, 0xf65dd57d, 0xb7037690, 0xc0be7901, +0xb6ee773a, 0xf62c2721, 0xb6d98328, 0xc0c630f2, 0xb6c49a5e, 0xf5fa7ed4, 0xb6afbce0, 0xc0ce0fe3, +0xb69aeab0, 0xf5c8dcb6, 0xb68623d1, 0xc0d615cf, 0xb6716847, 0xf59740e5, 0xb65cb815, 0xc0de42b2, +0xb648133e, 0xf565ab80, 0xb63379c5, 0xc0e69686, 0xb61eebae, 0xf5341ca5, 0xb60a68fb, 0xc0ef1147, +0xb5f5f1b1, 0xf5029473, 0xb5e185d1, 0xc0f7b2ee, 0xb5cd255f, 0xf4d11308, 0xb5b8d05f, 0xc1007b77, +0xb5a486d2, 0xf49f9884, 0xb59048be, 0xc1096add, 0xb57c1624, 0xf46e2504, 0xb567ef08, 0xc1128119, +0xb553d36c, 0xf43cb8a7, 0xb53fc355, 0xc11bbe26, 0xb52bbec4, 0xf40b538b, 0xb517c5be, 0xc12521ff, +0xb503d845, 0xf3d9f5cf, 0xb4eff65c, 0xc12eac9d, 0xb4dc2007, 0xf3a89f92, 0xb4c85548, 0xc1385dfb, +0xb4b49622, 0xf37750f2, 0xb4a0e299, 0xc1423613, 0xb48d3ab0, 0xf3460a0d, 0xb4799e69, 0xc14c34df, +0xb4660dc8, 0xf314cb02, 0xb45288cf, 0xc1565a58, 0xb43f0f82, 0xf2e393ef, 0xb42ba1e4, 0xc160a678, +0xb4183ff7, 0xf2b264f2, 0xb404e9bf, 0xc16b193a, 0xb3f19f3e, 0xf2813e2a, 0xb3de6078, 0xc175b296, +0xb3cb2d70, 0xf2501fb5, 0xb3b80628, 0xc1807285, 0xb3a4eaa4, 0xf21f09b1, 0xb391dae6, 0xc18b5903, +0xb37ed6f1, 0xf1edfc3d, 0xb36bdec9, 0xc1966606, 0xb358f26f, 0xf1bcf777, 0xb34611e8, 0xc1a1998a, +0xb3333d36, 0xf18bfb7d, 0xb320745c, 0xc1acf386, 0xb30db75d, 0xf15b086d, 0xb2fb063b, 0xc1b873f5, +0xb2e860fa, 0xf12a1e66, 0xb2d5c79d, 0xc1c41ace, 0xb2c33a26, 0xf0f93d86, 0xb2b0b898, 0xc1cfe80a, +0xb29e42f6, 0xf0c865ea, 0xb28bd943, 0xc1dbdba3, 0xb2797b82, 0xf09797b2, 0xb26729b5, 0xc1e7f591, +0xb254e3e0, 0xf066d2fa, 0xb242aa05, 0xc1f435cc, 0xb2307c27, 0xf03617e2, 0xb21e5a49, 0xc2009c4e, +0xb20c446d, 0xf0056687, 0xb1fa3a97, 0xc20d290d, 0xb1e83cc9, 0xefd4bf08, 0xb1d64b06, 0xc219dc03, +0xb1c46551, 0xefa42181, 0xb1b28bad, 0xc226b528, 0xb1a0be1b, 0xef738e12, 0xb18efca0, 0xc233b473, +0xb17d473d, 0xef4304d8, 0xb16b9df6, 0xc240d9de, 0xb15a00cd, 0xef1285f2, 0xb1486fc5, 0xc24e255e, +0xb136eae1, 0xeee2117c, 0xb1257223, 0xc25b96ee, 0xb114058e, 0xeeb1a796, 0xb102a524, 0xc2692e83, +0xb0f150e9, 0xee81485c, 0xb0e008e0, 0xc276ec16, 0xb0cecd09, 0xee50f3ed, 0xb0bd9d6a, 0xc284cf9f, +0xb0ac7a03, 0xee20aa67, 0xb09b62d8, 0xc292d914, 0xb08a57eb, 0xedf06be6, 0xb079593f, 0xc2a1086d, +0xb06866d7, 0xedc0388a, 0xb05780b5, 0xc2af5da2, 0xb046a6db, 0xed901070, 0xb035d94e, 0xc2bdd8a9, +0xb025180e, 0xed5ff3b5, 0xb014631e, 0xc2cc7979, 0xb003ba82, 0xed2fe277, 0xaff31e3b, 0xc2db400a, +0xafe28e4d, 0xecffdcd4, 0xafd20ab9, 0xc2ea2c53, 0xafc19383, 0xeccfe2ea, 0xafb128ad, 0xc2f93e4a, +0xafa0ca39, 0xec9ff4d6, 0xaf90782a, 0xc30875e5, 0xaf803283, 0xec7012b5, 0xaf6ff945, 0xc317d31c, +0xaf5fcc74, 0xec403ca5, 0xaf4fac12, 0xc32755e5, 0xaf3f9822, 0xec1072c4, 0xaf2f90a5, 0xc336fe37, +0xaf1f959f, 0xebe0b52f, 0xaf0fa712, 0xc346cc07, 0xaeffc500, 0xebb10404, 0xaeefef6c, 0xc356bf4d, +0xaee02658, 0xeb815f60, 0xaed069c7, 0xc366d7fd, 0xaec0b9bb, 0xeb51c760, 0xaeb11636, 0xc377160f, +0xaea17f3b, 0xeb223c22, 0xae91f4cd, 0xc3877978, 0xae8276ed, 0xeaf2bdc3, 0xae73059f, 0xc398022f, +0xae63a0e3, 0xeac34c60, 0xae5448be, 0xc3a8b028, 0xae44fd31, 0xea93e817, 0xae35be3f, 0xc3b9835a, +0xae268be9, 0xea649105, 0xae176633, 0xc3ca7bba, 0xae084d1f, 0xea354746, 0xadf940ae, 0xc3db993e, +0xadea40e4, 0xea060af9, 0xaddb4dc2, 0xc3ecdbdc, 0xadcc674b, 0xe9d6dc3b, 0xadbd8d82, 0xc3fe4388, +0xadaec067, 0xe9a7bb28, 0xad9fffff, 0xc40fd037, 0xad914c4b, 0xe978a7dd, 0xad82a54c, 0xc42181e0, +0xad740b07, 0xe949a278, 0xad657d7c, 0xc4335877, 0xad56fcaf, 0xe91aab16, 0xad4888a0, 0xc44553f2, +0xad3a2153, 0xe8ebc1d3, 0xad2bc6ca, 0xc4577444, 0xad1d7907, 0xe8bce6cd, 0xad0f380c, 0xc469b963, +0xad0103db, 0xe88e1a20, 0xacf2dc77, 0xc47c2344, 0xace4c1e2, 0xe85f5be9, 0xacd6b41e, 0xc48eb1db, +0xacc8b32c, 0xe830ac45, 0xacbabf10, 0xc4a1651c, 0xacacd7cb, 0xe8020b52, 0xac9efd60, 0xc4b43cfd, +0xac912fd1, 0xe7d3792b, 0xac836f1f, 0xc4c73972, 0xac75bb4d, 0xe7a4f5ed, 0xac68145d, 0xc4da5a6f, +0xac5a7a52, 0xe77681b6, 0xac4ced2c, 0xc4ed9fe7, 0xac3f6cef, 0xe7481ca1, 0xac31f99d, 0xc50109d0, +0xac249336, 0xe719c6cb, 0xac1739bf, 0xc514981d, 0xac09ed38, 0xe6eb8052, 0xabfcada3, 0xc5284ac3, +0xabef7b04, 0xe6bd4951, 0xabe2555b, 0xc53c21b4, 0xabd53caa, 0xe68f21e5, 0xabc830f5, 0xc5501ce5, +0xabbb323c, 0xe6610a2a, 0xabae4082, 0xc5643c4a, 0xaba15bc9, 0xe633023e, 0xab948413, 0xc5787fd6, +0xab87b962, 0xe6050a3b, 0xab7afbb7, 0xc58ce77c, 0xab6e4b15, 0xe5d72240, 0xab61a77d, 0xc5a17330, +0xab5510f3, 0xe5a94a67, 0xab488776, 0xc5b622e6, 0xab3c0b0b, 0xe57b82cd, 0xab2f9bb1, 0xc5caf690, +0xab23396c, 0xe54dcb8f, 0xab16e43d, 0xc5dfee22, 0xab0a9c27, 0xe52024c9, 0xaafe612a, 0xc5f5098f, +0xaaf23349, 0xe4f28e96, 0xaae61286, 0xc60a48c9, 0xaad9fee3, 0xe4c50914, 0xaacdf861, 0xc61fabc4, +0xaac1ff03, 0xe497945d, 0xaab612ca, 0xc6353273, 0xaaaa33b8, 0xe46a308f, 0xaa9e61cf, 0xc64adcc7, +0xaa929d10, 0xe43cddc4, 0xaa86e57e, 0xc660aab5, 0xaa7b3b1b, 0xe40f9c1a, 0xaa6f9de7, 0xc6769c2e, +0xaa640de6, 0xe3e26bac, 0xaa588b18, 0xc68cb124, 0xaa4d157f, 0xe3b54c95, 0xaa41ad1e, 0xc6a2e98b, +0xaa3651f6, 0xe3883ef2, 0xaa2b0409, 0xc6b94554, 0xaa1fc358, 0xe35b42df, 0xaa148fe6, 0xc6cfc472, +0xaa0969b3, 0xe32e5876, 0xa9fe50c2, 0xc6e666d7, 0xa9f34515, 0xe3017fd5, 0xa9e846ad, 0xc6fd2c75, +0xa9dd558b, 0xe2d4b916, 0xa9d271b2, 0xc714153e, 0xa9c79b23, 0xe2a80456, 0xa9bcd1e0, 0xc72b2123, +0xa9b215ea, 0xe27b61af, 0xa9a76744, 0xc7425016, 0xa99cc5ee, 0xe24ed13d, 0xa99231eb, 0xc759a20a, +0xa987ab3c, 0xe222531c, 0xa97d31e3, 0xc77116f0, 0xa972c5e1, 0xe1f5e768, 0xa9686738, 0xc788aeb9, +0xa95e15e9, 0xe1c98e3b, 0xa953d1f7, 0xc7a06957, 0xa9499b62, 0xe19d47b1, 0xa93f722c, 0xc7b846ba, +0xa9355658, 0xe17113e5, 0xa92b47e5, 0xc7d046d6, 0xa92146d7, 0xe144f2f3, 0xa917532e, 0xc7e8699a, +0xa90d6cec, 0xe118e4f6, 0xa9039413, 0xc800aef7, 0xa8f9c8a4, 0xe0ecea09, 0xa8f00aa0, 0xc81916df, +0xa8e65a0a, 0xe0c10247, 0xa8dcb6e2, 0xc831a143, 0xa8d3212a, 0xe0952dcb, 0xa8c998e3, 0xc84a4e14, +0xa8c01e10, 0xe0696cb0, 0xa8b6b0b1, 0xc8631d42, 0xa8ad50c8, 0xe03dbf11, 0xa8a3fe57, 0xc87c0ebd, +0xa89ab95e, 0xe012250a, 0xa89181df, 0xc8952278, 0xa88857dc, 0xdfe69eb4, 0xa87f3b57, 0xc8ae5862, +0xa8762c4f, 0xdfbb2c2c, 0xa86d2ac8, 0xc8c7b06b, 0xa86436c2, 0xdf8fcd8b, 0xa85b503e, 0xc8e12a84, +0xa852773f, 0xdf6482ed, 0xa849abc4, 0xc8fac69e, 0xa840edd1, 0xdf394c6b, 0xa8383d66, 0xc91484a8, +0xa82f9a84, 0xdf0e2a22, 0xa827052d, 0xc92e6492, 0xa81e7d62, 0xdee31c2b, 0xa8160324, 0xc948664d, +0xa80d9675, 0xdeb822a1, 0xa8053756, 0xc96289c9, 0xa7fce5c9, 0xde8d3d9e, 0xa7f4a1ce, 0xc97ccef5, +0xa7ec6b66, 0xde626d3e, 0xa7e44294, 0xc99735c2, 0xa7dc2759, 0xde37b199, 0xa7d419b4, 0xc9b1be1e, +0xa7cc19a9, 0xde0d0acc, 0xa7c42738, 0xc9cc67fa, 0xa7bc4262, 0xdde278ef, 0xa7b46b29, 0xc9e73346, +0xa7aca18e, 0xddb7fc1e, 0xa7a4e591, 0xca021fef, 0xa79d3735, 0xdd8d9472, 0xa795967a, 0xca1d2de7, +0xa78e0361, 0xdd634206, 0xa7867dec, 0xca385d1d, 0xa77f061c, 0xdd3904f4, 0xa7779bf2, 0xca53ad7e, +0xa7703f70, 0xdd0edd55, 0xa768f095, 0xca6f1efc, 0xa761af64, 0xdce4cb44, 0xa75a7bdd, 0xca8ab184, +0xa7535602, 0xdcbacedb, 0xa74c3dd4, 0xcaa66506, 0xa7453353, 0xdc90e834, 0xa73e3681, 0xcac23971, +0xa7374760, 0xdc671768, 0xa73065ef, 0xcade2eb3, 0xa7299231, 0xdc3d5c91, 0xa722cc25, 0xcafa44bc, +0xa71c13ce, 0xdc13b7c9, 0xa715692c, 0xcb167b79, 0xa70ecc41, 0xdbea292b, 0xa7083d0d, 0xcb32d2da, +0xa701bb91, 0xdbc0b0ce, 0xa6fb47ce, 0xcb4f4acd, 0xa6f4e1c6, 0xdb974ece, 0xa6ee8979, 0xcb6be341, +0xa6e83ee8, 0xdb6e0342, 0xa6e20214, 0xcb889c23, 0xa6dbd2ff, 0xdb44ce46, 0xa6d5b1a9, 0xcba57563, +0xa6cf9e13, 0xdb1baff2, 0xa6c9983e, 0xcbc26eee, 0xa6c3a02b, 0xdaf2a860, 0xa6bdb5da, 0xcbdf88b3, +0xa6b7d94e, 0xdac9b7a9, 0xa6b20a86, 0xcbfcc29f, 0xa6ac4984, 0xdaa0dde7, 0xa6a69649, 0xcc1a1ca0, +0xa6a0f0d5, 0xda781b31, 0xa69b5929, 0xcc3796a5, 0xa695cf46, 0xda4f6fa3, 0xa690532d, 0xcc55309b, +0xa68ae4df, 0xda26db54, 0xa685845c, 0xcc72ea70, 0xa68031a6, 0xd9fe5e5e, 0xa67aecbd, 0xcc90c412, +0xa675b5a3, 0xd9d5f8d9, 0xa6708c57, 0xccaebd6e, 0xa66b70db, 0xd9adaadf, 0xa6666330, 0xccccd671, +0xa6616355, 0xd9857489, 0xa65c714d, 0xcceb0f0a, 0xa6578d18, 0xd95d55ef, 0xa652b6b6, 0xcd096725, +0xa64dee28, 0xd9354f2a, 0xa6493370, 0xcd27deb0, 0xa644868d, 0xd90d6053, 0xa63fe781, 0xcd467599, +0xa63b564c, 0xd8e58982, 0xa636d2ee, 0xcd652bcb, 0xa6325d6a, 0xd8bdcad0, 0xa62df5bf, 0xcd840134, +0xa6299bed, 0xd8962456, 0xa6254ff7, 0xcda2f5c2, 0xa62111db, 0xd86e962b, 0xa61ce19c, 0xcdc20960, +0xa618bf39, 0xd8472069, 0xa614aab3, 0xcde13bfd, 0xa610a40c, 0xd81fc328, 0xa60cab43, 0xce008d84, +0xa608c058, 0xd7f87e7f, 0xa604e34e, 0xce1ffde2, 0xa6011424, 0xd7d15288, 0xa5fd52db, 0xce3f8d05, +0xa5f99f73, 0xd7aa3f5a, 0xa5f5f9ed, 0xce5f3ad8, 0xa5f2624a, 0xd783450d, 0xa5eed88a, 0xce7f0748, +0xa5eb5cae, 0xd75c63ba, 0xa5e7eeb6, 0xce9ef241, 0xa5e48ea3, 0xd7359b78, 0xa5e13c75, 0xcebefbb0, +0xa5ddf82d, 0xd70eec60, 0xa5dac1cb, 0xcedf2380, 0xa5d79950, 0xd6e85689, 0xa5d47ebc, 0xceff699f, +0xa5d17210, 0xd6c1da0b, 0xa5ce734d, 0xcf1fcdf8, 0xa5cb8272, 0xd69b76fe, 0xa5c89f80, 0xcf405077, +0xa5c5ca77, 0xd6752d79, 0xa5c30359, 0xcf60f108, 0xa5c04a25, 0xd64efd94, 0xa5bd9edc, 0xcf81af97, +0xa5bb017f, 0xd628e767, 0xa5b8720d, 0xcfa28c10, 0xa5b5f087, 0xd602eb0a, 0xa5b37cee, 0xcfc3865e, +0xa5b11741, 0xd5dd0892, 0xa5aebf82, 0xcfe49e6d, 0xa5ac75b0, 0xd5b74019, 0xa5aa39cd, 0xd005d42a, +0xa5a80bd7, 0xd59191b5, 0xa5a5ebd0, 0xd027277e, 0xa5a3d9b8, 0xd56bfd7d, 0xa5a1d590, 0xd0489856, +0xa59fdf57, 0xd5468389, 0xa59df70e, 0xd06a269d, 0xa59c1cb5, 0xd52123f0, 0xa59a504c, 0xd08bd23f, +0xa59891d4, 0xd4fbdec9, 0xa596e14e, 0xd0ad9b26, 0xa5953eb8, 0xd4d6b42b, 0xa593aa14, 0xd0cf813e, +0xa5922362, 0xd4b1a42c, 0xa590aaa2, 0xd0f18472, 0xa58f3fd4, 0xd48caee4, 0xa58de2f8, 0xd113a4ad, +0xa58c940f, 0xd467d469, 0xa58b5319, 0xd135e1d9, 0xa58a2016, 0xd44314d3, 0xa588fb06, 0xd1583be2, +0xa587e3ea, 0xd41e7037, 0xa586dac1, 0xd17ab2b3, 0xa585df8c, 0xd3f9e6ad, 0xa584f24b, 0xd19d4636, +0xa58412fe, 0xd3d5784a, 0xa58341a5, 0xd1bff656, 0xa5827e40, 0xd3b12526, 0xa581c8d0, 0xd1e2c2fd, +0xa5812154, 0xd38ced57, 0xa58087cd, 0xd205ac17, 0xa57ffc3b, 0xd368d0f3, 0xa57f7e9d, 0xd228b18d, +0xa57f0ef5, 0xd344d011, 0xa57ead41, 0xd24bd34a, 0xa57e5982, 0xd320eac6, 0xa57e13b8, 0xd26f1138, +0xa57ddbe4, 0xd2fd2129, 0xa57db204, 0xd2926b41, 0xa57d961a, 0xd2d97350, 0xa57d8825, 0xd2b5e151, +}; + +const int32_t cos1sin1tab[514] PROGMEM = { +/* format = Q30 */ +0x40000000, 0x00000000, 0x40323034, 0x003243f1, 0x406438cf, 0x006487c4, 0x409619b2, 0x0096cb58, +0x40c7d2bd, 0x00c90e90, 0x40f963d3, 0x00fb514b, 0x412accd4, 0x012d936c, 0x415c0da3, 0x015fd4d2, +0x418d2621, 0x0192155f, 0x41be162f, 0x01c454f5, 0x41eeddaf, 0x01f69373, 0x421f7c84, 0x0228d0bb, +0x424ff28f, 0x025b0caf, 0x42803fb2, 0x028d472e, 0x42b063d0, 0x02bf801a, 0x42e05ecb, 0x02f1b755, +0x43103085, 0x0323ecbe, 0x433fd8e1, 0x03562038, 0x436f57c1, 0x038851a2, 0x439ead09, 0x03ba80df, +0x43cdd89a, 0x03ecadcf, 0x43fcda59, 0x041ed854, 0x442bb227, 0x0451004d, 0x445a5fe8, 0x0483259d, +0x4488e37f, 0x04b54825, 0x44b73ccf, 0x04e767c5, 0x44e56bbd, 0x0519845e, 0x4513702a, 0x054b9dd3, +0x454149fc, 0x057db403, 0x456ef916, 0x05afc6d0, 0x459c7d5a, 0x05e1d61b, 0x45c9d6af, 0x0613e1c5, +0x45f704f7, 0x0645e9af, 0x46240816, 0x0677edbb, 0x4650dff1, 0x06a9edc9, 0x467d8c6d, 0x06dbe9bb, +0x46aa0d6d, 0x070de172, 0x46d662d6, 0x073fd4cf, 0x47028c8d, 0x0771c3b3, 0x472e8a76, 0x07a3adff, +0x475a5c77, 0x07d59396, 0x47860275, 0x08077457, 0x47b17c54, 0x08395024, 0x47dcc9f9, 0x086b26de, +0x4807eb4b, 0x089cf867, 0x4832e02d, 0x08cec4a0, 0x485da887, 0x09008b6a, 0x4888443d, 0x09324ca7, +0x48b2b335, 0x09640837, 0x48dcf556, 0x0995bdfd, 0x49070a84, 0x09c76dd8, 0x4930f2a6, 0x09f917ac, +0x495aada2, 0x0a2abb59, 0x49843b5f, 0x0a5c58c0, 0x49ad9bc2, 0x0a8defc3, 0x49d6ceb3, 0x0abf8043, +0x49ffd417, 0x0af10a22, 0x4a28abd6, 0x0b228d42, 0x4a5155d6, 0x0b540982, 0x4a79d1ff, 0x0b857ec7, +0x4aa22036, 0x0bb6ecef, 0x4aca4065, 0x0be853de, 0x4af23270, 0x0c19b374, 0x4b19f641, 0x0c4b0b94, +0x4b418bbe, 0x0c7c5c1e, 0x4b68f2cf, 0x0cada4f5, 0x4b902b5c, 0x0cdee5f9, 0x4bb7354d, 0x0d101f0e, +0x4bde1089, 0x0d415013, 0x4c04bcf8, 0x0d7278eb, 0x4c2b3a84, 0x0da39978, 0x4c518913, 0x0dd4b19a, +0x4c77a88e, 0x0e05c135, 0x4c9d98de, 0x0e36c82a, 0x4cc359ec, 0x0e67c65a, 0x4ce8eb9f, 0x0e98bba7, +0x4d0e4de2, 0x0ec9a7f3, 0x4d33809c, 0x0efa8b20, 0x4d5883b7, 0x0f2b650f, 0x4d7d571c, 0x0f5c35a3, +0x4da1fab5, 0x0f8cfcbe, 0x4dc66e6a, 0x0fbdba40, 0x4deab226, 0x0fee6e0d, 0x4e0ec5d1, 0x101f1807, +0x4e32a956, 0x104fb80e, 0x4e565c9f, 0x10804e06, 0x4e79df95, 0x10b0d9d0, 0x4e9d3222, 0x10e15b4e, +0x4ec05432, 0x1111d263, 0x4ee345ad, 0x11423ef0, 0x4f06067f, 0x1172a0d7, 0x4f289692, 0x11a2f7fc, +0x4f4af5d1, 0x11d3443f, 0x4f6d2427, 0x12038584, 0x4f8f217e, 0x1233bbac, 0x4fb0edc1, 0x1263e699, +0x4fd288dc, 0x1294062f, 0x4ff3f2bb, 0x12c41a4f, 0x50152b47, 0x12f422db, 0x5036326e, 0x13241fb6, +0x50570819, 0x135410c3, 0x5077ac37, 0x1383f5e3, 0x50981eb1, 0x13b3cefa, 0x50b85f74, 0x13e39be9, +0x50d86e6d, 0x14135c94, 0x50f84b87, 0x144310dd, 0x5117f6ae, 0x1472b8a5, 0x51376fd0, 0x14a253d1, +0x5156b6d9, 0x14d1e242, 0x5175cbb5, 0x150163dc, 0x5194ae52, 0x1530d881, 0x51b35e9b, 0x15604013, +0x51d1dc80, 0x158f9a76, 0x51f027eb, 0x15bee78c, 0x520e40cc, 0x15ee2738, 0x522c270f, 0x161d595d, +0x5249daa2, 0x164c7ddd, 0x52675b72, 0x167b949d, 0x5284a96e, 0x16aa9d7e, 0x52a1c482, 0x16d99864, +0x52beac9f, 0x17088531, 0x52db61b0, 0x173763c9, 0x52f7e3a6, 0x1766340f, 0x5314326d, 0x1794f5e6, +0x53304df6, 0x17c3a931, 0x534c362d, 0x17f24dd3, 0x5367eb03, 0x1820e3b0, 0x53836c66, 0x184f6aab, +0x539eba45, 0x187de2a7, 0x53b9d48f, 0x18ac4b87, 0x53d4bb34, 0x18daa52f, 0x53ef6e23, 0x1908ef82, +0x5409ed4b, 0x19372a64, 0x5424389d, 0x196555b8, 0x543e5007, 0x19937161, 0x5458337a, 0x19c17d44, +0x5471e2e6, 0x19ef7944, 0x548b5e3b, 0x1a1d6544, 0x54a4a56a, 0x1a4b4128, 0x54bdb862, 0x1a790cd4, +0x54d69714, 0x1aa6c82b, 0x54ef4171, 0x1ad47312, 0x5507b76a, 0x1b020d6c, 0x551ff8ef, 0x1b2f971e, +0x553805f2, 0x1b5d100a, 0x554fde64, 0x1b8a7815, 0x55678236, 0x1bb7cf23, 0x557ef15a, 0x1be51518, +0x55962bc0, 0x1c1249d8, 0x55ad315b, 0x1c3f6d47, 0x55c4021d, 0x1c6c7f4a, 0x55da9df7, 0x1c997fc4, +0x55f104dc, 0x1cc66e99, 0x560736bd, 0x1cf34baf, 0x561d338d, 0x1d2016e9, 0x5632fb3f, 0x1d4cd02c, +0x56488dc5, 0x1d79775c, 0x565deb11, 0x1da60c5d, 0x56731317, 0x1dd28f15, 0x568805c9, 0x1dfeff67, +0x569cc31b, 0x1e2b5d38, 0x56b14b00, 0x1e57a86d, 0x56c59d6a, 0x1e83e0eb, 0x56d9ba4e, 0x1eb00696, +0x56eda1a0, 0x1edc1953, 0x57015352, 0x1f081907, 0x5714cf59, 0x1f340596, 0x572815a8, 0x1f5fdee6, +0x573b2635, 0x1f8ba4dc, 0x574e00f2, 0x1fb7575c, 0x5760a5d5, 0x1fe2f64c, 0x577314d2, 0x200e8190, +0x57854ddd, 0x2039f90f, 0x579750ec, 0x20655cac, 0x57a91df2, 0x2090ac4d, 0x57bab4e6, 0x20bbe7d8, +0x57cc15bc, 0x20e70f32, 0x57dd406a, 0x21122240, 0x57ee34e5, 0x213d20e8, 0x57fef323, 0x21680b0f, +0x580f7b19, 0x2192e09b, 0x581fccbc, 0x21bda171, 0x582fe804, 0x21e84d76, 0x583fcce6, 0x2212e492, +0x584f7b58, 0x223d66a8, 0x585ef351, 0x2267d3a0, 0x586e34c7, 0x22922b5e, 0x587d3fb0, 0x22bc6dca, +0x588c1404, 0x22e69ac8, 0x589ab1b9, 0x2310b23e, 0x58a918c6, 0x233ab414, 0x58b74923, 0x2364a02e, +0x58c542c5, 0x238e7673, 0x58d305a6, 0x23b836ca, 0x58e091bd, 0x23e1e117, 0x58ede700, 0x240b7543, +0x58fb0568, 0x2434f332, 0x5907eced, 0x245e5acc, 0x59149d87, 0x2487abf7, 0x5921172e, 0x24b0e699, +0x592d59da, 0x24da0a9a, 0x59396584, 0x250317df, 0x59453a24, 0x252c0e4f, 0x5950d7b3, 0x2554edd1, +0x595c3e2a, 0x257db64c, 0x59676d82, 0x25a667a7, 0x597265b4, 0x25cf01c8, 0x597d26b8, 0x25f78497, +0x5987b08a, 0x261feffa, 0x59920321, 0x264843d9, 0x599c1e78, 0x2670801a, 0x59a60288, 0x2698a4a6, +0x59afaf4c, 0x26c0b162, 0x59b924bc, 0x26e8a637, 0x59c262d5, 0x2710830c, 0x59cb698f, 0x273847c8, +0x59d438e5, 0x275ff452, 0x59dcd0d3, 0x27878893, 0x59e53151, 0x27af0472, 0x59ed5a5c, 0x27d667d5, +0x59f54bee, 0x27fdb2a7, 0x59fd0603, 0x2824e4cc, 0x5a048895, 0x284bfe2f, 0x5a0bd3a1, 0x2872feb6, +0x5a12e720, 0x2899e64a, 0x5a19c310, 0x28c0b4d2, 0x5a20676c, 0x28e76a37, 0x5a26d42f, 0x290e0661, +0x5a2d0957, 0x29348937, 0x5a3306de, 0x295af2a3, 0x5a38ccc2, 0x2981428c, 0x5a3e5afe, 0x29a778db, +0x5a43b190, 0x29cd9578, 0x5a48d074, 0x29f3984c, 0x5a4db7a6, 0x2a19813f, 0x5a526725, 0x2a3f503a, +0x5a56deec, 0x2a650525, 0x5a5b1efa, 0x2a8a9fea, 0x5a5f274b, 0x2ab02071, 0x5a62f7dd, 0x2ad586a3, +0x5a6690ae, 0x2afad269, 0x5a69f1bb, 0x2b2003ac, 0x5a6d1b03, 0x2b451a55, 0x5a700c84, 0x2b6a164d, +0x5a72c63b, 0x2b8ef77d, 0x5a754827, 0x2bb3bdce, 0x5a779246, 0x2bd8692b, 0x5a79a498, 0x2bfcf97c, +0x5a7b7f1a, 0x2c216eaa, 0x5a7d21cc, 0x2c45c8a0, 0x5a7e8cac, 0x2c6a0746, 0x5a7fbfbb, 0x2c8e2a87, +0x5a80baf6, 0x2cb2324c, 0x5a817e5d, 0x2cd61e7f, 0x5a8209f1, 0x2cf9ef09, 0x5a825db0, 0x2d1da3d5, +0x5a82799a, 0x2d413ccd, +}; + +const uint8_t sinWindowOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 128}; + +const int32_t sinWindow[128 + 1024] PROGMEM = { +/* 128 - format = Q31 * 2^0 */ +0x00c90f88, 0x7fff6216, 0x025b26d7, 0x7ffa72d1, 0x03ed26e6, 0x7ff09478, 0x057f0035, 0x7fe1c76b, +0x0710a345, 0x7fce0c3e, 0x08a2009a, 0x7fb563b3, 0x0a3308bd, 0x7f97cebd, 0x0bc3ac35, 0x7f754e80, +0x0d53db92, 0x7f4de451, 0x0ee38766, 0x7f2191b4, 0x1072a048, 0x7ef05860, 0x120116d5, 0x7eba3a39, +0x138edbb1, 0x7e7f3957, 0x151bdf86, 0x7e3f57ff, 0x16a81305, 0x7dfa98a8, 0x183366e9, 0x7db0fdf8, +0x19bdcbf3, 0x7d628ac6, 0x1b4732ef, 0x7d0f4218, 0x1ccf8cb3, 0x7cb72724, 0x1e56ca1e, 0x7c5a3d50, +0x1fdcdc1b, 0x7bf88830, 0x2161b3a0, 0x7b920b89, 0x22e541af, 0x7b26cb4f, 0x24677758, 0x7ab6cba4, +0x25e845b6, 0x7a4210d8, 0x27679df4, 0x79c89f6e, 0x28e5714b, 0x794a7c12, 0x2a61b101, 0x78c7aba2, +0x2bdc4e6f, 0x78403329, 0x2d553afc, 0x77b417df, 0x2ecc681e, 0x77235f2d, 0x3041c761, 0x768e0ea6, +0x31b54a5e, 0x75f42c0b, 0x3326e2c3, 0x7555bd4c, 0x34968250, 0x74b2c884, 0x36041ad9, 0x740b53fb, +0x376f9e46, 0x735f6626, 0x38d8fe93, 0x72af05a7, 0x3a402dd2, 0x71fa3949, 0x3ba51e29, 0x71410805, +0x3d07c1d6, 0x708378ff, 0x3e680b2c, 0x6fc19385, 0x3fc5ec98, 0x6efb5f12, 0x4121589b, 0x6e30e34a, +0x427a41d0, 0x6d6227fa, 0x43d09aed, 0x6c8f351c, 0x452456bd, 0x6bb812d1, 0x46756828, 0x6adcc964, +0x47c3c22f, 0x69fd614a, 0x490f57ee, 0x6919e320, 0x4a581c9e, 0x683257ab, 0x4b9e0390, 0x6746c7d8, +0x4ce10034, 0x66573cbb, 0x4e210617, 0x6563bf92, 0x4f5e08e3, 0x646c59bf, 0x5097fc5e, 0x637114cc, +0x51ced46e, 0x6271fa69, 0x53028518, 0x616f146c, 0x5433027d, 0x60686ccf, 0x556040e2, 0x5f5e0db3, +0x568a34a9, 0x5e50015d, 0x57b0d256, 0x5d3e5237, 0x58d40e8c, 0x5c290acc, 0x59f3de12, 0x5b1035cf, +/* 1024 - format = Q31 * 2^0 */ +0x001921fb, 0x7ffffd88, 0x004b65ee, 0x7fffe9cb, 0x007da9d4, 0x7fffc251, 0x00afeda8, 0x7fff8719, +0x00e23160, 0x7fff3824, 0x011474f6, 0x7ffed572, 0x0146b860, 0x7ffe5f03, 0x0178fb99, 0x7ffdd4d7, +0x01ab3e97, 0x7ffd36ee, 0x01dd8154, 0x7ffc8549, 0x020fc3c6, 0x7ffbbfe6, 0x024205e8, 0x7ffae6c7, +0x027447b0, 0x7ff9f9ec, 0x02a68917, 0x7ff8f954, 0x02d8ca16, 0x7ff7e500, 0x030b0aa4, 0x7ff6bcf0, +0x033d4abb, 0x7ff58125, 0x036f8a51, 0x7ff4319d, 0x03a1c960, 0x7ff2ce5b, 0x03d407df, 0x7ff1575d, +0x040645c7, 0x7fefcca4, 0x04388310, 0x7fee2e30, 0x046abfb3, 0x7fec7c02, 0x049cfba7, 0x7feab61a, +0x04cf36e5, 0x7fe8dc78, 0x05017165, 0x7fe6ef1c, 0x0533ab20, 0x7fe4ee06, 0x0565e40d, 0x7fe2d938, +0x05981c26, 0x7fe0b0b1, 0x05ca5361, 0x7fde7471, 0x05fc89b8, 0x7fdc247a, 0x062ebf22, 0x7fd9c0ca, +0x0660f398, 0x7fd74964, 0x06932713, 0x7fd4be46, 0x06c5598a, 0x7fd21f72, 0x06f78af6, 0x7fcf6ce8, +0x0729bb4e, 0x7fcca6a7, 0x075bea8c, 0x7fc9ccb2, 0x078e18a7, 0x7fc6df08, 0x07c04598, 0x7fc3dda9, +0x07f27157, 0x7fc0c896, 0x08249bdd, 0x7fbd9fd0, 0x0856c520, 0x7fba6357, 0x0888ed1b, 0x7fb7132b, +0x08bb13c5, 0x7fb3af4e, 0x08ed3916, 0x7fb037bf, 0x091f5d06, 0x7facac7f, 0x09517f8f, 0x7fa90d8e, +0x0983a0a7, 0x7fa55aee, 0x09b5c048, 0x7fa1949e, 0x09e7de6a, 0x7f9dbaa0, 0x0a19fb04, 0x7f99ccf4, +0x0a4c1610, 0x7f95cb9a, 0x0a7e2f85, 0x7f91b694, 0x0ab0475c, 0x7f8d8de1, 0x0ae25d8d, 0x7f895182, +0x0b147211, 0x7f850179, 0x0b4684df, 0x7f809dc5, 0x0b7895f0, 0x7f7c2668, 0x0baaa53b, 0x7f779b62, +0x0bdcb2bb, 0x7f72fcb4, 0x0c0ebe66, 0x7f6e4a5e, 0x0c40c835, 0x7f698461, 0x0c72d020, 0x7f64aabf, +0x0ca4d620, 0x7f5fbd77, 0x0cd6da2d, 0x7f5abc8a, 0x0d08dc3f, 0x7f55a7fa, 0x0d3adc4e, 0x7f507fc7, +0x0d6cda53, 0x7f4b43f2, 0x0d9ed646, 0x7f45f47b, 0x0dd0d01f, 0x7f409164, 0x0e02c7d7, 0x7f3b1aad, +0x0e34bd66, 0x7f359057, 0x0e66b0c3, 0x7f2ff263, 0x0e98a1e9, 0x7f2a40d2, 0x0eca90ce, 0x7f247ba5, +0x0efc7d6b, 0x7f1ea2dc, 0x0f2e67b8, 0x7f18b679, 0x0f604faf, 0x7f12b67c, 0x0f923546, 0x7f0ca2e7, +0x0fc41876, 0x7f067bba, 0x0ff5f938, 0x7f0040f6, 0x1027d784, 0x7ef9f29d, 0x1059b352, 0x7ef390ae, +0x108b8c9b, 0x7eed1b2c, 0x10bd6356, 0x7ee69217, 0x10ef377d, 0x7edff570, 0x11210907, 0x7ed94538, +0x1152d7ed, 0x7ed28171, 0x1184a427, 0x7ecbaa1a, 0x11b66dad, 0x7ec4bf36, 0x11e83478, 0x7ebdc0c6, +0x1219f880, 0x7eb6aeca, 0x124bb9be, 0x7eaf8943, 0x127d7829, 0x7ea85033, 0x12af33ba, 0x7ea1039b, +0x12e0ec6a, 0x7e99a37c, 0x1312a230, 0x7e922fd6, 0x13445505, 0x7e8aa8ac, 0x137604e2, 0x7e830dff, +0x13a7b1bf, 0x7e7b5fce, 0x13d95b93, 0x7e739e1d, 0x140b0258, 0x7e6bc8eb, 0x143ca605, 0x7e63e03b, +0x146e4694, 0x7e5be40c, 0x149fe3fc, 0x7e53d462, 0x14d17e36, 0x7e4bb13c, 0x1503153a, 0x7e437a9c, +0x1534a901, 0x7e3b3083, 0x15663982, 0x7e32d2f4, 0x1597c6b7, 0x7e2a61ed, 0x15c95097, 0x7e21dd73, +0x15fad71b, 0x7e194584, 0x162c5a3b, 0x7e109a24, 0x165dd9f0, 0x7e07db52, 0x168f5632, 0x7dff0911, +0x16c0cef9, 0x7df62362, 0x16f2443e, 0x7ded2a47, 0x1723b5f9, 0x7de41dc0, 0x17552422, 0x7ddafdce, +0x17868eb3, 0x7dd1ca75, 0x17b7f5a3, 0x7dc883b4, 0x17e958ea, 0x7dbf298d, 0x181ab881, 0x7db5bc02, +0x184c1461, 0x7dac3b15, 0x187d6c82, 0x7da2a6c6, 0x18aec0db, 0x7d98ff17, 0x18e01167, 0x7d8f4409, +0x19115e1c, 0x7d85759f, 0x1942a6f3, 0x7d7b93da, 0x1973ebe6, 0x7d719eba, 0x19a52ceb, 0x7d679642, +0x19d669fc, 0x7d5d7a74, 0x1a07a311, 0x7d534b50, 0x1a38d823, 0x7d4908d9, 0x1a6a0929, 0x7d3eb30f, +0x1a9b361d, 0x7d3449f5, 0x1acc5ef6, 0x7d29cd8c, 0x1afd83ad, 0x7d1f3dd6, 0x1b2ea43a, 0x7d149ad5, +0x1b5fc097, 0x7d09e489, 0x1b90d8bb, 0x7cff1af5, 0x1bc1ec9e, 0x7cf43e1a, 0x1bf2fc3a, 0x7ce94dfb, +0x1c240786, 0x7cde4a98, 0x1c550e7c, 0x7cd333f3, 0x1c861113, 0x7cc80a0f, 0x1cb70f43, 0x7cbcccec, +0x1ce80906, 0x7cb17c8d, 0x1d18fe54, 0x7ca618f3, 0x1d49ef26, 0x7c9aa221, 0x1d7adb73, 0x7c8f1817, +0x1dabc334, 0x7c837ad8, 0x1ddca662, 0x7c77ca65, 0x1e0d84f5, 0x7c6c06c0, 0x1e3e5ee5, 0x7c602fec, +0x1e6f342c, 0x7c5445e9, 0x1ea004c1, 0x7c4848ba, 0x1ed0d09d, 0x7c3c3860, 0x1f0197b8, 0x7c3014de, +0x1f325a0b, 0x7c23de35, 0x1f63178f, 0x7c179467, 0x1f93d03c, 0x7c0b3777, 0x1fc4840a, 0x7bfec765, +0x1ff532f2, 0x7bf24434, 0x2025dcec, 0x7be5ade6, 0x205681f1, 0x7bd9047c, 0x208721f9, 0x7bcc47fa, +0x20b7bcfe, 0x7bbf7860, 0x20e852f6, 0x7bb295b0, 0x2118e3dc, 0x7ba59fee, 0x21496fa7, 0x7b989719, +0x2179f64f, 0x7b8b7b36, 0x21aa77cf, 0x7b7e4c45, 0x21daf41d, 0x7b710a49, 0x220b6b32, 0x7b63b543, +0x223bdd08, 0x7b564d36, 0x226c4996, 0x7b48d225, 0x229cb0d5, 0x7b3b4410, 0x22cd12bd, 0x7b2da2fa, +0x22fd6f48, 0x7b1feee5, 0x232dc66d, 0x7b1227d3, 0x235e1826, 0x7b044dc7, 0x238e646a, 0x7af660c2, +0x23beab33, 0x7ae860c7, 0x23eeec78, 0x7ada4dd8, 0x241f2833, 0x7acc27f7, 0x244f5e5c, 0x7abdef25, +0x247f8eec, 0x7aafa367, 0x24afb9da, 0x7aa144bc, 0x24dfdf20, 0x7a92d329, 0x250ffeb7, 0x7a844eae, +0x25401896, 0x7a75b74f, 0x25702cb7, 0x7a670d0d, 0x25a03b11, 0x7a584feb, 0x25d0439f, 0x7a497feb, +0x26004657, 0x7a3a9d0f, 0x26304333, 0x7a2ba75a, 0x26603a2c, 0x7a1c9ece, 0x26902b39, 0x7a0d836d, +0x26c01655, 0x79fe5539, 0x26effb76, 0x79ef1436, 0x271fda96, 0x79dfc064, 0x274fb3ae, 0x79d059c8, +0x277f86b5, 0x79c0e062, 0x27af53a6, 0x79b15435, 0x27df1a77, 0x79a1b545, 0x280edb23, 0x79920392, +0x283e95a1, 0x79823f20, 0x286e49ea, 0x797267f2, 0x289df7f8, 0x79627e08, 0x28cd9fc1, 0x79528167, +0x28fd4140, 0x79427210, 0x292cdc6d, 0x79325006, 0x295c7140, 0x79221b4b, 0x298bffb2, 0x7911d3e2, +0x29bb87bc, 0x790179cd, 0x29eb0957, 0x78f10d0f, 0x2a1a847b, 0x78e08dab, 0x2a49f920, 0x78cffba3, +0x2a796740, 0x78bf56f9, 0x2aa8ced3, 0x78ae9fb0, 0x2ad82fd2, 0x789dd5cb, 0x2b078a36, 0x788cf94c, +0x2b36ddf7, 0x787c0a36, 0x2b662b0e, 0x786b088c, 0x2b957173, 0x7859f44f, 0x2bc4b120, 0x7848cd83, +0x2bf3ea0d, 0x7837942b, 0x2c231c33, 0x78264849, 0x2c52478a, 0x7814e9df, 0x2c816c0c, 0x780378f1, +0x2cb089b1, 0x77f1f581, 0x2cdfa071, 0x77e05f91, 0x2d0eb046, 0x77ceb725, 0x2d3db928, 0x77bcfc3f, +0x2d6cbb10, 0x77ab2ee2, 0x2d9bb5f6, 0x77994f11, 0x2dcaa9d5, 0x77875cce, 0x2df996a3, 0x7775581d, +0x2e287c5a, 0x776340ff, 0x2e575af3, 0x77511778, 0x2e863267, 0x773edb8b, 0x2eb502ae, 0x772c8d3a, +0x2ee3cbc1, 0x771a2c88, 0x2f128d99, 0x7707b979, 0x2f41482e, 0x76f5340e, 0x2f6ffb7a, 0x76e29c4b, +0x2f9ea775, 0x76cff232, 0x2fcd4c19, 0x76bd35c7, 0x2ffbe95d, 0x76aa670d, 0x302a7f3a, 0x76978605, +0x30590dab, 0x768492b4, 0x308794a6, 0x76718d1c, 0x30b61426, 0x765e7540, 0x30e48c22, 0x764b4b23, +0x3112fc95, 0x76380ec8, 0x31416576, 0x7624c031, 0x316fc6be, 0x76115f63, 0x319e2067, 0x75fdec60, +0x31cc7269, 0x75ea672a, 0x31fabcbd, 0x75d6cfc5, 0x3228ff5c, 0x75c32634, 0x32573a3f, 0x75af6a7b, +0x32856d5e, 0x759b9c9b, 0x32b398b3, 0x7587bc98, 0x32e1bc36, 0x7573ca75, 0x330fd7e1, 0x755fc635, +0x333debab, 0x754bafdc, 0x336bf78f, 0x7537876c, 0x3399fb85, 0x75234ce8, 0x33c7f785, 0x750f0054, +0x33f5eb89, 0x74faa1b3, 0x3423d78a, 0x74e63108, 0x3451bb81, 0x74d1ae55, 0x347f9766, 0x74bd199f, +0x34ad6b32, 0x74a872e8, 0x34db36df, 0x7493ba34, 0x3508fa66, 0x747eef85, 0x3536b5be, 0x746a12df, +0x356468e2, 0x74552446, 0x359213c9, 0x744023bc, 0x35bfb66e, 0x742b1144, 0x35ed50c9, 0x7415ece2, +0x361ae2d3, 0x7400b69a, 0x36486c86, 0x73eb6e6e, 0x3675edd9, 0x73d61461, 0x36a366c6, 0x73c0a878, +0x36d0d746, 0x73ab2ab4, 0x36fe3f52, 0x73959b1b, 0x372b9ee3, 0x737ff9ae, 0x3758f5f2, 0x736a4671, +0x37864477, 0x73548168, 0x37b38a6d, 0x733eaa96, 0x37e0c7cc, 0x7328c1ff, 0x380dfc8d, 0x7312c7a5, +0x383b28a9, 0x72fcbb8c, 0x38684c19, 0x72e69db7, 0x389566d6, 0x72d06e2b, 0x38c278d9, 0x72ba2cea, +0x38ef821c, 0x72a3d9f7, 0x391c8297, 0x728d7557, 0x39497a43, 0x7276ff0d, 0x39766919, 0x7260771b, +0x39a34f13, 0x7249dd86, 0x39d02c2a, 0x72333251, 0x39fd0056, 0x721c7580, 0x3a29cb91, 0x7205a716, +0x3a568dd4, 0x71eec716, 0x3a834717, 0x71d7d585, 0x3aaff755, 0x71c0d265, 0x3adc9e86, 0x71a9bdba, +0x3b093ca3, 0x71929789, 0x3b35d1a5, 0x717b5fd3, 0x3b625d86, 0x7164169d, 0x3b8ee03e, 0x714cbbeb, +0x3bbb59c7, 0x71354fc0, 0x3be7ca1a, 0x711dd220, 0x3c143130, 0x7106430e, 0x3c408f03, 0x70eea28e, +0x3c6ce38a, 0x70d6f0a4, 0x3c992ec0, 0x70bf2d53, 0x3cc5709e, 0x70a7589f, 0x3cf1a91c, 0x708f728b, +0x3d1dd835, 0x70777b1c, 0x3d49fde1, 0x705f7255, 0x3d761a19, 0x70475839, 0x3da22cd7, 0x702f2ccd, +0x3dce3614, 0x7016f014, 0x3dfa35c8, 0x6ffea212, 0x3e262bee, 0x6fe642ca, 0x3e52187f, 0x6fcdd241, +0x3e7dfb73, 0x6fb5507a, 0x3ea9d4c3, 0x6f9cbd79, 0x3ed5a46b, 0x6f841942, 0x3f016a61, 0x6f6b63d8, +0x3f2d26a0, 0x6f529d40, 0x3f58d921, 0x6f39c57d, 0x3f8481dd, 0x6f20dc92, 0x3fb020ce, 0x6f07e285, +0x3fdbb5ec, 0x6eeed758, 0x40074132, 0x6ed5bb10, 0x4032c297, 0x6ebc8db0, 0x405e3a16, 0x6ea34f3d, +0x4089a7a8, 0x6e89ffb9, 0x40b50b46, 0x6e709f2a, 0x40e064ea, 0x6e572d93, 0x410bb48c, 0x6e3daaf8, +0x4136fa27, 0x6e24175c, 0x416235b2, 0x6e0a72c5, 0x418d6729, 0x6df0bd35, 0x41b88e84, 0x6dd6f6b1, +0x41e3abbc, 0x6dbd1f3c, 0x420ebecb, 0x6da336dc, 0x4239c7aa, 0x6d893d93, 0x4264c653, 0x6d6f3365, +0x428fbabe, 0x6d551858, 0x42baa4e6, 0x6d3aec6e, 0x42e584c3, 0x6d20afac, 0x43105a50, 0x6d066215, +0x433b2585, 0x6cec03af, 0x4365e65b, 0x6cd1947c, 0x43909ccd, 0x6cb71482, 0x43bb48d4, 0x6c9c83c3, +0x43e5ea68, 0x6c81e245, 0x44108184, 0x6c67300b, 0x443b0e21, 0x6c4c6d1a, 0x44659039, 0x6c319975, +0x449007c4, 0x6c16b521, 0x44ba74bd, 0x6bfbc021, 0x44e4d71c, 0x6be0ba7b, 0x450f2edb, 0x6bc5a431, +0x45397bf4, 0x6baa7d49, 0x4563be60, 0x6b8f45c7, 0x458df619, 0x6b73fdae, 0x45b82318, 0x6b58a503, +0x45e24556, 0x6b3d3bcb, 0x460c5cce, 0x6b21c208, 0x46366978, 0x6b0637c1, 0x46606b4e, 0x6aea9cf8, +0x468a624a, 0x6acef1b2, 0x46b44e65, 0x6ab335f4, 0x46de2f99, 0x6a9769c1, 0x470805df, 0x6a7b8d1e, +0x4731d131, 0x6a5fa010, 0x475b9188, 0x6a43a29a, 0x478546de, 0x6a2794c1, 0x47aef12c, 0x6a0b7689, +0x47d8906d, 0x69ef47f6, 0x48022499, 0x69d3090e, 0x482badab, 0x69b6b9d3, 0x48552b9b, 0x699a5a4c, +0x487e9e64, 0x697dea7b, 0x48a805ff, 0x69616a65, 0x48d16265, 0x6944da10, 0x48fab391, 0x6928397e, +0x4923f97b, 0x690b88b5, 0x494d341e, 0x68eec7b9, 0x49766373, 0x68d1f68f, 0x499f8774, 0x68b5153a, +0x49c8a01b, 0x689823bf, 0x49f1ad61, 0x687b2224, 0x4a1aaf3f, 0x685e106c, 0x4a43a5b0, 0x6840ee9b, +0x4a6c90ad, 0x6823bcb7, 0x4a957030, 0x68067ac3, 0x4abe4433, 0x67e928c5, 0x4ae70caf, 0x67cbc6c0, +0x4b0fc99d, 0x67ae54ba, 0x4b387af9, 0x6790d2b6, 0x4b6120bb, 0x677340ba, 0x4b89badd, 0x67559eca, +0x4bb24958, 0x6737ecea, 0x4bdacc28, 0x671a2b20, 0x4c034345, 0x66fc596f, 0x4c2baea9, 0x66de77dc, +0x4c540e4e, 0x66c0866d, 0x4c7c622d, 0x66a28524, 0x4ca4aa41, 0x66847408, 0x4ccce684, 0x6666531d, +0x4cf516ee, 0x66482267, 0x4d1d3b7a, 0x6629e1ec, 0x4d455422, 0x660b91af, 0x4d6d60df, 0x65ed31b5, +0x4d9561ac, 0x65cec204, 0x4dbd5682, 0x65b0429f, 0x4de53f5a, 0x6591b38c, 0x4e0d1c30, 0x657314cf, +0x4e34ecfc, 0x6554666d, 0x4e5cb1b9, 0x6535a86b, 0x4e846a60, 0x6516dacd, 0x4eac16eb, 0x64f7fd98, +0x4ed3b755, 0x64d910d1, 0x4efb4b96, 0x64ba147d, 0x4f22d3aa, 0x649b08a0, 0x4f4a4f89, 0x647bed3f, +0x4f71bf2e, 0x645cc260, 0x4f992293, 0x643d8806, 0x4fc079b1, 0x641e3e38, 0x4fe7c483, 0x63fee4f8, +0x500f0302, 0x63df7c4d, 0x50363529, 0x63c0043b, 0x505d5af1, 0x63a07cc7, 0x50847454, 0x6380e5f6, +0x50ab814d, 0x63613fcd, 0x50d281d5, 0x63418a50, 0x50f975e6, 0x6321c585, 0x51205d7b, 0x6301f171, +0x5147388c, 0x62e20e17, 0x516e0715, 0x62c21b7e, 0x5194c910, 0x62a219aa, 0x51bb7e75, 0x628208a1, +0x51e22740, 0x6261e866, 0x5208c36a, 0x6241b8ff, 0x522f52ee, 0x62217a72, 0x5255d5c5, 0x62012cc2, +0x527c4bea, 0x61e0cff5, 0x52a2b556, 0x61c06410, 0x52c91204, 0x619fe918, 0x52ef61ee, 0x617f5f12, +0x5315a50e, 0x615ec603, 0x533bdb5d, 0x613e1df0, 0x536204d7, 0x611d66de, 0x53882175, 0x60fca0d2, +0x53ae3131, 0x60dbcbd1, 0x53d43406, 0x60bae7e1, 0x53fa29ed, 0x6099f505, 0x542012e1, 0x6078f344, +0x5445eedb, 0x6057e2a2, 0x546bbdd7, 0x6036c325, 0x54917fce, 0x601594d1, 0x54b734ba, 0x5ff457ad, +0x54dcdc96, 0x5fd30bbc, 0x5502775c, 0x5fb1b104, 0x55280505, 0x5f90478a, 0x554d858d, 0x5f6ecf53, +0x5572f8ed, 0x5f4d4865, 0x55985f20, 0x5f2bb2c5, 0x55bdb81f, 0x5f0a0e77, 0x55e303e6, 0x5ee85b82, +0x5608426e, 0x5ec699e9, 0x562d73b2, 0x5ea4c9b3, 0x565297ab, 0x5e82eae5, 0x5677ae54, 0x5e60fd84, +0x569cb7a8, 0x5e3f0194, 0x56c1b3a1, 0x5e1cf71c, 0x56e6a239, 0x5dfade20, 0x570b8369, 0x5dd8b6a7, +0x5730572e, 0x5db680b4, 0x57551d80, 0x5d943c4e, 0x5779d65b, 0x5d71e979, 0x579e81b8, 0x5d4f883b, +0x57c31f92, 0x5d2d189a, 0x57e7afe4, 0x5d0a9a9a, 0x580c32a7, 0x5ce80e41, 0x5830a7d6, 0x5cc57394, +0x58550f6c, 0x5ca2ca99, 0x58796962, 0x5c801354, 0x589db5b3, 0x5c5d4dcc, 0x58c1f45b, 0x5c3a7a05, +0x58e62552, 0x5c179806, 0x590a4893, 0x5bf4a7d2, 0x592e5e19, 0x5bd1a971, 0x595265df, 0x5bae9ce7, +0x59765fde, 0x5b8b8239, 0x599a4c12, 0x5b68596d, 0x59be2a74, 0x5b452288, 0x59e1faff, 0x5b21dd90, +0x5a05bdae, 0x5afe8a8b, 0x5a29727b, 0x5adb297d, 0x5a4d1960, 0x5ab7ba6c, 0x5a70b258, 0x5a943d5e, +}; + +const int32_t kbdWindowOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 128}; + +const int32_t kbdWindow[128 + 1024] PROGMEM = { +/* 128 - format = Q31 * 2^0 */ +0x00016f63, 0x7ffffffe, 0x0003e382, 0x7ffffff1, 0x00078f64, 0x7fffffc7, 0x000cc323, 0x7fffff5d, +0x0013d9ed, 0x7ffffe76, 0x001d3a9d, 0x7ffffcaa, 0x0029581f, 0x7ffff953, 0x0038b1bd, 0x7ffff372, +0x004bd34d, 0x7fffe98b, 0x00635538, 0x7fffd975, 0x007fdc64, 0x7fffc024, 0x00a219f1, 0x7fff995b, +0x00cacad0, 0x7fff5f5b, 0x00fab72d, 0x7fff0a75, 0x0132b1af, 0x7ffe9091, 0x01739689, 0x7ffde49e, +0x01be4a63, 0x7ffcf5ef, 0x0213b910, 0x7ffbaf84, 0x0274d41e, 0x7ff9f73a, 0x02e2913a, 0x7ff7acf1, +0x035de86c, 0x7ff4a99a, 0x03e7d233, 0x7ff0be3d, 0x0481457c, 0x7febb2f1, 0x052b357c, 0x7fe545d4, +0x05e68f77, 0x7fdd2a02, 0x06b4386f, 0x7fd30695, 0x07950acb, 0x7fc675b4, 0x0889d3ef, 0x7fb703be, +0x099351e0, 0x7fa42e89, 0x0ab230e0, 0x7f8d64d8, 0x0be70923, 0x7f7205f8, 0x0d325c93, 0x7f516195, +0x0e9494ae, 0x7f2ab7d0, 0x100e0085, 0x7efd3997, 0x119ed2ef, 0x7ec8094a, 0x134720d8, 0x7e8a3ba7, +0x1506dfdc, 0x7e42d906, 0x16dde50b, 0x7df0dee4, 0x18cbe3f7, 0x7d9341b4, 0x1ad06e07, 0x7d28ef02, +0x1ceaf215, 0x7cb0cfcc, 0x1f1abc4f, 0x7c29cb20, 0x215ef677, 0x7b92c8eb, 0x23b6a867, 0x7aeab4ec, +0x2620b8ec, 0x7a3081d0, 0x289beef5, 0x79632c5a, 0x2b26f30b, 0x7881be95, 0x2dc0511f, 0x778b5304, +0x30667aa2, 0x767f17c0, 0x3317c8dd, 0x755c5178, 0x35d27f98, 0x74225e50, 0x3894cff3, 0x72d0b887, +0x3b5cdb7b, 0x7166f8e7, 0x3e28b770, 0x6fe4d8e8, 0x40f6702a, 0x6e4a3491, 0x43c40caa, 0x6c970bfc, +0x468f9231, 0x6acb8483, 0x495707f5, 0x68e7e994, 0x4c187ac7, 0x66ecad1c, 0x4ed200c5, 0x64da6797, +0x5181bcea, 0x62b1d7b7, 0x5425e28e, 0x6073e1ae, 0x56bcb8c2, 0x5e218e16, 0x59449d76, 0x5bbc0875, +/* 1024 - format = Q31 * 2^0 */ +0x0009962f, 0x7fffffa4, 0x000e16fb, 0x7fffff39, 0x0011ea65, 0x7ffffebf, 0x0015750e, 0x7ffffe34, +0x0018dc74, 0x7ffffd96, 0x001c332e, 0x7ffffce5, 0x001f83f5, 0x7ffffc1f, 0x0022d59a, 0x7ffffb43, +0x00262cc2, 0x7ffffa4f, 0x00298cc4, 0x7ffff942, 0x002cf81f, 0x7ffff81a, 0x003070c4, 0x7ffff6d6, +0x0033f840, 0x7ffff573, 0x00378fd9, 0x7ffff3f1, 0x003b38a1, 0x7ffff24d, 0x003ef381, 0x7ffff085, +0x0042c147, 0x7fffee98, 0x0046a2a8, 0x7fffec83, 0x004a9847, 0x7fffea44, 0x004ea2b7, 0x7fffe7d8, +0x0052c283, 0x7fffe53f, 0x0056f829, 0x7fffe274, 0x005b4422, 0x7fffdf76, 0x005fa6dd, 0x7fffdc43, +0x006420c8, 0x7fffd8d6, 0x0068b249, 0x7fffd52f, 0x006d5bc4, 0x7fffd149, 0x00721d9a, 0x7fffcd22, +0x0076f828, 0x7fffc8b6, 0x007bebca, 0x7fffc404, 0x0080f8d9, 0x7fffbf06, 0x00861fae, 0x7fffb9bb, +0x008b609e, 0x7fffb41e, 0x0090bbff, 0x7fffae2c, 0x00963224, 0x7fffa7e1, 0x009bc362, 0x7fffa13a, +0x00a17009, 0x7fff9a32, 0x00a7386c, 0x7fff92c5, 0x00ad1cdc, 0x7fff8af0, 0x00b31da8, 0x7fff82ad, +0x00b93b21, 0x7fff79f9, 0x00bf7596, 0x7fff70cf, 0x00c5cd57, 0x7fff672a, 0x00cc42b1, 0x7fff5d05, +0x00d2d5f3, 0x7fff525c, 0x00d9876c, 0x7fff4729, 0x00e05769, 0x7fff3b66, 0x00e74638, 0x7fff2f10, +0x00ee5426, 0x7fff221f, 0x00f58182, 0x7fff148e, 0x00fcce97, 0x7fff0658, 0x01043bb3, 0x7ffef776, +0x010bc923, 0x7ffee7e2, 0x01137733, 0x7ffed795, 0x011b4631, 0x7ffec68a, 0x01233669, 0x7ffeb4ba, +0x012b4827, 0x7ffea21d, 0x01337bb8, 0x7ffe8eac, 0x013bd167, 0x7ffe7a61, 0x01444982, 0x7ffe6533, +0x014ce454, 0x7ffe4f1c, 0x0155a229, 0x7ffe3813, 0x015e834d, 0x7ffe2011, 0x0167880c, 0x7ffe070d, +0x0170b0b2, 0x7ffdecff, 0x0179fd8b, 0x7ffdd1df, 0x01836ee1, 0x7ffdb5a2, 0x018d0500, 0x7ffd9842, +0x0196c035, 0x7ffd79b3, 0x01a0a0ca, 0x7ffd59ee, 0x01aaa70a, 0x7ffd38e8, 0x01b4d341, 0x7ffd1697, +0x01bf25b9, 0x7ffcf2f2, 0x01c99ebd, 0x7ffccdee, 0x01d43e99, 0x7ffca780, 0x01df0597, 0x7ffc7f9e, +0x01e9f401, 0x7ffc563d, 0x01f50a22, 0x7ffc2b51, 0x02004844, 0x7ffbfecf, 0x020baeb1, 0x7ffbd0ab, +0x02173db4, 0x7ffba0da, 0x0222f596, 0x7ffb6f4f, 0x022ed6a1, 0x7ffb3bfd, 0x023ae11f, 0x7ffb06d8, +0x02471558, 0x7ffacfd3, 0x02537397, 0x7ffa96e0, 0x025ffc25, 0x7ffa5bf2, 0x026caf4a, 0x7ffa1efc, +0x02798d4f, 0x7ff9dfee, 0x0286967c, 0x7ff99ebb, 0x0293cb1b, 0x7ff95b55, 0x02a12b72, 0x7ff915ab, +0x02aeb7cb, 0x7ff8cdaf, 0x02bc706d, 0x7ff88351, 0x02ca559f, 0x7ff83682, 0x02d867a9, 0x7ff7e731, +0x02e6a6d2, 0x7ff7954e, 0x02f51361, 0x7ff740c8, 0x0303ad9c, 0x7ff6e98e, 0x031275ca, 0x7ff68f8f, +0x03216c30, 0x7ff632ba, 0x03309116, 0x7ff5d2fb, 0x033fe4bf, 0x7ff57042, 0x034f6773, 0x7ff50a7a, +0x035f1975, 0x7ff4a192, 0x036efb0a, 0x7ff43576, 0x037f0c78, 0x7ff3c612, 0x038f4e02, 0x7ff35353, +0x039fbfeb, 0x7ff2dd24, 0x03b06279, 0x7ff26370, 0x03c135ed, 0x7ff1e623, 0x03d23a8b, 0x7ff16527, +0x03e37095, 0x7ff0e067, 0x03f4d84e, 0x7ff057cc, 0x040671f7, 0x7fefcb40, 0x04183dd3, 0x7fef3aad, +0x042a3c22, 0x7feea5fa, 0x043c6d25, 0x7fee0d11, 0x044ed11d, 0x7fed6fda, 0x04616849, 0x7fecce3d, +0x047432eb, 0x7fec2821, 0x04873140, 0x7feb7d6c, 0x049a6388, 0x7feace07, 0x04adca01, 0x7fea19d6, +0x04c164ea, 0x7fe960c0, 0x04d53481, 0x7fe8a2aa, 0x04e93902, 0x7fe7df79, 0x04fd72aa, 0x7fe71712, +0x0511e1b6, 0x7fe6495a, 0x05268663, 0x7fe57634, 0x053b60eb, 0x7fe49d83, 0x05507189, 0x7fe3bf2b, +0x0565b879, 0x7fe2db0f, 0x057b35f4, 0x7fe1f110, 0x0590ea35, 0x7fe10111, 0x05a6d574, 0x7fe00af3, +0x05bcf7ea, 0x7fdf0e97, 0x05d351cf, 0x7fde0bdd, 0x05e9e35c, 0x7fdd02a6, 0x0600acc8, 0x7fdbf2d2, +0x0617ae48, 0x7fdadc40, 0x062ee814, 0x7fd9becf, 0x06465a62, 0x7fd89a5e, 0x065e0565, 0x7fd76eca, +0x0675e954, 0x7fd63bf1, 0x068e0662, 0x7fd501b0, 0x06a65cc3, 0x7fd3bfe4, 0x06beecaa, 0x7fd2766a, +0x06d7b648, 0x7fd1251e, 0x06f0b9d1, 0x7fcfcbda, 0x0709f775, 0x7fce6a7a, 0x07236f65, 0x7fcd00d8, +0x073d21d2, 0x7fcb8ecf, 0x07570eea, 0x7fca1439, 0x077136dd, 0x7fc890ed, 0x078b99da, 0x7fc704c7, +0x07a6380d, 0x7fc56f9d, 0x07c111a4, 0x7fc3d147, 0x07dc26cc, 0x7fc2299e, 0x07f777b1, 0x7fc07878, +0x0813047d, 0x7fbebdac, 0x082ecd5b, 0x7fbcf90f, 0x084ad276, 0x7fbb2a78, 0x086713f7, 0x7fb951bc, +0x08839206, 0x7fb76eaf, 0x08a04ccb, 0x7fb58126, 0x08bd446e, 0x7fb388f4, 0x08da7915, 0x7fb185ee, +0x08f7eae7, 0x7faf77e5, 0x09159a09, 0x7fad5ead, 0x0933869f, 0x7fab3a17, 0x0951b0cd, 0x7fa909f6, +0x097018b7, 0x7fa6ce1a, 0x098ebe7f, 0x7fa48653, 0x09ada248, 0x7fa23273, 0x09ccc431, 0x7f9fd249, +0x09ec245b, 0x7f9d65a4, 0x0a0bc2e7, 0x7f9aec53, 0x0a2b9ff3, 0x7f986625, 0x0a4bbb9e, 0x7f95d2e7, +0x0a6c1604, 0x7f933267, 0x0a8caf43, 0x7f908472, 0x0aad8776, 0x7f8dc8d5, 0x0ace9eb9, 0x7f8aff5c, +0x0aeff526, 0x7f8827d3, 0x0b118ad8, 0x7f854204, 0x0b335fe6, 0x7f824dbb, 0x0b557469, 0x7f7f4ac3, +0x0b77c879, 0x7f7c38e4, 0x0b9a5c2b, 0x7f7917e9, 0x0bbd2f97, 0x7f75e79b, 0x0be042d0, 0x7f72a7c3, +0x0c0395ec, 0x7f6f5828, 0x0c2728fd, 0x7f6bf892, 0x0c4afc16, 0x7f6888c9, 0x0c6f0f4a, 0x7f650894, +0x0c9362a8, 0x7f6177b9, 0x0cb7f642, 0x7f5dd5ff, 0x0cdcca26, 0x7f5a232a, 0x0d01de63, 0x7f565f00, +0x0d273307, 0x7f528947, 0x0d4cc81f, 0x7f4ea1c2, 0x0d729db7, 0x7f4aa835, 0x0d98b3da, 0x7f469c65, +0x0dbf0a92, 0x7f427e13, 0x0de5a1e9, 0x7f3e4d04, 0x0e0c79e7, 0x7f3a08f9, 0x0e339295, 0x7f35b1b4, +0x0e5aebfa, 0x7f3146f8, 0x0e82861a, 0x7f2cc884, 0x0eaa60fd, 0x7f28361b, 0x0ed27ca5, 0x7f238f7c, +0x0efad917, 0x7f1ed467, 0x0f237656, 0x7f1a049d, 0x0f4c5462, 0x7f151fdc, 0x0f75733d, 0x7f1025e3, +0x0f9ed2e6, 0x7f0b1672, 0x0fc8735e, 0x7f05f146, 0x0ff254a1, 0x7f00b61d, 0x101c76ae, 0x7efb64b4, +0x1046d981, 0x7ef5fcca, 0x10717d15, 0x7ef07e19, 0x109c6165, 0x7eeae860, 0x10c7866a, 0x7ee53b5b, +0x10f2ec1e, 0x7edf76c4, 0x111e9279, 0x7ed99a58, 0x114a7971, 0x7ed3a5d1, 0x1176a0fc, 0x7ecd98eb, +0x11a30910, 0x7ec77360, 0x11cfb1a1, 0x7ec134eb, 0x11fc9aa2, 0x7ebadd44, 0x1229c406, 0x7eb46c27, +0x12572dbf, 0x7eade14c, 0x1284d7bc, 0x7ea73c6c, 0x12b2c1ed, 0x7ea07d41, 0x12e0ec42, 0x7e99a382, +0x130f56a8, 0x7e92aee7, 0x133e010b, 0x7e8b9f2a, 0x136ceb59, 0x7e847402, 0x139c157b, 0x7e7d2d25, +0x13cb7f5d, 0x7e75ca4c, 0x13fb28e6, 0x7e6e4b2d, 0x142b1200, 0x7e66af7f, 0x145b3a92, 0x7e5ef6f8, +0x148ba281, 0x7e572150, 0x14bc49b4, 0x7e4f2e3b, 0x14ed300f, 0x7e471d70, 0x151e5575, 0x7e3eeea5, +0x154fb9c9, 0x7e36a18e, 0x15815ced, 0x7e2e35e2, 0x15b33ec1, 0x7e25ab56, 0x15e55f25, 0x7e1d019e, +0x1617bdf9, 0x7e14386e, 0x164a5b19, 0x7e0b4f7d, 0x167d3662, 0x7e02467e, 0x16b04fb2, 0x7df91d25, +0x16e3a6e2, 0x7defd327, 0x17173bce, 0x7de66837, 0x174b0e4d, 0x7ddcdc0a, 0x177f1e39, 0x7dd32e53, +0x17b36b69, 0x7dc95ec6, 0x17e7f5b3, 0x7dbf6d17, 0x181cbcec, 0x7db558f9, 0x1851c0e9, 0x7dab221f, +0x1887017d, 0x7da0c83c, 0x18bc7e7c, 0x7d964b05, 0x18f237b6, 0x7d8baa2b, 0x19282cfd, 0x7d80e563, +0x195e5e20, 0x7d75fc5e, 0x1994caee, 0x7d6aeed0, 0x19cb7335, 0x7d5fbc6d, 0x1a0256c2, 0x7d5464e6, +0x1a397561, 0x7d48e7ef, 0x1a70cede, 0x7d3d453b, 0x1aa86301, 0x7d317c7c, 0x1ae03195, 0x7d258d65, +0x1b183a63, 0x7d1977aa, 0x1b507d30, 0x7d0d3afc, 0x1b88f9c5, 0x7d00d710, 0x1bc1afe6, 0x7cf44b97, +0x1bfa9f58, 0x7ce79846, 0x1c33c7e0, 0x7cdabcce, 0x1c6d293f, 0x7ccdb8e4, 0x1ca6c337, 0x7cc08c39, +0x1ce0958a, 0x7cb33682, 0x1d1a9ff8, 0x7ca5b772, 0x1d54e240, 0x7c980ebd, 0x1d8f5c21, 0x7c8a3c14, +0x1dca0d56, 0x7c7c3f2e, 0x1e04f59f, 0x7c6e17bc, 0x1e4014b4, 0x7c5fc573, 0x1e7b6a53, 0x7c514807, +0x1eb6f633, 0x7c429f2c, 0x1ef2b80f, 0x7c33ca96, 0x1f2eaf9e, 0x7c24c9fa, 0x1f6adc98, 0x7c159d0d, +0x1fa73eb2, 0x7c064383, 0x1fe3d5a3, 0x7bf6bd11, 0x2020a11e, 0x7be7096c, 0x205da0d8, 0x7bd7284a, +0x209ad483, 0x7bc71960, 0x20d83bd1, 0x7bb6dc65, 0x2115d674, 0x7ba6710d, 0x2153a41b, 0x7b95d710, +0x2191a476, 0x7b850e24, 0x21cfd734, 0x7b7415ff, 0x220e3c02, 0x7b62ee59, 0x224cd28d, 0x7b5196e9, +0x228b9a82, 0x7b400f67, 0x22ca938a, 0x7b2e578a, 0x2309bd52, 0x7b1c6f0b, 0x23491783, 0x7b0a55a1, +0x2388a1c4, 0x7af80b07, 0x23c85bbf, 0x7ae58ef5, 0x2408451a, 0x7ad2e124, 0x24485d7c, 0x7ac0014e, +0x2488a48a, 0x7aacef2e, 0x24c919e9, 0x7a99aa7e, 0x2509bd3d, 0x7a8632f8, 0x254a8e29, 0x7a728858, +0x258b8c50, 0x7a5eaa5a, 0x25ccb753, 0x7a4a98b9, 0x260e0ed3, 0x7a365333, 0x264f9271, 0x7a21d983, +0x269141cb, 0x7a0d2b68, 0x26d31c80, 0x79f8489e, 0x2715222f, 0x79e330e4, 0x27575273, 0x79cde3f8, +0x2799acea, 0x79b8619a, 0x27dc3130, 0x79a2a989, 0x281ededf, 0x798cbb85, 0x2861b591, 0x7976974e, +0x28a4b4e0, 0x79603ca5, 0x28e7dc65, 0x7949ab4c, 0x292b2bb8, 0x7932e304, 0x296ea270, 0x791be390, +0x29b24024, 0x7904acb3, 0x29f6046b, 0x78ed3e30, 0x2a39eed8, 0x78d597cc, 0x2a7dff02, 0x78bdb94a, +0x2ac2347c, 0x78a5a270, 0x2b068eda, 0x788d5304, 0x2b4b0dae, 0x7874cacb, 0x2b8fb08a, 0x785c098d, +0x2bd47700, 0x78430f11, 0x2c1960a1, 0x7829db1f, 0x2c5e6cfd, 0x78106d7f, 0x2ca39ba3, 0x77f6c5fb, +0x2ce8ec23, 0x77dce45c, 0x2d2e5e0b, 0x77c2c86e, 0x2d73f0e8, 0x77a871fa, 0x2db9a449, 0x778de0cd, +0x2dff77b8, 0x777314b2, 0x2e456ac4, 0x77580d78, 0x2e8b7cf6, 0x773ccaeb, 0x2ed1addb, 0x77214cdb, +0x2f17fcfb, 0x77059315, 0x2f5e69e2, 0x76e99d69, 0x2fa4f419, 0x76cd6ba9, 0x2feb9b27, 0x76b0fda4, +0x30325e96, 0x7694532e, 0x30793dee, 0x76776c17, 0x30c038b5, 0x765a4834, 0x31074e72, 0x763ce759, +0x314e7eab, 0x761f4959, 0x3195c8e6, 0x76016e0b, 0x31dd2ca9, 0x75e35545, 0x3224a979, 0x75c4fedc, +0x326c3ed8, 0x75a66aab, 0x32b3ec4d, 0x75879887, 0x32fbb159, 0x7568884b, 0x33438d81, 0x754939d1, +0x338b8045, 0x7529acf4, 0x33d3892a, 0x7509e18e, 0x341ba7b1, 0x74e9d77d, 0x3463db5a, 0x74c98e9e, +0x34ac23a7, 0x74a906cd, 0x34f48019, 0x74883fec, 0x353cf02f, 0x746739d8, 0x3585736a, 0x7445f472, +0x35ce0949, 0x74246f9c, 0x3616b14c, 0x7402ab37, 0x365f6af0, 0x73e0a727, 0x36a835b5, 0x73be6350, +0x36f11118, 0x739bdf95, 0x3739fc98, 0x73791bdd, 0x3782f7b2, 0x7356180e, 0x37cc01e3, 0x7332d410, +0x38151aa8, 0x730f4fc9, 0x385e417e, 0x72eb8b24, 0x38a775e1, 0x72c7860a, 0x38f0b74d, 0x72a34066, +0x393a053e, 0x727eba24, 0x39835f30, 0x7259f331, 0x39ccc49e, 0x7234eb79, 0x3a163503, 0x720fa2eb, +0x3a5fafda, 0x71ea1977, 0x3aa9349e, 0x71c44f0c, 0x3af2c2ca, 0x719e439d, 0x3b3c59d7, 0x7177f71a, +0x3b85f940, 0x71516978, 0x3bcfa07e, 0x712a9aaa, 0x3c194f0d, 0x71038aa4, 0x3c630464, 0x70dc395e, +0x3cacbfff, 0x70b4a6cd, 0x3cf68155, 0x708cd2e9, 0x3d4047e1, 0x7064bdab, 0x3d8a131c, 0x703c670d, +0x3dd3e27e, 0x7013cf0a, 0x3e1db580, 0x6feaf59c, 0x3e678b9b, 0x6fc1dac1, 0x3eb16449, 0x6f987e76, +0x3efb3f01, 0x6f6ee0b9, 0x3f451b3d, 0x6f45018b, 0x3f8ef874, 0x6f1ae0eb, 0x3fd8d620, 0x6ef07edb, +0x4022b3b9, 0x6ec5db5d, 0x406c90b7, 0x6e9af675, 0x40b66c93, 0x6e6fd027, 0x410046c5, 0x6e446879, +0x414a1ec6, 0x6e18bf71, 0x4193f40d, 0x6decd517, 0x41ddc615, 0x6dc0a972, 0x42279455, 0x6d943c8d, +0x42715e45, 0x6d678e71, 0x42bb235f, 0x6d3a9f2a, 0x4304e31a, 0x6d0d6ec5, 0x434e9cf1, 0x6cdffd4f, +0x4398505b, 0x6cb24ad6, 0x43e1fcd1, 0x6c84576b, 0x442ba1cd, 0x6c56231c, 0x44753ec7, 0x6c27adfd, +0x44bed33a, 0x6bf8f81e, 0x45085e9d, 0x6bca0195, 0x4551e06b, 0x6b9aca75, 0x459b581e, 0x6b6b52d5, +0x45e4c52f, 0x6b3b9ac9, 0x462e2717, 0x6b0ba26b, 0x46777d52, 0x6adb69d3, 0x46c0c75a, 0x6aaaf11b, +0x470a04a9, 0x6a7a385c, 0x475334b9, 0x6a493fb3, 0x479c5707, 0x6a18073d, 0x47e56b0c, 0x69e68f17, +0x482e7045, 0x69b4d761, 0x4877662c, 0x6982e039, 0x48c04c3f, 0x6950a9c0, 0x490921f8, 0x691e341a, +0x4951e6d5, 0x68eb7f67, 0x499a9a51, 0x68b88bcd, 0x49e33beb, 0x68855970, 0x4a2bcb1f, 0x6851e875, +0x4a74476b, 0x681e3905, 0x4abcb04c, 0x67ea4b47, 0x4b050541, 0x67b61f63, 0x4b4d45c9, 0x6781b585, +0x4b957162, 0x674d0dd6, 0x4bdd878c, 0x67182883, 0x4c2587c6, 0x66e305b8, 0x4c6d7190, 0x66ada5a5, +0x4cb5446a, 0x66780878, 0x4cfcffd5, 0x66422e60, 0x4d44a353, 0x660c1790, 0x4d8c2e64, 0x65d5c439, +0x4dd3a08c, 0x659f348e, 0x4e1af94b, 0x656868c3, 0x4e623825, 0x6531610d, 0x4ea95c9d, 0x64fa1da3, +0x4ef06637, 0x64c29ebb, 0x4f375477, 0x648ae48d, 0x4f7e26e1, 0x6452ef53, 0x4fc4dcfb, 0x641abf46, +0x500b7649, 0x63e254a2, 0x5051f253, 0x63a9afa2, 0x5098509f, 0x6370d083, 0x50de90b3, 0x6337b784, +0x5124b218, 0x62fe64e3, 0x516ab455, 0x62c4d8e0, 0x51b096f3, 0x628b13bc, 0x51f6597b, 0x625115b8, +0x523bfb78, 0x6216df18, 0x52817c72, 0x61dc701f, 0x52c6dbf5, 0x61a1c912, 0x530c198d, 0x6166ea36, +0x535134c5, 0x612bd3d2, 0x53962d2a, 0x60f0862d, 0x53db024a, 0x60b50190, 0x541fb3b1, 0x60794644, +0x546440ef, 0x603d5494, 0x54a8a992, 0x60012cca, 0x54eced2b, 0x5fc4cf33, 0x55310b48, 0x5f883c1c, +0x5575037c, 0x5f4b73d2, 0x55b8d558, 0x5f0e76a5, 0x55fc806f, 0x5ed144e5, 0x56400452, 0x5e93dee1, +0x56836096, 0x5e5644ec, 0x56c694cf, 0x5e187757, 0x5709a092, 0x5dda7677, 0x574c8374, 0x5d9c429f, +0x578f3d0d, 0x5d5ddc24, 0x57d1ccf2, 0x5d1f435d, 0x581432bd, 0x5ce078a0, 0x58566e04, 0x5ca17c45, +0x58987e63, 0x5c624ea4, 0x58da6372, 0x5c22f016, 0x591c1ccc, 0x5be360f6, 0x595daa0d, 0x5ba3a19f, +0x599f0ad1, 0x5b63b26c, 0x59e03eb6, 0x5b2393ba, 0x5a214558, 0x5ae345e7, 0x5a621e56, 0x5aa2c951, +}; +/* bit reverse tables for FFT */ +const uint8_t bitrevtabOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 17}; +const uint8_t bitrevtab[17 + 129] PROGMEM = { +/* nfft = 64 */ +0x01, 0x08, 0x02, 0x04, 0x03, 0x0c, 0x05, 0x0a, 0x07, 0x0e, 0x0b, 0x0d, 0x00, 0x06, 0x09, 0x0f, +0x00, +/* nfft = 512 */ +0x01, 0x40, 0x02, 0x20, 0x03, 0x60, 0x04, 0x10, 0x05, 0x50, 0x06, 0x30, 0x07, 0x70, 0x09, 0x48, +0x0a, 0x28, 0x0b, 0x68, 0x0c, 0x18, 0x0d, 0x58, 0x0e, 0x38, 0x0f, 0x78, 0x11, 0x44, 0x12, 0x24, +0x13, 0x64, 0x15, 0x54, 0x16, 0x34, 0x17, 0x74, 0x19, 0x4c, 0x1a, 0x2c, 0x1b, 0x6c, 0x1d, 0x5c, +0x1e, 0x3c, 0x1f, 0x7c, 0x21, 0x42, 0x23, 0x62, 0x25, 0x52, 0x26, 0x32, 0x27, 0x72, 0x29, 0x4a, +0x2b, 0x6a, 0x2d, 0x5a, 0x2e, 0x3a, 0x2f, 0x7a, 0x31, 0x46, 0x33, 0x66, 0x35, 0x56, 0x37, 0x76, +0x39, 0x4e, 0x3b, 0x6e, 0x3d, 0x5e, 0x3f, 0x7e, 0x43, 0x61, 0x45, 0x51, 0x47, 0x71, 0x4b, 0x69, +0x4d, 0x59, 0x4f, 0x79, 0x53, 0x65, 0x57, 0x75, 0x5b, 0x6d, 0x5f, 0x7d, 0x67, 0x73, 0x6f, 0x7b, +0x00, 0x08, 0x14, 0x1c, 0x22, 0x2a, 0x36, 0x3e, 0x41, 0x49, 0x55, 0x5d, 0x63, 0x6b, 0x77, 0x7f, +0x00, +}; + +const uint8_t uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f}; + +const uint32_t twidTabOdd[8*6 + 32*6 + 128*6] PROGMEM = { + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x539eba45, 0xe7821d59, + 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, + 0x539eba45, 0xc4df2862, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x22a2f4f8, 0xc4df2862, + 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, + 0xac6145bb, 0x187de2a7, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x45f704f7, 0xf9ba1651, + 0x43103085, 0xfcdc1342, 0x48b2b335, 0xf69bf7c9, 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, + 0x4fd288dc, 0xed6bf9d1, 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, 0x553805f2, 0xe4a2eff6, + 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x569cc31b, 0xe1d4a2c8, + 0x4da1fab5, 0xf0730342, 0x5a6690ae, 0xd5052d97, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, + 0x5a12e720, 0xce86ff2a, 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, 0x57cc15bc, 0xc91af976, + 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a12e720, 0xce86ff2a, + 0x553805f2, 0xe4a2eff6, 0x4da1fab5, 0xc1eb0209, 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, + 0x45f704f7, 0xc04ee4b8, 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, 0x3cc85709, 0xc013bc39, + 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x4fd288dc, 0xc2c17d52, + 0x5987b08a, 0xd9e01006, 0x26b2a794, 0xc3bdbdf6, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, + 0x1a4608ab, 0xc78e9a1d, 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, 0x0d47d096, 0xcc983f70, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x396b3199, 0xc04ee4b8, + 0x5a6690ae, 0xd09441bb, 0xf2b82f6a, 0xd9e01006, 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, + 0xe5b9f755, 0xe1d4a2c8, 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, 0xd94d586c, 0xea70658a, + 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x1a4608ab, 0xc78e9a1d, + 0x57cc15bc, 0xc91af976, 0xc337a8f7, 0xfcdc1342, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, + 0xba08fb09, 0x0645e9af, 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, 0xb25e054b, 0x0f8cfcbe, + 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xf720e574, 0xd76619b6, + 0x51d1dc80, 0xc3bdbdf6, 0xa833ea44, 0x20e70f32, 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, + 0xa5ed18e0, 0x2899e64a, 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, 0xa5996f52, 0x2f6bbe45, + 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xd5558381, 0xed6bf9d1, + 0x48b2b335, 0xc0b15502, 0xaac7fa0e, 0x39daf5e8, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, + 0xb02d7724, 0x3d3e82ae, 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, 0xb74d4ccb, 0x3f4eaafe, + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x418d2621, 0xfe6deaa1, + 0x40c7d2bd, 0xff36f170, 0x424ff28f, 0xfda4f351, 0x43103085, 0xfcdc1342, 0x418d2621, 0xfe6deaa1, + 0x4488e37f, 0xfb4ab7db, 0x4488e37f, 0xfb4ab7db, 0x424ff28f, 0xfda4f351, 0x46aa0d6d, 0xf8f21e8e, + 0x45f704f7, 0xf9ba1651, 0x43103085, 0xfcdc1342, 0x48b2b335, 0xf69bf7c9, 0x475a5c77, 0xf82a6c6a, + 0x43cdd89a, 0xfc135231, 0x4aa22036, 0xf4491311, 0x48b2b335, 0xf69bf7c9, 0x4488e37f, 0xfb4ab7db, + 0x4c77a88e, 0xf1fa3ecb, 0x49ffd417, 0xf50ef5de, 0x454149fc, 0xfa824bfd, 0x4e32a956, 0xefb047f2, + 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x4c77a88e, 0xf1fa3ecb, + 0x46aa0d6d, 0xf8f21e8e, 0x5156b6d9, 0xeb2e1dbe, 0x4da1fab5, 0xf0730342, 0x475a5c77, 0xf82a6c6a, + 0x52beac9f, 0xe8f77acf, 0x4ec05432, 0xeeee2d9d, 0x4807eb4b, 0xf7630799, 0x5409ed4b, 0xe6c8d59c, + 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, 0x553805f2, 0xe4a2eff6, 0x50d86e6d, 0xebeca36c, + 0x495aada2, 0xf5d544a7, 0x56488dc5, 0xe28688a4, 0x51d1dc80, 0xea70658a, 0x49ffd417, 0xf50ef5de, + 0x573b2635, 0xe0745b24, 0x52beac9f, 0xe8f77acf, 0x4aa22036, 0xf4491311, 0x580f7b19, 0xde6d1f65, + 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5471e2e6, 0xe61086bc, + 0x4bde1089, 0xf2beafed, 0x595c3e2a, 0xda8249b4, 0x553805f2, 0xe4a2eff6, 0x4c77a88e, 0xf1fa3ecb, + 0x59d438e5, 0xd8a00bae, 0x55f104dc, 0xe3399167, 0x4d0e4de2, 0xf136580d, 0x5a2d0957, 0xd6cb76c9, + 0x569cc31b, 0xe1d4a2c8, 0x4da1fab5, 0xf0730342, 0x5a6690ae, 0xd5052d97, 0x573b2635, 0xe0745b24, + 0x4e32a956, 0xefb047f2, 0x5a80baf6, 0xd34dcdb4, 0x57cc15bc, 0xdf18f0ce, 0x4ec05432, 0xeeee2d9d, + 0x5a7b7f1a, 0xd1a5ef90, 0x584f7b58, 0xddc29958, 0x4f4af5d1, 0xee2cbbc1, 0x5a56deec, 0xd00e2639, + 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x592d59da, 0xdb25f566, + 0x50570819, 0xecabef3d, 0x59afaf4c, 0xcd110216, 0x5987b08a, 0xd9e01006, 0x50d86e6d, 0xebeca36c, + 0x592d59da, 0xcbacb0bf, 0x59d438e5, 0xd8a00bae, 0x5156b6d9, 0xeb2e1dbe, 0x588c1404, 0xca5a86c4, + 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, 0x57cc15bc, 0xc91af976, 0x5a43b190, 0xd6326a88, + 0x5249daa2, 0xe9b38223, 0x56eda1a0, 0xc7ee77b3, 0x5a6690ae, 0xd5052d97, 0x52beac9f, 0xe8f77acf, + 0x55f104dc, 0xc6d569be, 0x5a7b7f1a, 0xd3de9156, 0x53304df6, 0xe83c56cf, 0x54d69714, 0xc5d03118, + 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a7b7f1a, 0xd1a5ef90, + 0x5409ed4b, 0xe6c8d59c, 0x5249daa2, 0xc402a33c, 0x5a6690ae, 0xd09441bb, 0x5471e2e6, 0xe61086bc, + 0x50d86e6d, 0xc33aee27, 0x5a43b190, 0xcf89e3e8, 0x54d69714, 0xe55937d5, 0x4f4af5d1, 0xc2884e6e, + 0x5a12e720, 0xce86ff2a, 0x553805f2, 0xe4a2eff6, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xcd8bbb6d, + 0x55962bc0, 0xe3edb628, 0x4bde1089, 0xc1633f8a, 0x5987b08a, 0xcc983f70, 0x55f104dc, 0xe3399167, + 0x49ffd417, 0xc0f1360b, 0x592d59da, 0xcbacb0bf, 0x56488dc5, 0xe28688a4, 0x4807eb4b, 0xc0950d1d, + 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x584f7b58, 0xc9edeb50, + 0x56eda1a0, 0xe123e6ad, 0x43cdd89a, 0xc01ed535, 0x57cc15bc, 0xc91af976, 0x573b2635, 0xe0745b24, + 0x418d2621, 0xc004ef3f, 0x573b2635, 0xc8507ea7, 0x57854ddd, 0xdfc606f1, 0x3f35b59d, 0xc0013bd3, + 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, 0x3cc85709, 0xc013bc39, 0x55f104dc, 0xc6d569be, + 0x580f7b19, 0xde6d1f65, 0x3a45e1f7, 0xc03c6a07, 0x553805f2, 0xc6250a18, 0x584f7b58, 0xddc29958, + 0x37af354c, 0xc07b371e, 0x5471e2e6, 0xc57d965d, 0x588c1404, 0xdd196538, 0x350536f1, 0xc0d00db6, + 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x52beac9f, 0xc449d892, + 0x58fb0568, 0xdbcb0cce, 0x2f7afdfc, 0xc1bb5a11, 0x51d1dc80, 0xc3bdbdf6, 0x592d59da, 0xdb25f566, + 0x2c9caf6c, 0xc2517e31, 0x50d86e6d, 0xc33aee27, 0x595c3e2a, 0xda8249b4, 0x29aee694, 0xc2fd08a9, + 0x4fd288dc, 0xc2c17d52, 0x5987b08a, 0xd9e01006, 0x26b2a794, 0xc3bdbdf6, 0x4ec05432, 0xc2517e31, + 0x59afaf4c, 0xd93f4e9e, 0x23a8fb93, 0xc4935b3c, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xd8a00bae, + 0x2092f05f, 0xc57d965d, 0x4c77a88e, 0xc18e18a7, 0x59f54bee, 0xd8024d59, 0x1d719810, 0xc67c1e18, + 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x49ffd417, 0xc0f1360b, + 0x5a2d0957, 0xd6cb76c9, 0x17115bc0, 0xc8b4ab32, 0x48b2b335, 0xc0b15502, 0x5a43b190, 0xd6326a88, + 0x13d4ae08, 0xc9edeb50, 0x475a5c77, 0xc07b371e, 0x5a56deec, 0xd59afadb, 0x10911f04, 0xcb39edca, + 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, 0x0d47d096, 0xcc983f70, 0x4488e37f, 0xc02c64a6, + 0x5a72c63b, 0xd4710883, 0x09f9e6a1, 0xce0866b8, 0x43103085, 0xc013bc39, 0x5a7b7f1a, 0xd3de9156, + 0x06a886a0, 0xcf89e3e8, 0x418d2621, 0xc004ef3f, 0x5a80baf6, 0xd34dcdb4, 0x0354d741, 0xd11c3142, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3e68fb62, 0xc004ef3f, + 0x5a80baf6, 0xd2317756, 0xfcab28bf, 0xd4710883, 0x3cc85709, 0xc013bc39, 0x5a7b7f1a, 0xd1a5ef90, + 0xf9577960, 0xd6326a88, 0x3b1e5335, 0xc02c64a6, 0x5a72c63b, 0xd11c3142, 0xf606195f, 0xd8024d59, + 0x396b3199, 0xc04ee4b8, 0x5a6690ae, 0xd09441bb, 0xf2b82f6a, 0xd9e01006, 0x37af354c, 0xc07b371e, + 0x5a56deec, 0xd00e2639, 0xef6ee0fc, 0xdbcb0cce, 0x35eaa2c7, 0xc0b15502, 0x5a43b190, 0xcf89e3e8, + 0xec2b51f8, 0xddc29958, 0x341dbfd3, 0xc0f1360b, 0x5a2d0957, 0xcf077fe1, 0xe8eea440, 0xdfc606f1, + 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x306c2624, 0xc18e18a7, + 0x59f54bee, 0xce0866b8, 0xe28e67f0, 0xe3edb628, 0x2e88013a, 0xc1eb0209, 0x59d438e5, 0xcd8bbb6d, + 0xdf6d0fa1, 0xe61086bc, 0x2c9caf6c, 0xc2517e31, 0x59afaf4c, 0xcd110216, 0xdc57046d, 0xe83c56cf, + 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, 0xd94d586c, 0xea70658a, 0x28b1b544, 0xc33aee27, + 0x595c3e2a, 0xcc217822, 0xd651196c, 0xecabef3d, 0x26b2a794, 0xc3bdbdf6, 0x592d59da, 0xcbacb0bf, + 0xd3635094, 0xeeee2d9d, 0x24ada23d, 0xc449d892, 0x58fb0568, 0xcb39edca, 0xd0850204, 0xf136580d, + 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x2092f05f, 0xc57d965d, + 0x588c1404, 0xca5a86c4, 0xcafac90f, 0xf5d544a7, 0x1e7de5df, 0xc6250a18, 0x584f7b58, 0xc9edeb50, + 0xc850cab4, 0xf82a6c6a, 0x1c6427a9, 0xc6d569be, 0x580f7b19, 0xc9836582, 0xc5ba1e09, 0xfa824bfd, + 0x1a4608ab, 0xc78e9a1d, 0x57cc15bc, 0xc91af976, 0xc337a8f7, 0xfcdc1342, 0x1823dc7d, 0xc8507ea7, + 0x57854ddd, 0xc8b4ab32, 0xc0ca4a63, 0xff36f170, 0x15fdf758, 0xc91af976, 0x573b2635, 0xc8507ea7, + 0xbe72d9df, 0x0192155f, 0x13d4ae08, 0xc9edeb50, 0x56eda1a0, 0xc7ee77b3, 0xbc322766, 0x03ecadcf, + 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x0f7944a7, 0xcbacb0bf, + 0x56488dc5, 0xc730e997, 0xb7f814b5, 0x089cf867, 0x0d47d096, 0xcc983f70, 0x55f104dc, 0xc6d569be, + 0xb6002be9, 0x0af10a22, 0x0b145041, 0xcd8bbb6d, 0x55962bc0, 0xc67c1e18, 0xb421ef77, 0x0d415013, + 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, 0xb25e054b, 0x0f8cfcbe, 0x06a886a0, 0xcf89e3e8, + 0x54d69714, 0xc5d03118, 0xb0b50a2f, 0x11d3443f, 0x0470ebdc, 0xd09441bb, 0x5471e2e6, 0xc57d965d, + 0xaf279193, 0x14135c94, 0x0238a1c6, 0xd1a5ef90, 0x5409ed4b, 0xc52d3d18, 0xadb6255e, 0x164c7ddd, + 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xfdc75e3a, 0xd3de9156, + 0x53304df6, 0xc4935b3c, 0xab2968ec, 0x1aa6c82b, 0xfb8f1424, 0xd5052d97, 0x52beac9f, 0xc449d892, + 0xaa0efb24, 0x1cc66e99, 0xf9577960, 0xd6326a88, 0x5249daa2, 0xc402a33c, 0xa9125e60, 0x1edc1953, + 0xf720e574, 0xd76619b6, 0x51d1dc80, 0xc3bdbdf6, 0xa833ea44, 0x20e70f32, 0xf4ebafbf, 0xd8a00bae, + 0x5156b6d9, 0xc37b2b6a, 0xa773ebfc, 0x22e69ac8, 0xf2b82f6a, 0xd9e01006, 0x50d86e6d, 0xc33aee27, + 0xa6d2a626, 0x24da0a9a, 0xf086bb59, 0xdb25f566, 0x50570819, 0xc2fd08a9, 0xa65050b4, 0x26c0b162, + 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xec2b51f8, 0xddc29958, + 0x4f4af5d1, 0xc2884e6e, 0xa5a92114, 0x2a650525, 0xea0208a8, 0xdf18f0ce, 0x4ec05432, 0xc2517e31, + 0xa58480e6, 0x2c216eaa, 0xe7dc2383, 0xe0745b24, 0x4e32a956, 0xc21d0eb8, 0xa57f450a, 0x2dce88aa, + 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, 0xa5996f52, 0x2f6bbe45, 0xe39bd857, 0xe3399167, + 0x4d0e4de2, 0xc1bb5a11, 0xa5d2f6a9, 0x30f8801f, 0xe1821a21, 0xe4a2eff6, 0x4c77a88e, 0xc18e18a7, + 0xa62bc71b, 0x32744493, 0xdf6d0fa1, 0xe61086bc, 0x4bde1089, 0xc1633f8a, 0xa6a3c1d6, 0x33de87de, + 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xdb525dc3, 0xe8f77acf, + 0x4aa22036, 0xc114ccb9, 0xa7f084e7, 0x367c9a7e, 0xd94d586c, 0xea70658a, 0x49ffd417, 0xc0f1360b, + 0xa8c4d9cb, 0x37af8159, 0xd74e4abc, 0xebeca36c, 0x495aada2, 0xc0d00db6, 0xa9b7723b, 0x38cf1669, + 0xd5558381, 0xed6bf9d1, 0x48b2b335, 0xc0b15502, 0xaac7fa0e, 0x39daf5e8, 0xd3635094, 0xeeee2d9d, + 0x4807eb4b, 0xc0950d1d, 0xabf612b5, 0x3ad2c2e8, 0xd177fec6, 0xf0730342, 0x475a5c77, 0xc07b371e, + 0xad415361, 0x3bb6276e, 0xcf93d9dc, 0xf1fa3ecb, 0x46aa0d6d, 0xc063d405, 0xaea94927, 0x3c84d496, + 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0xcbe2402d, 0xf50ef5de, + 0x454149fc, 0xc03c6a07, 0xb1cd56aa, 0x3de2f148, 0xca155d39, 0xf69bf7c9, 0x4488e37f, 0xc02c64a6, + 0xb3885772, 0x3e71e759, 0xc850cab4, 0xf82a6c6a, 0x43cdd89a, 0xc01ed535, 0xb55ddfca, 0x3eeb3347, + 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, 0xb74d4ccb, 0x3f4eaafe, 0xc4e1accb, 0xfb4ab7db, + 0x424ff28f, 0xc00b1a20, 0xb955f293, 0x3f9c2bfb, 0xc337a8f7, 0xfcdc1342, 0x418d2621, 0xc004ef3f, + 0xbb771c81, 0x3fd39b5a, 0xc197049e, 0xfe6deaa1, 0x40c7d2bd, 0xc0013bd3, 0xbdb00d71, 0x3ff4e5e0, +}; + +const uint32_t twidTabEven[4*6 + 16*6 + 64*6] PROGMEM = { + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x5a82799a, 0xd2bec333, + 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, + 0x00000000, 0xd2bec333, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x4b418bbe, 0xf383a3e2, + 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, + 0x58c542c5, 0xdc71898d, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, + 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xcac933ae, + 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, + 0x3248d382, 0xc13ad060, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3248d382, 0xc13ad060, + 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, + 0xcdb72c7e, 0xf383a3e2, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, + 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xee57aa21, 0xdc71898d, + 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, + 0xa73abd3b, 0x3536cc52, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x43103085, 0xfcdc1342, + 0x418d2621, 0xfe6deaa1, 0x4488e37f, 0xfb4ab7db, 0x45f704f7, 0xf9ba1651, 0x43103085, 0xfcdc1342, + 0x48b2b335, 0xf69bf7c9, 0x48b2b335, 0xf69bf7c9, 0x4488e37f, 0xfb4ab7db, 0x4c77a88e, 0xf1fa3ecb, + 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x4da1fab5, 0xf0730342, + 0x475a5c77, 0xf82a6c6a, 0x52beac9f, 0xe8f77acf, 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, + 0x553805f2, 0xe4a2eff6, 0x51d1dc80, 0xea70658a, 0x49ffd417, 0xf50ef5de, 0x573b2635, 0xe0745b24, + 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x553805f2, 0xe4a2eff6, + 0x4c77a88e, 0xf1fa3ecb, 0x59d438e5, 0xd8a00bae, 0x569cc31b, 0xe1d4a2c8, 0x4da1fab5, 0xf0730342, + 0x5a6690ae, 0xd5052d97, 0x57cc15bc, 0xdf18f0ce, 0x4ec05432, 0xeeee2d9d, 0x5a7b7f1a, 0xd1a5ef90, + 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x5987b08a, 0xd9e01006, + 0x50d86e6d, 0xebeca36c, 0x592d59da, 0xcbacb0bf, 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, + 0x57cc15bc, 0xc91af976, 0x5a6690ae, 0xd5052d97, 0x52beac9f, 0xe8f77acf, 0x55f104dc, 0xc6d569be, + 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a6690ae, 0xd09441bb, + 0x5471e2e6, 0xe61086bc, 0x50d86e6d, 0xc33aee27, 0x5a12e720, 0xce86ff2a, 0x553805f2, 0xe4a2eff6, + 0x4da1fab5, 0xc1eb0209, 0x5987b08a, 0xcc983f70, 0x55f104dc, 0xe3399167, 0x49ffd417, 0xc0f1360b, + 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x57cc15bc, 0xc91af976, + 0x573b2635, 0xe0745b24, 0x418d2621, 0xc004ef3f, 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, + 0x3cc85709, 0xc013bc39, 0x553805f2, 0xc6250a18, 0x584f7b58, 0xddc29958, 0x37af354c, 0xc07b371e, + 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x51d1dc80, 0xc3bdbdf6, + 0x592d59da, 0xdb25f566, 0x2c9caf6c, 0xc2517e31, 0x4fd288dc, 0xc2c17d52, 0x5987b08a, 0xd9e01006, + 0x26b2a794, 0xc3bdbdf6, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xd8a00bae, 0x2092f05f, 0xc57d965d, + 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x48b2b335, 0xc0b15502, + 0x5a43b190, 0xd6326a88, 0x13d4ae08, 0xc9edeb50, 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, + 0x0d47d096, 0xcc983f70, 0x43103085, 0xc013bc39, 0x5a7b7f1a, 0xd3de9156, 0x06a886a0, 0xcf89e3e8, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3cc85709, 0xc013bc39, + 0x5a7b7f1a, 0xd1a5ef90, 0xf9577960, 0xd6326a88, 0x396b3199, 0xc04ee4b8, 0x5a6690ae, 0xd09441bb, + 0xf2b82f6a, 0xd9e01006, 0x35eaa2c7, 0xc0b15502, 0x5a43b190, 0xcf89e3e8, 0xec2b51f8, 0xddc29958, + 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x2e88013a, 0xc1eb0209, + 0x59d438e5, 0xcd8bbb6d, 0xdf6d0fa1, 0xe61086bc, 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, + 0xd94d586c, 0xea70658a, 0x26b2a794, 0xc3bdbdf6, 0x592d59da, 0xcbacb0bf, 0xd3635094, 0xeeee2d9d, + 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x1e7de5df, 0xc6250a18, + 0x584f7b58, 0xc9edeb50, 0xc850cab4, 0xf82a6c6a, 0x1a4608ab, 0xc78e9a1d, 0x57cc15bc, 0xc91af976, + 0xc337a8f7, 0xfcdc1342, 0x15fdf758, 0xc91af976, 0x573b2635, 0xc8507ea7, 0xbe72d9df, 0x0192155f, + 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x0d47d096, 0xcc983f70, + 0x55f104dc, 0xc6d569be, 0xb6002be9, 0x0af10a22, 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, + 0xb25e054b, 0x0f8cfcbe, 0x0470ebdc, 0xd09441bb, 0x5471e2e6, 0xc57d965d, 0xaf279193, 0x14135c94, + 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xfb8f1424, 0xd5052d97, + 0x52beac9f, 0xc449d892, 0xaa0efb24, 0x1cc66e99, 0xf720e574, 0xd76619b6, 0x51d1dc80, 0xc3bdbdf6, + 0xa833ea44, 0x20e70f32, 0xf2b82f6a, 0xd9e01006, 0x50d86e6d, 0xc33aee27, 0xa6d2a626, 0x24da0a9a, + 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xea0208a8, 0xdf18f0ce, + 0x4ec05432, 0xc2517e31, 0xa58480e6, 0x2c216eaa, 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, + 0xa5996f52, 0x2f6bbe45, 0xe1821a21, 0xe4a2eff6, 0x4c77a88e, 0xc18e18a7, 0xa62bc71b, 0x32744493, + 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xd94d586c, 0xea70658a, + 0x49ffd417, 0xc0f1360b, 0xa8c4d9cb, 0x37af8159, 0xd5558381, 0xed6bf9d1, 0x48b2b335, 0xc0b15502, + 0xaac7fa0e, 0x39daf5e8, 0xd177fec6, 0xf0730342, 0x475a5c77, 0xc07b371e, 0xad415361, 0x3bb6276e, + 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0xca155d39, 0xf69bf7c9, + 0x4488e37f, 0xc02c64a6, 0xb3885772, 0x3e71e759, 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, + 0xb74d4ccb, 0x3f4eaafe, 0xc337a8f7, 0xfcdc1342, 0x418d2621, 0xc004ef3f, 0xbb771c81, 0x3fd39b5a, +}; + +/* log2Tab[x] = floor(log2(x)), format = Q28 */ +const int32_t log2Tab[65] PROGMEM = { + 0x00000000, 0x00000000, 0x10000000, 0x195c01a3, 0x20000000, 0x25269e12, 0x295c01a3, 0x2ceaecfe, + 0x30000000, 0x32b80347, 0x35269e12, 0x3759d4f8, 0x395c01a3, 0x3b350047, 0x3ceaecfe, 0x3e829fb6, + 0x40000000, 0x41663f6f, 0x42b80347, 0x43f782d7, 0x45269e12, 0x4646eea2, 0x4759d4f8, 0x48608280, + 0x495c01a3, 0x4a4d3c25, 0x4b350047, 0x4c1404ea, 0x4ceaecfe, 0x4dba4a47, 0x4e829fb6, 0x4f446359, + 0x50000000, 0x50b5d69b, 0x51663f6f, 0x52118b11, 0x52b80347, 0x5359ebc5, 0x53f782d7, 0x549101ea, + 0x55269e12, 0x55b88873, 0x5646eea2, 0x56d1fafd, 0x5759d4f8, 0x57dea15a, 0x58608280, 0x58df988f, + 0x595c01a3, 0x59d5d9fd, 0x5a4d3c25, 0x5ac24113, 0x5b350047, 0x5ba58feb, 0x5c1404ea, 0x5c80730b, + 0x5ceaecfe, 0x5d53847a, 0x5dba4a47, 0x5e1f4e51, 0x5e829fb6, 0x5ee44cd5, 0x5f446359, 0x5fa2f045, + 0x60000000 +}; + +const HuffInfo_t huffTabSpecInfo[11] PROGMEM = { + /* table 0 not used */ + {11, { 1, 0, 0, 0, 8, 0, 24, 0, 24, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0}, + { 9, { 0, 0, 1, 1, 7, 24, 15, 19, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 81}, + {16, { 1, 0, 0, 4, 2, 6, 3, 5, 15, 15, 8, 9, 3, 3, 5, 2, 0, 0, 0, 0}, 162}, + {12, { 0, 0, 0, 10, 6, 0, 9, 21, 8, 14, 11, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 243}, + {13, { 1, 0, 0, 4, 4, 0, 4, 12, 12, 12, 18, 10, 4, 0, 0, 0, 0, 0, 0, 0}, 324}, + {11, { 0, 0, 0, 9, 0, 16, 13, 8, 23, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 405}, + {12, { 1, 0, 2, 1, 0, 4, 5, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 486}, + {10, { 0, 0, 1, 5, 7, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 550}, + {15, { 1, 0, 2, 1, 0, 4, 3, 8, 11, 20, 31, 38, 32, 14, 4, 0, 0, 0, 0, 0}, 614}, + {12, { 0, 0, 0, 3, 8, 14, 17, 25, 31, 41, 22, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 783}, + {12, { 0, 0, 0, 2, 6, 7, 16, 59, 55, 95, 43, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 952}, +}; + +const int16_t huffTabSpec[1241] PROGMEM = { + /* spectrum table 1 [81] (signed) */ + 0x0000, 0x0200, 0x0e00, 0x0007, 0x0040, 0x0001, 0x0038, 0x0008, 0x01c0, 0x03c0, 0x0e40, 0x0039, 0x0078, 0x01c8, 0x000f, 0x0240, + 0x003f, 0x0fc0, 0x01f8, 0x0238, 0x0047, 0x0e08, 0x0009, 0x0208, 0x01c1, 0x0048, 0x0041, 0x0e38, 0x0201, 0x0e07, 0x0207, 0x0e01, + 0x01c7, 0x0278, 0x0e78, 0x03c8, 0x004f, 0x0079, 0x01c9, 0x01cf, 0x03f8, 0x0239, 0x007f, 0x0e48, 0x0e0f, 0x0fc8, 0x01f9, 0x03c1, + 0x03c7, 0x0e47, 0x0ff8, 0x01ff, 0x0049, 0x020f, 0x0241, 0x0e41, 0x0248, 0x0fc1, 0x0e3f, 0x0247, 0x023f, 0x0e39, 0x0fc7, 0x0e09, + 0x0209, 0x03cf, 0x0e79, 0x0e4f, 0x03f9, 0x0249, 0x0fc9, 0x027f, 0x0fcf, 0x0fff, 0x0279, 0x03c9, 0x0e49, 0x0e7f, 0x0ff9, 0x03ff, + 0x024f, + /* spectrum table 2 [81] (signed) */ + 0x0000, 0x0200, 0x0e00, 0x0001, 0x0038, 0x0007, 0x01c0, 0x0008, 0x0040, 0x01c8, 0x0e40, 0x0078, 0x000f, 0x0047, 0x0039, 0x0e07, + 0x03c0, 0x0238, 0x0fc0, 0x003f, 0x0208, 0x0201, 0x01c1, 0x0e08, 0x0041, 0x01f8, 0x0e01, 0x01c7, 0x0e38, 0x0240, 0x0048, 0x0009, + 0x0207, 0x0079, 0x0239, 0x0e78, 0x01cf, 0x03c8, 0x0247, 0x0209, 0x0e48, 0x01f9, 0x0248, 0x0e0f, 0x0ff8, 0x0e39, 0x03f8, 0x0278, + 0x03c1, 0x0e47, 0x0fc8, 0x0e09, 0x0fc1, 0x0fc7, 0x01ff, 0x020f, 0x023f, 0x007f, 0x0049, 0x0e41, 0x0e3f, 0x004f, 0x03c7, 0x01c9, + 0x0241, 0x03cf, 0x0e79, 0x03f9, 0x0fff, 0x0e4f, 0x0e49, 0x0249, 0x0fcf, 0x03c9, 0x0e7f, 0x0fc9, 0x027f, 0x03ff, 0x0ff9, 0x0279, + 0x024f, + /* spectrum table 3 [81] (unsigned) */ + 0x0000, 0x1200, 0x1001, 0x1040, 0x1008, 0x2240, 0x2009, 0x2048, 0x2041, 0x2208, 0x3049, 0x2201, 0x3248, 0x4249, 0x3209, 0x3241, + 0x1400, 0x1002, 0x200a, 0x2440, 0x3288, 0x2011, 0x3051, 0x2280, 0x304a, 0x3448, 0x1010, 0x2088, 0x2050, 0x1080, 0x2042, 0x2408, + 0x4289, 0x3089, 0x3250, 0x4251, 0x3281, 0x2210, 0x3211, 0x2081, 0x4449, 0x424a, 0x3441, 0x320a, 0x2012, 0x3052, 0x3488, 0x3290, + 0x2202, 0x2401, 0x3091, 0x2480, 0x4291, 0x3242, 0x3409, 0x4252, 0x4489, 0x2090, 0x308a, 0x3212, 0x3481, 0x3450, 0x3490, 0x3092, + 0x4491, 0x4451, 0x428a, 0x4292, 0x2082, 0x2410, 0x3282, 0x3411, 0x444a, 0x3442, 0x4492, 0x448a, 0x4452, 0x340a, 0x2402, 0x3482, + 0x3412, + /* spectrum table 4 [81] (unsigned) */ + 0x4249, 0x3049, 0x3241, 0x3248, 0x3209, 0x1200, 0x2240, 0x0000, 0x2009, 0x2208, 0x2201, 0x2048, 0x1001, 0x2041, 0x1008, 0x1040, + 0x4449, 0x4251, 0x4289, 0x424a, 0x3448, 0x3441, 0x3288, 0x3409, 0x3051, 0x304a, 0x3250, 0x3089, 0x320a, 0x3281, 0x3242, 0x3211, + 0x2440, 0x2408, 0x2280, 0x2401, 0x2042, 0x2088, 0x200a, 0x2050, 0x2081, 0x2202, 0x2011, 0x2210, 0x1400, 0x1002, 0x1080, 0x1010, + 0x4291, 0x4489, 0x4451, 0x4252, 0x428a, 0x444a, 0x3290, 0x3488, 0x3450, 0x3091, 0x3052, 0x3481, 0x308a, 0x3411, 0x3212, 0x4491, + 0x3282, 0x340a, 0x3442, 0x4292, 0x4452, 0x448a, 0x2090, 0x2480, 0x2012, 0x2410, 0x2082, 0x2402, 0x4492, 0x3092, 0x3490, 0x3482, + 0x3412, + /* spectrum table 5 [81] (signed) */ + 0x0000, 0x03e0, 0x0020, 0x0001, 0x001f, 0x003f, 0x03e1, 0x03ff, 0x0021, 0x03c0, 0x0002, 0x0040, 0x001e, 0x03df, 0x0041, 0x03fe, + 0x0022, 0x03c1, 0x005f, 0x03e2, 0x003e, 0x03a0, 0x0060, 0x001d, 0x0003, 0x03bf, 0x0023, 0x0061, 0x03fd, 0x03a1, 0x007f, 0x003d, + 0x03e3, 0x03c2, 0x0042, 0x03de, 0x005e, 0x03be, 0x007e, 0x03c3, 0x005d, 0x0062, 0x0043, 0x03a2, 0x03dd, 0x001c, 0x0380, 0x0081, + 0x0080, 0x039f, 0x0004, 0x009f, 0x03fc, 0x0024, 0x03e4, 0x0381, 0x003c, 0x007d, 0x03bd, 0x03a3, 0x03c4, 0x039e, 0x0082, 0x005c, + 0x0044, 0x0063, 0x0382, 0x03dc, 0x009e, 0x007c, 0x039d, 0x0383, 0x0064, 0x03a4, 0x0083, 0x009d, 0x03bc, 0x009c, 0x0384, 0x0084, + 0x039c, + /* spectrum table 6 [81] (signed) */ + 0x0000, 0x0020, 0x001f, 0x0001, 0x03e0, 0x0021, 0x03e1, 0x003f, 0x03ff, 0x005f, 0x0041, 0x03c1, 0x03df, 0x03c0, 0x03e2, 0x0040, + 0x003e, 0x0022, 0x001e, 0x03fe, 0x0002, 0x005e, 0x03c2, 0x03de, 0x0042, 0x03a1, 0x0061, 0x007f, 0x03e3, 0x03bf, 0x0023, 0x003d, + 0x03fd, 0x0060, 0x03a0, 0x001d, 0x0003, 0x0062, 0x03be, 0x03c3, 0x0043, 0x007e, 0x005d, 0x03dd, 0x03a2, 0x0063, 0x007d, 0x03bd, + 0x03a3, 0x003c, 0x03fc, 0x0081, 0x0381, 0x039f, 0x0024, 0x009f, 0x03e4, 0x001c, 0x0382, 0x039e, 0x0044, 0x03dc, 0x0380, 0x0082, + 0x009e, 0x03c4, 0x0080, 0x005c, 0x0004, 0x03bc, 0x03a4, 0x007c, 0x009d, 0x0064, 0x0083, 0x0383, 0x039d, 0x0084, 0x0384, 0x039c, + 0x009c, + /* spectrum table 7 [64] (unsigned) */ + 0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0823, 0x0842, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824, + 0x0881, 0x0825, 0x08a1, 0x0863, 0x0844, 0x0404, 0x0480, 0x0882, 0x0845, 0x08a2, 0x0405, 0x08c1, 0x04a0, 0x0826, 0x0883, 0x0865, + 0x0864, 0x08a3, 0x0846, 0x08c2, 0x0827, 0x0866, 0x0406, 0x04c0, 0x0884, 0x08e1, 0x0885, 0x08e2, 0x08a4, 0x08c3, 0x0847, 0x08e3, + 0x08c4, 0x08a5, 0x0886, 0x0867, 0x04e0, 0x0407, 0x08c5, 0x08a6, 0x08e4, 0x0887, 0x08a7, 0x08e5, 0x08e6, 0x08c6, 0x08c7, 0x08e7, + /* spectrum table 8 [64] (unsigned) */ + 0x0821, 0x0841, 0x0420, 0x0822, 0x0401, 0x0842, 0x0000, 0x0440, 0x0402, 0x0861, 0x0823, 0x0862, 0x0843, 0x0863, 0x0881, 0x0824, + 0x0882, 0x0844, 0x0460, 0x0403, 0x0883, 0x0864, 0x08a2, 0x08a1, 0x0845, 0x0825, 0x08a3, 0x0865, 0x0884, 0x08a4, 0x0404, 0x0885, + 0x0480, 0x0846, 0x08c2, 0x08c1, 0x0826, 0x0866, 0x08c3, 0x08a5, 0x04a0, 0x08c4, 0x0405, 0x0886, 0x08e1, 0x08e2, 0x0847, 0x08c5, + 0x08e3, 0x0827, 0x08a6, 0x0867, 0x08c6, 0x08e4, 0x04c0, 0x0887, 0x0406, 0x08e5, 0x08e6, 0x08c7, 0x08a7, 0x04e0, 0x0407, 0x08e7, + /* spectrum table 9 [169] (unsigned) */ + 0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0842, 0x0823, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824, + 0x0881, 0x0844, 0x0825, 0x0882, 0x0863, 0x0404, 0x0480, 0x08a1, 0x0845, 0x0826, 0x0864, 0x08a2, 0x08c1, 0x0883, 0x0405, 0x0846, + 0x04a0, 0x0827, 0x0865, 0x0828, 0x0901, 0x0884, 0x08a3, 0x08c2, 0x08e1, 0x0406, 0x0902, 0x0848, 0x0866, 0x0847, 0x0885, 0x0921, + 0x0829, 0x08e2, 0x04c0, 0x08a4, 0x08c3, 0x0903, 0x0407, 0x0922, 0x0868, 0x0886, 0x0867, 0x0408, 0x0941, 0x08c4, 0x0849, 0x08a5, + 0x0500, 0x04e0, 0x08e3, 0x0942, 0x0923, 0x0904, 0x082a, 0x08e4, 0x08c5, 0x08a6, 0x0888, 0x0887, 0x0869, 0x0961, 0x08a8, 0x0520, + 0x0905, 0x0943, 0x084a, 0x0409, 0x0962, 0x0924, 0x08c6, 0x0981, 0x0889, 0x0906, 0x082b, 0x0925, 0x0944, 0x08a7, 0x08e5, 0x084b, + 0x082c, 0x0982, 0x0963, 0x086a, 0x08a9, 0x08c7, 0x0907, 0x0964, 0x040a, 0x08e6, 0x0983, 0x0540, 0x0945, 0x088a, 0x08c8, 0x084c, + 0x0926, 0x0927, 0x088b, 0x0560, 0x08c9, 0x086b, 0x08aa, 0x0908, 0x08e8, 0x0985, 0x086c, 0x0965, 0x08e7, 0x0984, 0x0966, 0x0946, + 0x088c, 0x08e9, 0x08ab, 0x040b, 0x0986, 0x08ca, 0x0580, 0x0947, 0x08ac, 0x08ea, 0x0928, 0x040c, 0x0967, 0x0909, 0x0929, 0x0948, + 0x08eb, 0x0987, 0x08cb, 0x090b, 0x0968, 0x08ec, 0x08cc, 0x090a, 0x0949, 0x090c, 0x092a, 0x092b, 0x092c, 0x094b, 0x0989, 0x094a, + 0x0969, 0x0988, 0x096a, 0x098a, 0x098b, 0x094c, 0x096b, 0x096c, 0x098c, + /* spectrum table 10 [169] (unsigned) */ + 0x0821, 0x0822, 0x0841, 0x0842, 0x0420, 0x0401, 0x0823, 0x0862, 0x0861, 0x0843, 0x0863, 0x0440, 0x0402, 0x0844, 0x0882, 0x0824, + 0x0881, 0x0000, 0x0883, 0x0864, 0x0460, 0x0403, 0x0884, 0x0845, 0x08a2, 0x0825, 0x08a1, 0x08a3, 0x0865, 0x08a4, 0x0885, 0x08c2, + 0x0846, 0x08c3, 0x0480, 0x08c1, 0x0404, 0x0826, 0x0866, 0x08a5, 0x08c4, 0x0886, 0x08c5, 0x08e2, 0x0867, 0x0847, 0x08a6, 0x0902, + 0x08e3, 0x04a0, 0x08e1, 0x0405, 0x0901, 0x0827, 0x0903, 0x08e4, 0x0887, 0x0848, 0x08c6, 0x08e5, 0x0828, 0x0868, 0x0904, 0x0888, + 0x08a7, 0x0905, 0x08a8, 0x08e6, 0x08c7, 0x0922, 0x04c0, 0x08c8, 0x0923, 0x0869, 0x0921, 0x0849, 0x0406, 0x0906, 0x0924, 0x0889, + 0x0942, 0x0829, 0x08e7, 0x0907, 0x0925, 0x08e8, 0x0943, 0x08a9, 0x0944, 0x084a, 0x0941, 0x086a, 0x0926, 0x08c9, 0x0500, 0x088a, + 0x04e0, 0x0962, 0x08e9, 0x0963, 0x0946, 0x082a, 0x0961, 0x0927, 0x0407, 0x0908, 0x0945, 0x086b, 0x08aa, 0x0909, 0x0965, 0x0408, + 0x0964, 0x084b, 0x08ea, 0x08ca, 0x0947, 0x088b, 0x082b, 0x0982, 0x0928, 0x0983, 0x0966, 0x08ab, 0x0984, 0x0967, 0x0985, 0x086c, + 0x08cb, 0x0520, 0x0948, 0x0540, 0x0981, 0x0409, 0x088c, 0x0929, 0x0986, 0x084c, 0x090a, 0x092a, 0x082c, 0x0968, 0x0987, 0x08eb, + 0x08ac, 0x08cc, 0x0949, 0x090b, 0x0988, 0x040a, 0x08ec, 0x0560, 0x094a, 0x0969, 0x096a, 0x040b, 0x096b, 0x092b, 0x094b, 0x0580, + 0x090c, 0x0989, 0x094c, 0x092c, 0x096c, 0x098b, 0x040c, 0x098a, 0x098c, + /* spectrum table 11 [289] (unsigned) */ + 0x0000, 0x2041, 0x2410, 0x1040, 0x1001, 0x2081, 0x2042, 0x2082, 0x2043, 0x20c1, 0x20c2, 0x1080, 0x2083, 0x1002, 0x20c3, 0x2101, + 0x2044, 0x2102, 0x2084, 0x2103, 0x20c4, 0x10c0, 0x1003, 0x2141, 0x2142, 0x2085, 0x2104, 0x2045, 0x2143, 0x20c5, 0x2144, 0x2105, + 0x2182, 0x2086, 0x2181, 0x2183, 0x20c6, 0x2046, 0x2110, 0x20d0, 0x2405, 0x2403, 0x2404, 0x2184, 0x2406, 0x1100, 0x2106, 0x1004, + 0x2090, 0x2145, 0x2150, 0x2407, 0x2402, 0x2408, 0x2087, 0x21c2, 0x20c7, 0x2185, 0x2146, 0x2190, 0x240a, 0x21c3, 0x21c1, 0x2409, + 0x21d0, 0x2050, 0x2047, 0x2107, 0x240b, 0x21c4, 0x240c, 0x2210, 0x2401, 0x2186, 0x2250, 0x2088, 0x2147, 0x2290, 0x240d, 0x2203, + 0x2202, 0x20c8, 0x1140, 0x240e, 0x22d0, 0x21c5, 0x2108, 0x2187, 0x21c6, 0x1005, 0x2204, 0x240f, 0x2310, 0x2048, 0x2201, 0x2390, + 0x2148, 0x2350, 0x20c9, 0x2205, 0x21c7, 0x2089, 0x2206, 0x2242, 0x2243, 0x23d0, 0x2109, 0x2188, 0x1180, 0x2244, 0x2149, 0x2207, + 0x21c8, 0x2049, 0x2283, 0x1006, 0x2282, 0x2241, 0x2245, 0x210a, 0x208a, 0x2246, 0x20ca, 0x2189, 0x2284, 0x2208, 0x2285, 0x2247, + 0x22c3, 0x204a, 0x11c0, 0x2286, 0x21c9, 0x20cb, 0x214a, 0x2281, 0x210b, 0x22c2, 0x2342, 0x218a, 0x2343, 0x208b, 0x1400, 0x214b, + 0x22c5, 0x22c4, 0x2248, 0x21ca, 0x2209, 0x1010, 0x210d, 0x1007, 0x20cd, 0x22c6, 0x2341, 0x2344, 0x2303, 0x208d, 0x2345, 0x220a, + 0x218b, 0x2288, 0x2287, 0x2382, 0x2304, 0x204b, 0x210c, 0x22c1, 0x20cc, 0x204d, 0x2302, 0x21cb, 0x20ce, 0x214c, 0x214d, 0x2384, + 0x210e, 0x22c7, 0x2383, 0x2305, 0x2346, 0x2306, 0x1200, 0x22c8, 0x208c, 0x2249, 0x2385, 0x218d, 0x228a, 0x23c2, 0x220b, 0x224a, + 0x2386, 0x2289, 0x214e, 0x22c9, 0x2381, 0x208e, 0x218c, 0x204c, 0x2348, 0x1008, 0x2347, 0x21cc, 0x2307, 0x21cd, 0x23c3, 0x2301, + 0x218e, 0x208f, 0x23c5, 0x23c4, 0x204e, 0x224b, 0x210f, 0x2387, 0x220d, 0x2349, 0x220c, 0x214f, 0x20cf, 0x228b, 0x22ca, 0x2308, + 0x23c6, 0x23c7, 0x220e, 0x23c1, 0x21ce, 0x1240, 0x1009, 0x224d, 0x224c, 0x2309, 0x2388, 0x228d, 0x2389, 0x230a, 0x218f, 0x21cf, + 0x224e, 0x23c8, 0x22cb, 0x22ce, 0x204f, 0x228c, 0x228e, 0x234b, 0x234a, 0x22cd, 0x22cc, 0x220f, 0x238b, 0x234c, 0x230d, 0x23c9, + 0x238a, 0x1280, 0x230b, 0x224f, 0x100a, 0x230c, 0x12c0, 0x230e, 0x228f, 0x234d, 0x100d, 0x238c, 0x23ca, 0x23cb, 0x22cf, 0x238d, + 0x1340, 0x100b, 0x234e, 0x23cc, 0x23cd, 0x230f, 0x1380, 0x238e, 0x234f, 0x1300, 0x238f, 0x100e, 0x100c, 0x23ce, 0x13c0, 0x100f, + 0x23cf, +}; + +/* coefficient table 4.A.87, format = Q31 + * reordered as cTab[0], cTab[64], cTab[128], ... cTab[576], cTab[1], cTab[65], cTab[129], ... cTab[639] + * keeping full table (not using symmetry) to allow sequential access in synth filter inner loop + * format = Q31 + */ +const uint32_t cTabS[640] PROGMEM = { + 0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d, 0xd1c58ace, 0x09015651, 0xfe4d1be3, 0x0055dba1, + 0xffede50e, 0x005b5371, 0x01d78bfc, 0x08d3e41b, 0x2faa221c, 0x6d41d963, 0xd3337b3d, 0x09299ead, 0xfe70b8d1, 0x0050b177, + 0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4, 0x6d32730f, 0xd49fd55f, 0x094d7ec2, 0xfe933dc0, 0x004b6c46, + 0xffefc9b9, 0x0065fde5, 0x02244a24, 0x086b1eeb, 0x328cc6f0, 0x6d18520e, 0xd60a46e5, 0x096d0e21, 0xfeb48d0d, 0x00465348, + 0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0x6cf4073e, 0xd7722f04, 0x09881dc5, 0xfed4bec3, 0x004103f4, + 0xffeff6ca, 0x0070c8a5, 0x0274ba43, 0x07ee507c, 0x3572ec70, 0x6cc59bab, 0xd8d7f21f, 0x099ec3dc, 0xfef3f6ab, 0x003c1fa4, + 0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691, 0x6c8c4c7a, 0xda3b176a, 0x09b18a1d, 0xff120d70, 0x003745f9, + 0xffeedfa4, 0x007b3875, 0x02c89901, 0x075ca90c, 0x385a49c4, 0x6c492217, 0xdb9b5b12, 0x09c018ce, 0xff2ef725, 0x00329ab6, + 0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0x6bfbdd98, 0xdcf898fb, 0x09caeb0f, 0xff4aabc8, 0x002d8e42, + 0xffed651d, 0x0085c217, 0x03201116, 0x06b559c3, 0x3b415115, 0x6ba4629f, 0xde529086, 0x09d1fa23, 0xff6542d1, 0x00293718, + 0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219, 0x6b42a864, 0xdfa93ab5, 0x09d5560b, 0xff7ee3f1, 0x0024dd50, + 0xffebe77b, 0x008f4bfc, 0x037ad438, 0x05f7fb90, 0x3e25b17e, 0x6ad73e8d, 0xe0fc421e, 0x09d52709, 0xff975c01, 0x002064f8, + 0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0x6a619c5e, 0xe24b8f66, 0x09d19ca9, 0xffaea5d6, 0x001c3549, + 0xffea9192, 0x0098b855, 0x03d8afe6, 0x05237f9d, 0x41058bc6, 0x69e29784, 0xe396a45d, 0x09cab9f2, 0xffc4e365, 0x0018703f, + 0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385, 0x6959709d, 0xe4de0cb0, 0x09c0e59f, 0xffda17f2, 0x001471f8, + 0xffe940f4, 0x00a1039c, 0x043889c6, 0x0437fb0a, 0x43de620a, 0x68c7269b, 0xe620c476, 0x09b3d77f, 0xffee183b, 0x0010bc63, + 0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0x682b39a4, 0xe75f8bb8, 0x09a3e163, 0x0000e790, 0x000d31b5, + 0xffe83a07, 0x00a8739d, 0x049aa82f, 0x03343533, 0x46aea856, 0x6785c24d, 0xe89971b7, 0x099140a7, 0x00131c75, 0x0009aa3f, + 0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848, 0x66d76725, 0xe9cea84a, 0x097c1ee8, 0x0023b989, 0x0006b1cf, + 0xffe7746e, 0x00af374c, 0x04fe20be, 0x02186a91, 0x4973fef1, 0x661fd6b8, 0xeafee7f1, 0x0963ed46, 0x0033b927, 0x00039609, + 0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0x655f63f2, 0xec2a3f5f, 0x0949eaac, 0x00426f36, 0x00007134, + 0xffe6afee, 0x00b3d15c, 0x05626209, 0x00e42fa2, 0x4c2ca3df, 0x64964063, 0xed50a31d, 0x092d7970, 0x00504f41, 0xfffdfa25, + 0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c, 0x63c45243, 0xee71b2fe, 0x090ec1fc, 0x005d36df, 0xfffb42b0, + 0xffe681c6, 0x00b74c37, 0x05c76fed, 0xff96db90, 0x4ed62be3, 0x62ea6474, 0xef8d4d7b, 0x08edfeaa, 0x006928a0, 0xfff91fca, + 0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0x6207f220, 0xf0a3959f, 0x08cb4e23, 0x007400b8, 0xfff681d6, + 0xffe66fac, 0x00b8fe0d, 0x062bf5ec, 0xfe310657, 0x516eefb9, 0x611d58a3, 0xf1b461ab, 0x08a75da4, 0x007e0393, 0xfff48700, + 0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de, 0x602b0c7f, 0xf2bf6ea4, 0x0880ffdd, 0x00872c63, 0xfff294c3, + 0xffe6fed4, 0x00b85f70, 0x068f8b44, 0xfcb1d740, 0x53f495aa, 0x5f30ff5f, 0xf3c4e887, 0x08594887, 0x008f87aa, 0xfff0e7ef, + 0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0x5e2f6367, 0xf4c473c6, 0x08303897, 0x0096dcc2, 0xffef2395, + 0xffe80414, 0x00b58c8c, 0x06f1825d, 0xfb19b7bd, 0x56654bdd, 0x5d26be9b, 0xf5be0fa9, 0x08061671, 0x009da526, 0xffedc418, + 0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5, 0x5c16d0ae, 0xf6b1f3c3, 0x07da2b7f, 0x00a3508f, 0xffec8409, + 0xffe954d0, 0x00b06b68, 0x075112a2, 0xf96916f5, 0x58befacd, 0x5b001db8, 0xf79fa13a, 0x07ad8c26, 0x00a85e94, 0xffeb3849, + 0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0x59e2f69e, 0xf887507c, 0x077fedb3, 0x00acbd2f, 0xffea353a, + 0xffeb3849, 0x00a85e94, 0x07ad8c26, 0xf79fa13a, 0x5b001db8, 0x58befacd, 0xf96916f5, 0x075112a2, 0x00b06b68, 0xffe954d0, + 0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae, 0x579505f5, 0xfa44a069, 0x0721bf22, 0x00b36acd, 0xffe85b4b, + 0xffedc418, 0x009da526, 0x08061671, 0xf5be0fa9, 0x5d26be9b, 0x56654bdd, 0xfb19b7bd, 0x06f1825d, 0x00b58c8c, 0xffe80414, + 0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0x552f8ff7, 0xfbe8f5bd, 0x06c0f0c0, 0x00b73ab0, 0xffe75361, + 0xfff0e7ef, 0x008f87aa, 0x08594887, 0xf3c4e887, 0x5f30ff5f, 0x53f495aa, 0xfcb1d740, 0x068f8b44, 0x00b85f70, 0xffe6fed4, + 0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f, 0x52b449de, 0xfd7475d8, 0x065dd56a, 0x00b8c6b0, 0xffe69423, + 0xfff48700, 0x007e0393, 0x08a75da4, 0xf1b461ab, 0x611d58a3, 0x516eefb9, 0xfe310657, 0x062bf5ec, 0x00b8fe0d, 0xffe66fac, + 0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0x5024d70e, 0xfee723c6, 0x05f9c051, 0x00b8394b, 0xffe66dd0, + 0xfff91fca, 0x006928a0, 0x08edfeaa, 0xef8d4d7b, 0x62ea6474, 0x4ed62be3, 0xff96db90, 0x05c76fed, 0x00b74c37, 0xffe681c6, + 0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243, 0x4d83976c, 0x0040c496, 0x05950122, 0x00b5c867, 0xffe65416, + 0xfffdfa25, 0x00504f41, 0x092d7970, 0xed50a31d, 0x64964063, 0x4c2ca3df, 0x00e42fa2, 0x05626209, 0x00b3d15c, 0xffe6afee, + 0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x4ad237a2, 0x01816e06, 0x05303f87, 0x00b1978d, 0xffe6d466, + 0x00039609, 0x0033b927, 0x0963ed46, 0xeafee7f1, 0x661fd6b8, 0x4973fef1, 0x02186a91, 0x04fe20be, 0x00af374c, 0xffe7746e, + 0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725, 0x4812f848, 0x02a99097, 0x04cc2fcf, 0x00abe79e, 0xffe79e16, + 0x0009aa3f, 0x00131c75, 0x099140a7, 0xe89971b7, 0x6785c24d, 0x46aea856, 0x03343533, 0x049aa82f, 0x00a8739d, 0xffe83a07, + 0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x4547daea, 0x03b8f8dc, 0x04694101, 0x00a520bb, 0xffe88ba8, + 0x0010bc63, 0xffee183b, 0x09b3d77f, 0xe620c476, 0x68c7269b, 0x43de620a, 0x0437fb0a, 0x043889c6, 0x00a1039c, 0xffe940f4, + 0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d, 0x4272a385, 0x04b0adcb, 0x04083fec, 0x009d10bf, 0xffe9ca76, + 0x0018703f, 0xffc4e365, 0x09cab9f2, 0xe396a45d, 0x69e29784, 0x41058bc6, 0x05237f9d, 0x03d8afe6, 0x0098b855, 0xffea9192, + 0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x3f962fb8, 0x0590a67d, 0x03a966bb, 0x009424c6, 0xffeb50b2, + 0x002064f8, 0xff975c01, 0x09d52709, 0xe0fc421e, 0x6ad73e8d, 0x3e25b17e, 0x05f7fb90, 0x037ad438, 0x008f4bfc, 0xffebe77b, + 0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864, 0x3cb41219, 0x06593912, 0x034d01f0, 0x008a7dd7, 0xffecc31b, + 0x00293718, 0xff6542d1, 0x09d1fa23, 0xde529086, 0x6ba4629f, 0x3b415115, 0x06b559c3, 0x03201116, 0x0085c217, 0xffed651d, + 0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x39ce0477, 0x070bbf58, 0x02f3e48d, 0x00807994, 0xffee1650, + 0x00329ab6, 0xff2ef725, 0x09c018ce, 0xdb9b5b12, 0x6c492217, 0x385a49c4, 0x075ca90c, 0x02c89901, 0x007b3875, 0xffeedfa4, + 0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a, 0x36e69691, 0x07a8127d, 0x029e35b4, 0x0075fded, 0xffef7b8b, + 0x003c1fa4, 0xfef3f6ab, 0x099ec3dc, 0xd8d7f21f, 0x6cc59bab, 0x3572ec70, 0x07ee507c, 0x0274ba43, 0x0070c8a5, 0xffeff6ca, + 0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x33ff670e, 0x082f552e, 0x024bf7a1, 0x006b47fa, 0xfff0065d, + 0x00465348, 0xfeb48d0d, 0x096d0e21, 0xd60a46e5, 0x6d18520e, 0x328cc6f0, 0x086b1eeb, 0x02244a24, 0x0065fde5, 0xffefc9b9, + 0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f, 0x311af3a4, 0x08a24899, 0x01fd3ba0, 0x006090c4, 0xffed978a, + 0x0050b177, 0xfe70b8d1, 0x09299ead, 0xd3337b3d, 0x6d41d963, 0x2faa221c, 0x08d3e41b, 0x01d78bfc, 0x005b5371, 0xffede50f, +}; + +const HuffInfo_t huffTabScaleFactInfo PROGMEM = + {19, { 1, 0, 1, 3, 2, 4, 3, 5, 4, 6, 6, 6, 5, 8, 4, 7, 3, 7, 46, 0}, 0}; + +/* note - includes offset of -60 (4.6.2.3 in spec) */ +const int16_t huffTabScaleFact[121] PROGMEM = { /* scale factor table [121] */ + 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, 6, -6, 7, -7, 8, + -8, 9, -9, 10, -10, -11, 11, 12, -12, 13, -13, 14, -14, 16, 15, 17, + 18, -15, -17, -16, 19, -18, -19, 20, -20, 21, -21, 22, -22, 23, -23, -25, + 25, -27, -24, -26, 24, -28, 27, 29, -30, -29, 26, -31, -34, -33, -32, -36, + 28, -35, -38, -37, 30, -39, -41, -57, -59, -58, -60, 38, 39, 40, 41, 42, + 57, 37, 31, 32, 33, 34, 35, 36, 44, 51, 52, 53, 54, 55, 56, 50, + 45, 46, 47, 48, 49, 58, -54, -52, -51, -50, -55, 43, 60, 59, -56, -53, + -45, -44, -42, -40, -43, -49, -48, -46, -47, +}; + +/* noise table 4.A.88, format = Q31 */ +const uint32_t noiseTab[512*2] PROGMEM = { + 0x8010fd38, 0xb3dc7948, 0x7c4e2301, 0xa9904192, 0x121622a7, 0x86489625, 0xc3d53d25, 0xd0343fa9, + 0x674d6f70, 0x25f4e9fd, 0xce1a8c8b, 0x72a726c5, 0xfea6efc6, 0xaa4adb1a, 0x8b2dd628, 0xf14029e4, + 0x46321c1a, 0x604889a0, 0x33363b63, 0x815ed069, 0x802b4315, 0x8f2bf7f3, 0x85b86073, 0x745cfb46, + 0xc57886b3, 0xb76731f0, 0xa2a66772, 0x828ca631, 0x60cc145e, 0x1ad1010f, 0x090c83d4, 0x9bd7ba87, + 0x5f5aeea2, 0x8b4dbd99, 0x848e7b1e, 0x86bb9fa2, 0x26f18ae5, 0xc0b81194, 0x553407bf, 0x52c17953, + 0x755f468d, 0x166b04f8, 0xa5687981, 0x4343248b, 0xa6558d5e, 0xc5f6fab7, 0x80a4fb8c, 0x8cb53cb7, + 0x7da68a54, 0x9cd8df8a, 0xba05376c, 0xfcb58ee2, 0xfdd657a4, 0x005e35ca, 0x91c75c55, 0x367651e6, + 0x816abf85, 0x8f831c4f, 0x423f9c9c, 0x55aa919e, 0x80779834, 0xb59f4244, 0x800a095c, 0x7de9e0cc, + 0x46bda5cb, 0x4c184464, 0x2c438f71, 0x797216b5, 0x5035cee6, 0xa0c3a26e, 0x9d3f95fa, 0xd4a100c0, + 0x8ac30dac, 0x04b87397, 0x9e5ac516, 0x8b0b442e, 0x66210ad6, 0x88ba7598, 0x45b9bd33, 0xf0be5087, + 0x9261b85e, 0x364f6a31, 0x891c4b50, 0x23ad08ce, 0xf10366a6, 0x80414276, 0x1b562e06, 0x8be21591, + 0x9e798195, 0x7fb4045c, 0x7d9506cf, 0x854e691f, 0x9207f092, 0x7a94c9d5, 0x88911536, 0x3f45cc61, + 0x27059279, 0xa5b57109, 0x6d2bb67b, 0x3bdc5379, 0x74e662d8, 0x80348f8c, 0xf875e638, 0x5a8caea1, + 0x2459ae75, 0x2c54b939, 0x79ee3203, 0xb9bc8683, 0x9b6f630c, 0x9f45b351, 0x8563b2b9, 0xe5dbba41, + 0x697c7d0d, 0x7bb7c90e, 0xac900866, 0x8e6b5177, 0x8822dd37, 0x7fd5a91e, 0x7506da05, 0x82302aca, + 0xa5e4be04, 0x4b4288eb, 0x00b8bc9f, 0x4f1033e4, 0x7200d612, 0x43900c8c, 0xa815b900, 0x676ed1d4, + 0x5c5f23b2, 0xa758ee11, 0xaf73abfa, 0x11714ec0, 0x265239e0, 0xc50de679, 0x8a84e341, 0xa1438354, + 0x7f1a341f, 0x343ec96b, 0x696e71b0, 0xa13bde39, 0x81e75094, 0x80091111, 0x853a73bf, 0x80f9c1ee, + 0xe4980086, 0x886a8e28, 0xa7e89426, 0xdd93edd7, 0x7592100d, 0x0bfa8123, 0x850a26d4, 0x2e34f395, + 0x421b6c00, 0xa4a462e4, 0x4e3f5090, 0x3c189f4c, 0x3c971a56, 0xdd0376d2, 0x747a5367, 0x7bcbc9d7, + 0x3966be6a, 0x7efda616, 0x55445e15, 0x7ba2ab3f, 0x5fe684f2, 0x8cf42af9, 0x808c61c3, 0x4390c27b, + 0x7cac62ff, 0xea6cab22, 0x5d0902ad, 0xc27b7208, 0x7a27389d, 0x5820a357, 0xa29bbe59, 0x9df0f1fd, + 0x92bd67e5, 0x7195b587, 0x97cac65b, 0x8339807e, 0x8f72d832, 0x5fad8685, 0xa462d9d3, 0x81d46214, + 0x6ae93e1d, 0x6b23a5b9, 0xc2732874, 0x81795268, 0x7c568cb6, 0x668513ea, 0x428d024e, 0x66b78b3a, + 0xfee9ef03, 0x9ddcbb82, 0xa605f07e, 0x46dc55e0, 0x85415054, 0xc89ec271, 0x7c42edfb, 0x0befe59b, + 0x89b8f607, 0x6d732a1a, 0xa7081ebd, 0x7e403258, 0x21feeb7b, 0x5dd7a1e7, 0x23e3a31a, 0x129bc896, + 0xa11a6b54, 0x7f1e031c, 0xfdc1a4d1, 0x96402e53, 0xb9700f1a, 0x8168ecd6, 0x7d63d3cc, 0x87a70d65, + 0x81075a7a, 0x55c8caa7, 0xa95d00b5, 0x102b1652, 0x0bb30215, 0xe5b63237, 0xa446ca44, 0x82d4c333, + 0x67b2e094, 0x44c3d661, 0x33fd6036, 0xde1ea2a1, 0xa95e8e47, 0x78f66eb9, 0x6f2aef1e, 0xe8887247, + 0x80a3b70e, 0xfca0d9d3, 0x6bf0fd20, 0x0d5226de, 0xf4341c87, 0x5902df05, 0x7ff1a38d, 0xf02e5a5b, + 0x99f129af, 0x8ac63d01, 0x7b53f599, 0x7bb32532, 0x99ac59b0, 0x5255a80f, 0xf1320a41, 0x2497aa5c, + 0xcce60bd8, 0x787c634b, 0x7ed58c5b, 0x8a28eb3a, 0x24a5e647, 0x8b79a2c1, 0x955f5ce5, 0xa9d12bc4, + 0x7a1e20c6, 0x3eeda7ac, 0xf7be823a, 0x042924ce, 0x808b3f03, 0x364248da, 0xac2895e5, 0x69a8b5fa, + 0x97fe8b63, 0xbdeac9aa, 0x8073e0ad, 0x6c25dba7, 0x005e51d2, 0x52e74389, 0x59d3988c, 0xe5d1f39c, + 0x7b57dc91, 0x341adbe7, 0xa7d42b8d, 0x74e9f335, 0xd35bf7d8, 0x5b7c0a4b, 0x75bc0874, 0x552129bf, + 0x8144b70d, 0x6de93bbb, 0x5825f14b, 0x473ec5ca, 0x80a8f37c, 0xe6552d69, 0x7898360b, 0x806379b0, + 0xa9b59339, 0x3f6bf60c, 0xc367d731, 0x920ade99, 0x125592f7, 0x877e5ed1, 0xda895d95, 0x075f2ece, + 0x380e5f5e, 0x9b006b62, 0xd17a6dd2, 0x530a0e13, 0xf4cc9a14, 0x7d0a0ed4, 0x847c6e3f, 0xbaee4975, + 0x47131163, 0x64fb2cac, 0x5e2100a6, 0x7b756a42, 0xd87609f4, 0x98bfe48c, 0x0493745e, 0x836c5784, + 0x7e5ccb40, 0x3df6b476, 0x97700d28, 0x8bbd93fd, 0x56de9cdb, 0x680b4e65, 0xebc3d90e, 0x6d286793, + 0x6753712e, 0xe05c98a7, 0x3d2b6b85, 0xc4b18ddb, 0x7b59b869, 0x31435688, 0x811888e9, 0xe011ee7a, + 0x6a5844f9, 0x86ae35ea, 0xb4cbc10b, 0x01a6f5d6, 0x7a49ed64, 0x927caa49, 0x847ddaed, 0xae0d9bb6, + 0x836bdb04, 0x0fd810a6, 0x74fe126b, 0x4a346b5f, 0x80184d36, 0x5afd153c, 0x90cc8102, 0xe606d0e6, + 0xde69aa58, 0xa89f1222, 0xe06df715, 0x8fd16144, 0x0317c3e8, 0x22ce92fc, 0x690c3eca, 0x93166f02, + 0x71573414, 0x8d43cffb, 0xe8bd0bb6, 0xde86770f, 0x0bf99a41, 0x4633a661, 0xba064108, 0x7adafae3, + 0x2f6cde5d, 0xb350a52c, 0xa5ebfb0b, 0x74c57b46, 0xd3b603b5, 0x80b70892, 0xa7f7fa53, 0xd94b566c, + 0xdda3fd86, 0x6a635793, 0x3ed005ca, 0xc5f087d8, 0x31e3a746, 0x7a4278f9, 0x82def1f9, 0x06caa2b2, + 0xe9d2c349, 0x8940e7f7, 0x7feef8dd, 0x4a9b01f0, 0xacde69f8, 0x57ddc280, 0xf09e4ba4, 0xb6d9f729, + 0xb48c18f2, 0xd3654aa9, 0xca7a03c8, 0x14d57545, 0x7fda87a5, 0x0e411366, 0xb77d0df0, 0x8c2aa467, + 0x787f2590, 0x2d292db1, 0x9f12682c, 0x44ac364d, 0x1a4b31a6, 0x871f7ded, 0x7ff99167, 0x6630a1d5, + 0x25385eb9, 0x2d4dd549, 0xaf8a7004, 0x319ebe0f, 0x379ab730, 0x81dc56a4, 0x822d8523, 0x1ae8554c, + 0x18fa0786, 0x875f7de4, 0x85ca350f, 0x7de818dc, 0x7786a38f, 0xa5456355, 0x92e60f88, 0xf5526122, + 0x916039bc, 0xc561e2de, 0x31c42042, 0x7c82e290, 0x75d158b2, 0xb015bda1, 0x7220c750, 0x46565441, + 0xd0da1fdd, 0x7b777481, 0x782e73c6, 0x8cd72b7b, 0x7f1006aa, 0xfb30e51e, 0x87994818, 0x34e7c7db, + 0x7faae06b, 0xea74fbc0, 0xd20c7af4, 0xc44f396b, 0x06b4234e, 0xdf2e2a93, 0x2efb07c8, 0xce861911, + 0x7550ea05, 0xd8d90bbb, 0x58522eec, 0x746b3520, 0xce844ce9, 0x7f5cacc3, 0xda8f17e0, 0x2fedf9cb, + 0xb2f77ec4, 0x6f13f4c0, 0x834de085, 0x7b7ace4b, 0x713b16ac, 0x499c5ab0, 0x06a7961d, 0x1b39a48a, + 0xbb853e6e, 0x7c781cc1, 0xc0baebf5, 0x7dace394, 0x815ceebc, 0xcc7b27d4, 0x8274b181, 0xa2be40a2, + 0xdd01d5dc, 0x7fefeb14, 0x0813ec78, 0xba3077cc, 0xe5cf1e1c, 0xedcfacae, 0x54c43a9b, 0x5cd62a42, + 0x93806b55, 0x03095c5b, 0x8e076ae3, 0x71bfcd2a, 0x7ac1989b, 0x623bc71a, 0x5e15d4d2, 0xfb341dd1, + 0xd75dfbca, 0xd0da32be, 0xd4569063, 0x337869da, 0x3d30606a, 0xcd89cca2, 0x7dd2ae36, 0x028c03cd, + 0xd85e052c, 0xe8dc9ec5, 0x7ffd9241, 0xde5bf4c6, 0x88c4b235, 0x8228be2e, 0x7fe6ec64, 0x996abe6a, + 0xdeb0666d, 0x9eb86611, 0xd249b922, 0x18b3e26b, 0x80211168, 0x5f8bb99c, 0x6ecb0dd2, 0x4728ff8d, + 0x2ac325b8, 0x6e5169d2, 0x7ebbd68d, 0x05e41d17, 0xaaa19f28, 0x8ab238a6, 0x51f105be, 0x140809cc, + 0x7f7345d9, 0x3aae5a9d, 0xaecec6e4, 0x1afb3473, 0xf6229ed1, 0x8d55f467, 0x7e32003a, 0x70f30c14, + 0x6686f33f, 0xd0d45ed8, 0x644fab57, 0x3a3fbbd3, 0x0b255fc4, 0x679a1701, 0x90e17b6e, 0x325d537b, + 0xcd7b9b87, 0xaa7be2a2, 0x7d47c966, 0xa33dbce5, 0x8659c3bb, 0x72a41367, 0x15c446e0, 0x45fe8b0a, + 0x9d8ddf26, 0x84d47643, 0x7fabe0da, 0x36a70122, 0x7a28ebfe, 0x7c29b8b8, 0x7f760406, 0xbabe4672, + 0x23ea216e, 0x92bcc50a, 0x6d20dba2, 0xad5a7c7e, 0xbf3897f5, 0xabb793e1, 0x8391fc7e, 0xe270291c, + 0x7a248d58, 0x80f8fd15, 0x83ef19f3, 0x5e6ece7d, 0x278430c1, 0x35239f4d, 0xe09c073b, 0x50e78cb5, + 0xd4b811bd, 0xce834ee0, 0xf88aaa34, 0xf71da5a9, 0xe2b0a1d5, 0x7c3aef31, 0xe84eabca, 0x3ce25964, + 0xf29336d3, 0x8fa78b2c, 0xa3fc3415, 0x63e1313d, 0x7fbc74e0, 0x7340bc93, 0x49ae583b, 0x8b79de4b, + 0x25011ce9, 0x7b462279, 0x36007db0, 0x3da1599c, 0x77780772, 0xc845c9bb, 0x83ba68be, 0x6ee507d1, + 0x2f0159b8, 0x5392c4ed, 0x98336ff6, 0x0b3c7f11, 0xde697aac, 0x893fc8d0, 0x6b83f8f3, 0x47799a0d, + 0x801d9dfc, 0x8516a83e, 0x5f8d22ec, 0x0f8ba384, 0xa049dc4b, 0xdd920b05, 0x7a99bc9f, 0x9ad19344, + 0x7a345dba, 0xf501a13f, 0x3e58bf19, 0x7fffaf9a, 0x3b4e1511, 0x0e08b991, 0x9e157620, 0x7230a326, + 0x4977f9ff, 0x2d2bbae1, 0x607aa7fc, 0x7bc85d5f, 0xb441bbbe, 0x8d8fa5f2, 0x601cce26, 0xda1884f2, + 0x81c82d64, 0x200b709c, 0xcbd36abe, 0x8cbdddd3, 0x55ab61d3, 0x7e3ee993, 0x833f18aa, 0xffc1aaea, + 0x7362e16a, 0x7fb85db2, 0x904ee04c, 0x7f04dca6, 0x8ad7a046, 0xebe7d8f7, 0xfbc4c687, 0xd0609458, + 0x093ed977, 0x8e546085, 0x7f5b8236, 0x7c47e118, 0xa01f2641, 0x7ffb3e48, 0x05de7cda, 0x7fc281b9, + 0x8e0278fc, 0xd74e6d07, 0x94c24450, 0x7cf9e641, 0x2ad27871, 0x919fa815, 0x805fd205, 0x7758397f, + 0xe2c7e02c, 0x1828e194, 0x5613d6fe, 0xfb55359f, 0xf9699516, 0x8978ee26, 0x7feebad9, 0x77d71d82, + 0x55b28b60, 0x7e997600, 0x80821a6b, 0xc6d78af1, 0x691822ab, 0x7f6982a0, 0x7ef56f99, 0x5c307f40, + 0xac6f8b76, 0x42cc8ba4, 0x782c61d9, 0xa0224dd0, 0x7bd234d1, 0x74576e3b, 0xe38cfe9a, 0x491e66ef, + 0xc78291c5, 0x895bb87f, 0x924f7889, 0x71b89394, 0x757b779d, 0xc4a9c604, 0x5cdf7829, 0x8020e9df, + 0x805e8245, 0x4a82c398, 0x6360bd62, 0x78bb60fc, 0x09e0d014, 0x4b0ea180, 0xb841978b, 0x69a0e864, + 0x7df35977, 0x3284b0dd, 0x3cdc2efd, 0x57d31f5e, 0x541069cc, 0x1776e92e, 0x04309ea3, 0xa015eb2d, + 0xce7bfabc, 0x41b638f8, 0x8365932e, 0x846ab44c, 0xbbcc80cb, 0x8afa6cac, 0x7fc422ea, 0x4e403fc0, + 0xbfac9aee, 0x8e4c6709, 0x028e01fb, 0x6d160a9b, 0x7fe93004, 0x790f9cdc, 0x6a1f37a0, 0xf7e7ef30, + 0xb4ea0f04, 0x7bf4c8e6, 0xe981701f, 0xc258a9d3, 0x6acbbfba, 0xef5479c7, 0x079c8bd8, 0x1a410f56, + 0x6853b799, 0x86cd4f01, 0xc66e23b6, 0x34585565, 0x8d1fe00d, 0x7fcdba1a, 0x32c9717b, 0xa02f9f48, + 0xf64940db, 0x5ed7d8f1, 0x61b823b2, 0x356f8918, 0xa0a7151e, 0x793fc969, 0x530beaeb, 0x34e93270, + 0x4fc4ddb5, 0x88d58b6c, 0x36094774, 0xf620ac80, 0x03763a72, 0xf910c9a6, 0x6666fb2d, 0x752c8be8, + 0x9a6dfdd8, 0xd1a7117d, 0x51c1b1d4, 0x0a67773d, 0x43b32a79, 0x4cdcd085, 0x5f067d30, 0x05bfe92a, + 0x7ed7d203, 0xe71a3c85, 0x99127ce2, 0x8eb3cac4, 0xad4bbcea, 0x5c6a0fd0, 0x0eec04af, 0x94e95cd4, + 0x8654f921, 0x83eabb5d, 0xb058d7ca, 0x69f12d3c, 0x03d881b2, 0x80558ef7, 0x82938cb3, 0x2ec0e1d6, + 0x80044422, 0xd1e47051, 0x720fc6ff, 0x82b20316, 0x0d527b02, 0x63049a15, 0x7ad5b9ad, 0xd2a4641d, + 0x41144f86, 0x7b04917a, 0x15c4a2c0, 0x9da07916, 0x211df54a, 0x7fdd09af, 0xfe924f3f, 0x7e132cfe, + 0x9a1d18d6, 0x7c56508b, 0x80f0f0af, 0x8095ced6, 0x8037d0d7, 0x026719d1, 0xa55fec43, 0x2b1c7cb7, + 0xa5cd5ac1, 0x77639fad, 0x7fcd8b62, 0x81a18c27, 0xaee4912e, 0xeae9eebe, 0xeb3081de, 0x8532aada, + 0xc822362e, 0x86a649a9, 0x8031a71d, 0x7b319dc6, 0xea8022e6, 0x814bc5a9, 0x8f62f7a1, 0xa430ea17, + 0x388deafb, 0x883b5185, 0x776fe13c, 0x801c683f, 0x87c11b98, 0xb7cbc644, 0x8e9ad3e8, 0x3cf5a10c, + 0x7ff6a634, 0x949ef096, 0x9f84aa7c, 0x010af13f, 0x782d1de8, 0xf18e492a, 0x6cf63b01, 0x4301cd81, + 0x32d15c9e, 0x68ad8cef, 0xd09bd2d6, 0x908c5c15, 0xd1e36260, 0x2c5bfdd0, 0x88765a99, 0x93deba1e, + 0xac6ae342, 0xe865b84c, 0x0f4f2847, 0x7fdf0499, 0x78b1c9b3, 0x6a73261e, 0x601a96f6, 0xd2847933, + 0x489aa888, 0xe12e8093, 0x3bfa5a5f, 0xd96ba5f7, 0x7c8f4c8d, 0x80940c6f, 0xcef9dd1a, 0x7e1a055f, + 0x3483558b, 0x02b59cc4, 0x0c56333e, 0x05a5b813, 0x92d66287, 0x7516b679, 0x71bfe03f, 0x8056bf68, + 0xc24d0724, 0x8416bcf3, 0x234afbdb, 0x4b0d6f9c, 0xaba97333, 0x4b4f42b6, 0x7e8343ab, 0x7ffe2603, + 0xe590f73c, 0x45e10c76, 0xb07a6a78, 0xb35609d3, 0x1a027dfd, 0x90cb6e20, 0x82d3fe38, 0x7b409257, + 0x0e395afa, 0x1b802093, 0xcb0c6c59, 0x241e17e7, 0x1ee3ea0a, 0x41a82302, 0xab04350a, 0xf570beb7, + 0xbb444b9b, 0x83021459, 0x838d65dc, 0x1c439c84, 0x6fdcc454, 0xef9ef325, 0x18626c1c, 0x020d251f, + 0xc4aae786, 0x8614cb48, 0xf6f53ca6, 0x8710dbab, 0x89abec0d, 0xf29d41c1, 0x94b50336, 0xfdd49178, + 0x604658d1, 0x800e85be, 0xca1bb079, 0x7fa48eeb, 0xa3b7fafe, 0xd330436b, 0x64eb604c, 0x43a658ae, + 0x7caa1337, 0xddd445e6, 0x7efbf955, 0xb706ec71, 0x624a6b53, 0x9e0e231f, 0x97097248, 0xa1e1a17a, + 0x68dd2e44, 0x7f9d2e14, 0xddcc7074, 0x58324197, 0xc88fc426, 0x6d3640ae, 0x7ef83600, 0x759a0270, + 0x98b6d854, 0xd63c9b84, 0x372474a2, 0xe3f18cfd, 0x56ab0bdb, 0x85c9be7e, 0x47dfcfeb, 0xa5830d41, + 0x0ddd6283, 0xf4f480ad, 0x74c60e38, 0xab8943c3, 0xc1508fe7, 0x480cdc39, 0x8e097362, 0xa44793be, + 0x538b7e18, 0x545f5b41, 0x56529175, 0x9771a97e, 0xc2da7421, 0xea8265f2, 0x805d1163, 0x883c5d28, + 0x8ba94c48, 0x4f676e65, 0xf78735b3, 0xe1853671, 0x7f454f53, 0x18147f85, 0x7d09e15d, 0xdb4f3494, + 0x795c8973, 0x83310632, 0x85d8061c, 0x9a1a0ebf, 0xc125583c, 0x2a1b1a95, 0x7fd9103f, 0x71e98c72, + 0x40932ed7, 0x91ed227a, 0x3c5e560e, 0xe816dee9, 0xb0891b80, 0x600038ba, 0xc7d9a80d, 0x7fff5e09, + 0x7e3f4351, 0xbb6b4424, 0xb14448d4, 0x8d6bb7e1, 0xfb153626, 0xa68ad537, 0xd9782006, 0xf62f6991, + 0x359ba8c1, 0x02ccff0b, 0x91bf2256, 0x7ea71c4d, 0x560ce5df, 0xeeba289b, 0xa574c4e7, 0x9e04f6ee, + 0x7860a5ec, 0x0b8db4a2, 0x968ba3d7, 0x0b6c77df, 0xd6f3157d, 0x402eff1a, 0x49b820b3, 0x8152aebb, + 0xd180b0b6, 0x098604d4, 0x7ff92224, 0xede9c996, 0x89c58061, 0x829624c4, 0xc6e71ea7, 0xba94d915, + 0x389c3cf6, 0x5b4c5a06, 0x04b335e6, 0x516a8aab, 0x42c8d7d9, 0x92b12af6, 0x86c8549f, 0xfda98acf, + 0x819673b6, 0x69545dac, 0x6feaa230, 0x726e6d3f, 0x886ebdfe, 0x34f5730a, 0x7af63ba2, 0x77307bbf, + 0x7cd80630, 0x6e45efe0, 0x7f8ad7eb, 0x59d7df99, 0x86c70946, 0xda233629, 0x753f6cbf, 0x825eeb40, +}; + +/* sample rates (table 4.5.1) */ +const int32_t sampRateTab[12] PROGMEM = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000 +}; + +/* max scalefactor band for prediction (main profile only) */ +const uint8_t predSFBMax[12] PROGMEM = { + 33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34 +}; + +/* channel mapping (table 1.6.3.4) (-1 = unknown, so need to determine mapping based on rules in 8.5.1) */ +const int8_t channelMapTab[8] PROGMEM = { + -1, 1, 2, 3, 4, 5, 6, 8 +}; + +/* number of channels in each element (SCE, CPE, etc.) + * see AACElementID in aaccommon.h + */ +const uint8_t elementNumChans[8] PROGMEM = { + 1, 2, 0, 1, 0, 0, 0, 0 +}; + +/* total number of scale factor bands in one window */ +const uint8_t /*char*/ sfBandTotalShort[12] PROGMEM = { + 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15 +}; + +const uint8_t /*char*/ sfBandTotalLong[12] PROGMEM = { + 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40 +}; + +/* scale factor band tables */ +const uint8_t sfBandTabShortOffset[12] PROGMEM = {0, 0, 0, 13, 13, 13, 28, 28, 44, 44, 44, 60}; + +const uint16_t sfBandTabShort[76] PROGMEM = { + /* short block 64, 88, 96 kHz [13] (tables 4.5.24, 4.5.26) */ + 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128, + + /* short block 32, 44, 48 kHz [15] (table 4.5.15) */ + 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 128, + + /* short block 22, 24 kHz [16] (table 4.5.22) */ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 128, + + /* short block 11, 12, 16 kHz [16] (table 4.5.20) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 128, + + /* short block 8 kHz [16] (table 4.5.18) */ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 128 +}; + +const uint16_t sfBandTabLongOffset[12] PROGMEM = {0, 0, 42, 90, 90, 140, 192, 192, 240, 240, 240, 284}; + +const uint16_t sfBandTabLong[325] PROGMEM = { + /* long block 88, 96 kHz [42] (table 4.5.25) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, + 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 156, 172, 188, 212, + 240, 276, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, + + /* long block 64 kHz [48] (table 4.5.13) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, + 72, 80, 88, 100, 112, 124, 140, 156, 172, 192, 216, 240, 268, 304, 344, 384, + 424, 464, 504, 544, 584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024, + + /* long block 44, 48 kHz [50] (table 4.5.14) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, + 96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, + 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 1024, + + /* long block 32 kHz [52] (table 4.5.16) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96, + 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, + 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 960, 992, 1024, + + /* long block 22, 24 kHz [48] (table 4.5.21) */ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 76, + 84, 92, 100, 108, 116, 124, 136, 148, 160, 172, 188, 204, 220, 240, 260, 284, + 308, 336, 364, 396, 432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024, + + /* long block 11, 12, 16 kHz [44] (table 4.5.19) */ + 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 100, 112, 124, + 136, 148, 160, 172, 184, 196, 212, 228, 244, 260, 280, 300, 320, 344, 368, + 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, 832, 896, 960, 1024, + + /* long block 8 kHz [41] (table 4.5.17) */ + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, + 172, 188, 204, 220, 236, 252, 268, 288, 308, 328, 348, 372, 396, 420, + 448, 476, 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, 1024 +}; + +/* TNS max bands (table 4.139) and max order (table 4.138) */ +const uint8_t tnsMaxBandsShortOffset[3] PROGMEM = {0, 0, 12}; + +const uint16_t tnsMaxBandsShort[2*12] PROGMEM = { + 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, /* short block, Main/LC */ + 7, 7, 7, 6, 6, 6, 7, 7, 8, 8, 8, 7 /* short block, SSR */ +}; + +const uint8_t tnsMaxOrderShort[3] PROGMEM = {7, 7, 7}; + +const uint8_t tnsMaxBandsLongOffset[3] PROGMEM = {0, 0, 12}; + +const uint16_t tnsMaxBandsLong[2*12] PROGMEM = { + 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39, /* long block, Main/LC */ + 28, 28, 27, 26, 26, 26, 29, 29, 23, 23, 23, 19, /* long block, SSR */ +}; + +const uint8_t tnsMaxOrderLong[3] PROGMEM = {20, 12, 12}; + + +/* k0Tab[sampRateIdx][k] = k0 = startMin + offset(bs_start_freq) for given sample rate (4.6.18.3.2.1) + * downsampled (single-rate) SBR not currently supported + */ +const uint8_t k0Tab[NUM_SAMPLE_RATES_SBR][16] = { + { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 96 kHz */ + { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 88 kHz */ + { 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 23, 26, 30 }, /* 64 kHz */ + { 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31 }, /* 48 kHz */ + { 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32 }, /* 44 kHz */ + { 10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 32 kHz */ + { 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 24 kHz */ + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30 }, /* 22 kHz */ + { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }, /* 16 kHz */ +}; + + +/* k2Tab[sampRateIdx][k] = stopVector(bs_stop_freq) for given sample rate, bs_stop_freq = [0, 13] (4.6.18.3.2.1) + * generated with Matlab script calc_stopvec.m + * downsampled (single-rate) SBR not currently supported + */ +const uint8_t k2Tab[NUM_SAMPLE_RATES_SBR][14] = { + { 13, 15, 17, 19, 21, 24, 27, 31, 35, 39, 44, 50, 57, 64 }, /* 96 kHz */ + { 15, 17, 19, 21, 23, 26, 29, 33, 37, 41, 46, 51, 57, 64 }, /* 88 kHz */ + { 20, 22, 24, 26, 28, 31, 34, 37, 41, 45, 49, 54, 59, 64 }, /* 64 kHz */ + { 21, 23, 25, 27, 29, 32, 35, 38, 41, 45, 49, 54, 59, 64 }, /* 48 kHz */ + { 23, 25, 27, 29, 31, 34, 37, 40, 43, 47, 51, 55, 59, 64 }, /* 44 kHz */ + { 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 32 kHz */ + { 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 24 kHz */ + { 35, 36, 38, 40, 42, 44, 46, 48, 50, 52, 55, 58, 61, 64 }, /* 22 kHz */ + { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 62, 64 }, /* 16 kHz */ +}; + +const HuffInfo_t huffTabSBRInfo[10] PROGMEM = { + {19, { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 7, 4, 8, 72, 0}, 0}, + {20, { 0, 2, 2, 2, 2, 2, 1, 3, 3, 2, 4, 4, 4, 3, 2, 5, 6, 13, 15, 46}, 121}, + {17, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 1, 25, 10, 0, 0, 0}, 242}, + {19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 0, 1, 1, 2, 1, 29, 2, 0}, 291}, + {19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, 2, 5, 1, 4, 2, 3, 34, 0}, 340}, + {20, { 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 4, 7, 10, 16}, 403}, + {14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 13, 2, 0, 0, 0, 0, 0, 0}, 466}, + {14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 8, 0, 0, 0, 0, 0, 0}, 491}, + {14, { 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0, 51, 2, 0, 0, 0, 0, 0, 0}, 516}, + { 8, { 1, 1, 1, 0, 1, 1, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 579}, +}; + +/* Huffman tables from appendix 4.A.6.1, includes offset of -LAV[i] for table i */ +const int16_t huffTabSBR[604] PROGMEM = { + /* SBR table sbr_tenv15 [121] (signed) */ + 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, + -9, 8, -10, 9, -11, 10, -12, -13, 11, -14, 12, -15, -16, 13, -19, -18, + -17, 14, -24, -20, 16, -26, -21, 15, -23, -25, -22, -60, -59, -58, -57, -56, + -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, + -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* SBR table sbr_fenv15 [121] (signed) */ + 0, -1, 1, -2, -3, 2, -4, 3, -5, 4, -6, 5, -7, 6, -8, 7, + -9, 8, -10, 9, -11, 10, 11, -12, 12, -13, 13, 14, -14, -15, 15, 16, + 17, -16, -17, -18, -19, 18, 19, -20, -21, 20, 21, -24, -23, -22, -26, -28, + 22, 23, 25, -41, -25, 26, 27, -30, -27, 24, 28, 44, -51, -46, -44, -43, + -37, -33, -31, -29, 30, 37, 42, 47, 48, -60, -59, -58, -57, -56, -55, -54, + -53, -52, -50, -49, -48, -47, -45, -42, -40, -39, -38, -36, -35, -34, -32, 29, + 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 43, 45, 46, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, + /* SBR table sbr_tenv15b [49] (signed) */ + 0, 1, -1, 2, -2, 3, -3, 4, -4, -5, 5, -6, 6, 7, -7, 8, + -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, + -8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, + /* SBR table sbr_fenv15b [49] (signed) */ + 0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, -6, 6, -7, 7, 8, + -9, -8, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, + -10, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, + /* SBR table sbr_tenv30 [63] (signed) */ + 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, -7, 6, -8, 7, + -9, -10, 8, 9, 10, -13, -11, -12, -14, 11, 12, -31, -30, -29, -28, -27, + -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + /* SBR table sbr_fenv30 [63] (signed) */ + 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, + 8, 9, -9, -10, 10, 11, -11, -12, 12, 13, -13, -15, 14, 15, -14, 18, + -18, -24, -19, 16, 17, -22, -21, -16, 20, 21, 22, 25, -23, -20, 24, -31, + -30, -29, -28, -27, -26, -25, -17, 19, 23, 26, 27, 28, 29, 30, 31, + /* SBR table sbr_tenv30b [25] (signed) */ + 0, 1, -1, -2, 2, 3, -3, -4, 4, -5, -12, -11, -10, -9, -8, -7, + -6, 5, 6, 7, 8, 9, 10, 11, 12, + /* SBR table sbr_fenv30b [25] (signed) */ + 0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, 6, -12, -11, -10, -9, + -8, -7, -6, 7, 8, 9, 10, 11, 12, + /* SBR table sbr_tnoise30 [63] (signed) */ + 0, 1, -1, -2, 2, -3, 3, -4, 4, -5, 5, 11, -31, -30, -29, -28, + -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, + -11, -10, -9, -8, -7, -6, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + /* SBR table sbr_tnoise30b [25] (signed) */ + 0, -1, 1, -2, 2, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, +}; + +/* newBWTab[prev invfMode][curr invfMode], format = Q31 (table 4.158) + * sample file which uses all of these: al_sbr_sr_64_2_fsaac32.aac + */ +static const int32_t newBWTab[4][4] PROGMEM = { + {0x00000000, 0x4ccccccd, 0x73333333, 0x7d70a3d7}, + {0x4ccccccd, 0x60000000, 0x73333333, 0x7d70a3d7}, + {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7}, + {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7}, +}; + +/* NINT(2.048E6 / Fs) (figure 4.47) + * downsampled (single-rate) SBR not currently supported + */ +const uint8_t goalSBTab[NUM_SAMPLE_RATES_SBR] = { + 21, 23, 32, 43, 46, 64, 85, 93, 128 +}; + +/* twiddle table for radix 4 pass, format = Q31 */ +static const uint32_t twidTabOdd32[8*6] = { + 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x539eba45, 0xe7821d59, + 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, + 0x539eba45, 0xc4df2862, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, + 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x22a2f4f8, 0xc4df2862, + 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, + 0xac6145bb, 0x187de2a7, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, +}; + +/* PostMultiply64() table + * format = Q30 + * reordered for sequential access + * + * for (i = 0; i <= (32/2); i++) { + * angle = i * M_PI / 64; + * x = (cos(angle) + sin(angle)); + * x = sin(angle); + * } + */ +static const int32_t cos1sin1tab64[34] PROGMEM = { + 0x40000000, 0x00000000, 0x43103085, 0x0323ecbe, 0x45f704f7, 0x0645e9af, 0x48b2b335, 0x09640837, + 0x4b418bbe, 0x0c7c5c1e, 0x4da1fab5, 0x0f8cfcbe, 0x4fd288dc, 0x1294062f, 0x51d1dc80, 0x158f9a76, + 0x539eba45, 0x187de2a7, 0x553805f2, 0x1b5d100a, 0x569cc31b, 0x1e2b5d38, 0x57cc15bc, 0x20e70f32, + 0x58c542c5, 0x238e7673, 0x5987b08a, 0x261feffa, 0x5a12e720, 0x2899e64a, 0x5a6690ae, 0x2afad269, + 0x5a82799a, 0x2d413ccd, +}; + +/* coefficient table 4.A.87, format = Q31 + * reordered as: + * cTab[0], cTab[64], cTab[128], cTab[192], cTab[256], + * cTab[2], cTab[66], cTab[130], cTab[194], cTab[258], + * ... + * cTab[64], cTab[128], cTab[192], cTab[256], cTab[320] + * + * NOTE: cTab[1, 2, ... , 318, 319] = cTab[639, 638, ... 322, 321] + * except cTab[384] = -cTab[256], cTab[512] = -cTab[128] + */ +const uint32_t cTabA[165] PROGMEM = { + 0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4, + 0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691, + 0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219, + 0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385, + 0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848, + 0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c, + 0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de, + 0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5, + 0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae, + 0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f, + 0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243, + 0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725, + 0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d, + 0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864, + 0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a, + 0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f, + 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d, +}; + +/* PreMultiply64() table + * format = Q30 + * reordered for sequential access + * + * for (i = 0; i < 64/4; i++) { + * angle = (i + 0.25) * M_PI / nmdct; + * x = (cos(angle) + sin(angle)); + * x = sin(angle); + * + * angle = (nmdct/2 - 1 - i + 0.25) * M_PI / nmdct; + * x = (cos(angle) + sin(angle)); + * x = sin(angle); + * } + */ +static const int32_t cos4sin4tab64[64] PROGMEM = { + 0x40c7d2bd, 0x00c90e90, 0x424ff28f, 0x3ff4e5e0, 0x43cdd89a, 0x03ecadcf, 0x454149fc, 0x3fc395f9, + 0x46aa0d6d, 0x070de172, 0x4807eb4b, 0x3f6af2e3, 0x495aada2, 0x0a2abb59, 0x4aa22036, 0x3eeb3347, + 0x4bde1089, 0x0d415013, 0x4d0e4de2, 0x3e44a5ef, 0x4e32a956, 0x104fb80e, 0x4f4af5d1, 0x3d77b192, + 0x50570819, 0x135410c3, 0x5156b6d9, 0x3c84d496, 0x5249daa2, 0x164c7ddd, 0x53304df6, 0x3b6ca4c4, + 0x5409ed4b, 0x19372a64, 0x54d69714, 0x3a2fcee8, 0x55962bc0, 0x1c1249d8, 0x56488dc5, 0x38cf1669, + 0x56eda1a0, 0x1edc1953, 0x57854ddd, 0x374b54ce, 0x580f7b19, 0x2192e09b, 0x588c1404, 0x35a5793c, + 0x58fb0568, 0x2434f332, 0x595c3e2a, 0x33de87de, 0x59afaf4c, 0x26c0b162, 0x59f54bee, 0x31f79948, + 0x5a2d0957, 0x29348937, 0x5a56deec, 0x2ff1d9c7, 0x5a72c63b, 0x2b8ef77d, 0x5a80baf6, 0x2dce88aa, +}; + +/* invBandTab[i] = 1.0 / (i + 1), Q31 */ +static const int32_t invBandTab[64] PROGMEM = { + 0x7fffffff, 0x40000000, 0x2aaaaaab, 0x20000000, 0x1999999a, 0x15555555, 0x12492492, 0x10000000, + 0x0e38e38e, 0x0ccccccd, 0x0ba2e8ba, 0x0aaaaaab, 0x09d89d8a, 0x09249249, 0x08888889, 0x08000000, + 0x07878788, 0x071c71c7, 0x06bca1af, 0x06666666, 0x06186186, 0x05d1745d, 0x0590b216, 0x05555555, + 0x051eb852, 0x04ec4ec5, 0x04bda12f, 0x04924925, 0x0469ee58, 0x04444444, 0x04210842, 0x04000000, + 0x03e0f83e, 0x03c3c3c4, 0x03a83a84, 0x038e38e4, 0x03759f23, 0x035e50d8, 0x03483483, 0x03333333, + 0x031f3832, 0x030c30c3, 0x02fa0be8, 0x02e8ba2f, 0x02d82d83, 0x02c8590b, 0x02b93105, 0x02aaaaab, + 0x029cbc15, 0x028f5c29, 0x02828283, 0x02762762, 0x026a439f, 0x025ed098, 0x0253c825, 0x02492492, + 0x023ee090, 0x0234f72c, 0x022b63cc, 0x02222222, 0x02192e2a, 0x02108421, 0x02082082, 0x02000000, +}; + +static const uint32_t poly43lo[5] PROGMEM = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 }; +static const uint32_t poly43hi[5] PROGMEM = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 }; + +/* pow2exp[i] = pow(2, i*4/3) exponent */ +static const uint16_t pow2exp[8] PROGMEM = { 14, 13, 11, 10, 9, 7, 6, 5 }; + +/* pow2exp[i] = pow(2, i*4/3) fraction */ +static const int32_t pow2frac[8] PROGMEM = { + 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, + 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6 +}; + +/* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */ +static const int32_t pow14[4] PROGMEM = { + 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 +}; + +/* pow(2, i/4.0) * pow(j, 4.0/3.0) for i = [0,1,2,3], j = [0,1,2,...,15] + * format = Q28 for j = [0-3], Q25 for j = [4-15] + */ +static const uint32_t pow43_14[4][16] PROGMEM = { + { + 0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, /* Q28 */ + 0x0cb2ff53, 0x111989d6, 0x15ce31c8, 0x1ac7f203, /* Q25 */ + 0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, /* Q25 */ + 0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c, /* Q25 */ + }, + { + 0x00000000, 0x1306fe0a, 0x2ff221af, 0x52538f52, + 0x0f1a1bf4, 0x1455ccc2, 0x19ee62a8, 0x1fd92396, + 0x260dfc14, 0x2c8694d8, 0x333dcb29, 0x3a2f5c7a, + 0x4157aed5, 0x48b3aaa3, 0x50409f76, 0x57fc3010, + }, + { + 0x00000000, 0x16a09e66, 0x39047c0f, 0x61e734aa, + 0x11f59ac4, 0x182ec633, 0x1ed66a45, 0x25dfc55a, + 0x2d413ccd, 0x34f3462d, 0x3cefc603, 0x4531ab69, + 0x4db4adf8, 0x56752054, 0x5f6fcfcd, 0x68a1eca1, + }, + { + 0x00000000, 0x1ae89f99, 0x43ce3e4b, 0x746d57b2, + 0x155b8109, 0x1cc21cdc, 0x24ac1839, 0x2d0a479e, + 0x35d13f33, 0x3ef80748, 0x48775c93, 0x524938cd, + 0x5c68841d, 0x66d0df0a, 0x717e7bfe, 0x7c6e0305, + }, +}; + +/* pow(j, 4.0 / 3.0) for j = [16,17,18,...,63], format = Q23 */ +static const int32_t pow43[48] PROGMEM = { + 0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85, + 0x1b24e8bb, 0x1cf7fcfa, 0x1ed28af2, 0x20b4582a, + 0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000, + 0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99, + 0x32cbfd4a, 0x34eca001, 0x3712ca62, 0x393e6088, + 0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72, + 0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3, + 0x4daaebfd, 0x5007b497, 0x5268fc62, 0x54ceb29c, + 0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129, + 0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b, + 0x6b1fc80c, 0x6daeaa0d, 0x70416360, 0x72d7e8b0, + 0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09, +}; + +/* invTab[x] = 1/(x+1), format = Q30 */ +static const int32_t invTab[5] PROGMEM = {0x40000000, 0x20000000, 0x15555555, 0x10000000, 0x0ccccccd}; + +/* inverse quantization tables for TNS filter coefficients, format = Q31 + * see bottom of file for table generation + * negative (vs. spec) since we use MADD for filter kernel + */ +static const uint32_t invQuant3[16] PROGMEM = { + 0x00000000, 0xc8767f65, 0x9becf22c, 0x83358feb, 0x83358feb, 0x9becf22c, 0xc8767f65, 0x00000000, + 0x2bc750e9, 0x5246dd49, 0x6ed9eba1, 0x7e0e2e32, 0x7e0e2e32, 0x6ed9eba1, 0x5246dd49, 0x2bc750e9, +}; + +static const uint32_t invQuant4[16] PROGMEM = { + 0x00000000, 0xe5632654, 0xcbf00dbe, 0xb4c373ee, 0xa0e0a15f, 0x9126145f, 0x8643c7b3, 0x80b381ac, + 0x7f7437ad, 0x7b1d1a49, 0x7294b5f2, 0x66256db2, 0x563ba8aa, 0x4362210e, 0x2e3d2abb, 0x17851aad, +}; + +static const int8_t sgnMask[3] = {0x02, 0x04, 0x08}; +static const int8_t negMask[3] = {~0x03, ~0x07, ~0x0f}; + +/*********************************************************************************************************************** + * Function: AACDecoder_AllocateBuffers + * + * Description: allocate all the memory needed for the AAC decoder + * try heap first, because it's faster + * + * Inputs: none + * + * Outputs: none + * + * Return: false if not enough memory, otherwise true + * + **********************************************************************************************************************/ + +#ifdef CONFIG_IDF_TARGET_ESP32S3 + // ESP32-S3: If there is PSRAM, prefer it + #define __malloc_heap_psram(size) \ + heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) +#else + // ESP32, PSRAM is too slow, prefer SRAM + #define __malloc_heap_psram(size) \ + heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM) +#endif + +bool AACDecoder_AllocateBuffers(void){ + + /* here, sizes are: AACDecInfo_t:96 PSInfoBase_t:27364 ProgConfigElement_t*16:1312 PSInfoSBR_t:50788 */ +#ifdef AAC_ENABLE_SBR + if(!m_PSInfoSBR) {m_PSInfoSBR = (PSInfoSBR_t*)__malloc_heap_psram(sizeof(PSInfoSBR_t));} + + if(!m_PSInfoSBR) { + log_e("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR_t)); + return false; // ERR_AAC_SBR_INIT; + } + else { + log_d("AAC Spectral Band Replication enabled, %d additional bytes allocated", sizeof(PSInfoSBR_t)); + } +#endif + + /* these could fall back to PSRAM if not enough heap available */ + if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) __malloc_heap_psram(sizeof(AACDecInfo_t));} + if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) __malloc_heap_psram(sizeof(PSInfoBase_t));} + if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) __malloc_heap_psram(sizeof(ProgConfigElement_t)*16);} + + if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) { + log_e("not enough memory to allocate aacdecoder buffers"); + AACDecoder_FreeBuffers(); + return false; + } + + // Clear Buffer + memset( m_AACDecInfo, 0, sizeof(AACDecInfo_t)); //Clear AACDecInfo + memset( m_PSInfoBase, 0, sizeof(PSInfoBase_t)); //Clear PSInfoBase + memset(&m_AACFrameInfo, 0, sizeof(AACFrameInfo_t)); //Clear AACFrameInfo + memset(&m_fhADTS, 0, sizeof(ADTSHeader_t)); //Clear fhADTS + memset(&m_fhADIF, 0, sizeof(ADIFHeader_t)); //Clear fhADIS + memset( m_pce[0], 0, sizeof(ProgConfigElement_t) * 16); //Clear ProgConfigElement + memset(&m_pulseInfo[0], 0, sizeof(PulseInfo_t) *2); //Clear PulseInfo + memset(&m_aac_BitStreamInfo, 0, sizeof(aac_BitStreamInfo_t)); //Clear aac_BitStreamInfo +#ifdef AAC_ENABLE_SBR + memset( m_PSInfoSBR, 0, sizeof(PSInfoSBR_t)); //Clear PSInfoSBR + InitSBRState(); +#endif + + m_AACDecInfo->prevBlockID = AAC_ID_INVALID; + m_AACDecInfo->currBlockID = AAC_ID_INVALID; + m_AACDecInfo->currInstTag = -1; + for(int32_t ch = 0; ch < MAX_NCHANS_ELEM; ch++) + m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; + m_AACDecInfo->adtsBlocksLeft = 0; + m_AACDecInfo->tnsUsed = 0; + m_AACDecInfo->pnsUsed = 0; + + return true; +} + +/************************************************************************************** + * Function: AACFlushCodec + * + * Description: flush internal codec state (after seeking, for example) + * + * Inputs: valid AAC decoder instance pointer (HAACDecoder) + * + * Outputs: updated state variables in aacDecInfo + * + * Return: 0 if successful, error code (< 0) if error + **************************************************************************************/ +int32_t AACFlushCodec() +{ + int32_t ch; + + if (!m_AACDecInfo) + return ERR_AAC_NULL_POINTER; + + /* reset common state variables which change per-frame + * don't touch state variables which are (usually) constant for entire clip + * (nChans, sampRate, profile, format, sbrEnabled) + */ + m_AACDecInfo->prevBlockID = AAC_ID_INVALID; + m_AACDecInfo->currBlockID = AAC_ID_INVALID; + m_AACDecInfo->currInstTag = -1; + for (ch = 0; ch < MAX_NCHANS_ELEM; ch++) + m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; + m_AACDecInfo->adtsBlocksLeft = 0; + m_AACDecInfo->tnsUsed = 0; + m_AACDecInfo->pnsUsed = 0; + + /* reset internal codec state (flush overlap buffers, etc.) */ + memset(m_PSInfoBase->overlap, 0, AAC_MAX_NCHANS * AAC_MAX_NSAMPS * sizeof(int32_t)); + memset(m_PSInfoBase->prevWinShape, 0, AAC_MAX_NCHANS * sizeof(int32_t)); + + return ERR_AAC_NONE; +} +/*********************************************************************************************************************** + * Function: AACDecoder_FreeBuffers + * + * Description: allocate all the memory needed for the AAC decoder + * + * Inputs: none + * + * Outputs: none + * + * Return: none + + **********************************************************************************************************************/ +void AACDecoder_FreeBuffers(void) { + +// uint32_t i = ESP.getFreeHeap(); + + if(m_AACDecInfo) {free(m_AACDecInfo); m_AACDecInfo=NULL;} + if(m_PSInfoBase) {free(m_PSInfoBase); m_PSInfoBase=NULL;} + if(m_pce[0]) {free(m_pce[0]); m_pce[0]=NULL;} + +#ifdef AAC_ENABLE_SBR + if(m_PSInfoSBR) {free(m_PSInfoSBR); m_PSInfoSBR=NULL;} //Clear AACDecInfo +#endif + +// log_i("AACDecoder: %lu bytes memory was freed", ESP.getFreeHeap() - i); +} + +/*********************************************************************************************************************** + * Function: AACDecoder_IsInit + * + * Description: returns AAC decoder initialization status + * + * Inputs: none + * + * Outputs: none + * + * Return: true if buffers allocated, otherwise false + + **********************************************************************************************************************/ +bool AACDecoder_IsInit(void) { + if(m_AACDecInfo && m_PSInfoBase && m_pce[0]){ + return true; + } + return false; +} + +/*********************************************************************************************************************** + * Function: AACDecoder_FreeBuffers + * + * Description: allocate all the memory needed for the AAC decoder + * + * Inputs: none + * + * Outputs: none + * + * Return: none + + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: AACFindSyncWord + * + * Description: locate the next byte-alinged sync word in the raw AAC stream + * + * Inputs: buffer to search for sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to first sync word (bytes from start of buf) + * -1 if sync not found after searching nBytes + **********************************************************************************************************************/ +int32_t AACFindSyncWord(uint8_t *buf, int32_t nBytes) +{ + int32_t i; + + /* find byte-aligned syncword (12 bits = 0xFFF) */ + for (i = 0; i < nBytes - 1; i++) { + if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL ) + return i; + } + + return -1; +} +//************************************************************************************** +int32_t AACGetSampRate(){return m_AACDecInfo->sampRate * (m_AACDecInfo->sbrEnabled ? 2 : 1);} +int32_t AACGetChannels(){return m_AACDecInfo->nChans;} +int32_t AACGetBitsPerSample(){return 16;} +int32_t AACGetID() {return m_AACDecInfo->id;} // 0-MPEG4, 1-MPEG2 +uint8_t AACGetProfile() {return (uint8_t)m_AACDecInfo->profile;} // 0-Main, 1-LC, 2-SSR, 3-reserved +uint8_t AACGetFormat() {return (uint8_t)m_AACDecInfo->format;} // 0-unknown 1-ADTS 2-ADIF, 3-RAW +int32_t AACGetOutputSamps(){return m_AACDecInfo->nChans * AAC_MAX_NSAMPS * (m_AACDecInfo->sbrEnabled ? 2 : 1);} +int32_t AACGetBitrate() { + uint32_t br = AACGetBitsPerSample() * AACGetChannels() * AACGetSampRate(); + return (br / m_AACDecInfo->compressionRatio); +} +/************************************************************************************** + * Function: AACSetRawBlockParams + * + * Description: set internal state variables for decoding a stream of raw data blocks + * + * Inputs: flag indicating source of parameters + * nChans, sampRate, + * and profile 0 = main, 1 = LC, 2 = SSR, 3 = reserved + * optionally filled-in + * + * Outputs: updated codec state + * + * Return: 0 if successful, error code (< 0) if error + * + * Notes: if copyLast == 1, then the codec sets up its internal state (for + * decoding raw blocks) based on previously-decoded ADTS header info + * if copyLast == 0, then the codec uses the values passed in + * aacFrameInfo to configure its internal state (useful when the + * source is MP4 format, for example) + **************************************************************************************/ +int32_t AACSetRawBlockParams(int32_t nChans, int32_t sampRateCore, int32_t profile, int32_t copyLast) +{ + if (!m_AACDecInfo) + return ERR_AAC_NULL_POINTER; + + m_AACDecInfo->format = AAC_FF_RAW; + if (copyLast) + return SetRawBlockParams(1, 0, 0, 0); + else + return SetRawBlockParams(0, nChans, sampRateCore, profile); +} + +/*********************************************************************************************************************** + * Function: AACDecode + * + * Description: decode AAC frame + * + * Inputs: double pointer to buffer of AAC data + * pointer to number of valid bytes remaining in inbuf + * pointer to outbuf, big enough to hold one frame of decoded PCM samples + * + * Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo + * number of output samples = 1024 per channel + * updated inbuf pointer + * updated bytesLeft + * + * Return: 0 if successful, error code (< 0) if error + * + * Notes: inbuf pointer and bytesLeft are not updated until whole frame is + * successfully decoded, so if ERR_AAC_INDATA_UNDERFLOW is returned + * just call AACDecode again with more data in inbuf + **********************************************************************************************************************/ +int32_t AACDecode(uint8_t *inbuf, int32_t *bytesLeft, int16_t *outbuf) +{ + int32_t err, offset, bitOffset, bitsAvail; + int32_t ch, baseChan, elementChans; + uint8_t *inptr; + +#ifdef AAC_ENABLE_SBR + int32_t baseChanSBR, elementChansSBR; +#endif + + /* make local copies (see "Notes" above) */ + inptr = inbuf; + bitOffset = 0; + bitsAvail = (*bytesLeft) << 3; + + /* first time through figure out what the file format is */ + if (m_AACDecInfo->format == AAC_FF_Unknown) { + if (bitsAvail < 32) + return ERR_AAC_INDATA_UNDERFLOW; + + if ((inptr)[0] == 'A' && (inptr)[1] == 'D' && (inptr)[2] == 'I' && (inptr)[3] == 'F') { + /* unpack ADIF header */ + m_AACDecInfo->format = AAC_FF_ADIF; + err = UnpackADIFHeader(&inptr, &bitOffset, &bitsAvail); + if (err) + return err; + } else { + /* assume ADTS by default */ + m_AACDecInfo->format = AAC_FF_ADTS; + } + } + /* if ADTS, search for start of next frame */ + if (m_AACDecInfo->format == AAC_FF_ADTS) { + /* can have 1-4 raw data blocks per ADTS frame (header only present for first one) */ + if (m_AACDecInfo->adtsBlocksLeft == 0) { + offset = AACFindSyncWord(inptr, bitsAvail >> 3); + if (offset < 0) + return ERR_AAC_INDATA_UNDERFLOW; + inptr += offset; + bitsAvail -= (offset << 3); + + err = UnpackADTSHeader(&inptr, &bitOffset, &bitsAvail); + if (err) + return err; + + if (m_AACDecInfo->nChans == -1) { + /* figure out implicit channel mapping if necessary */ + err = GetADTSChannelMapping(inptr, bitOffset, bitsAvail); + if (err) + return err; + } + } + m_AACDecInfo->adtsBlocksLeft--; + } else if (m_AACDecInfo->format == AAC_FF_RAW) { + err = PrepareRawBlock(); + if (err) + return err; + } + + /* check for valid number of channels */ + if (m_AACDecInfo->nChans > AAC_MAX_NCHANS || m_AACDecInfo->nChans <= 0) + return ERR_AAC_NCHANS_TOO_HIGH; + + /* will be set later if active in this frame */ + m_AACDecInfo->tnsUsed = 0; + m_AACDecInfo->pnsUsed = 0; + + bitOffset = 0; + baseChan = 0; + +#ifdef AAC_ENABLE_SBR + baseChanSBR = 0; +#endif + + do { + /* parse next syntactic element */ + if(bitsAvail < 0) return ERR_AAC_INDATA_UNDERFLOW; + err = DecodeNextElement(&inptr, &bitOffset, &bitsAvail); + if (err) + return err; + + elementChans = elementNumChans[m_AACDecInfo->currBlockID]; + if (baseChan + elementChans > AAC_MAX_NCHANS) + return ERR_AAC_NCHANS_TOO_HIGH; + + /* noiseless decoder and dequantizer */ + for (ch = 0; ch < elementChans; ch++) { + err = DecodeNoiselessData(&inptr, &bitOffset, &bitsAvail, ch); + + if (err) + return err; + + if (AACDequantize(ch)) + return ERR_AAC_DEQUANT; + } + + /* mid-side and intensity stereo */ + if (m_AACDecInfo->currBlockID == AAC_ID_CPE) { + if (StereoProcess()) + return ERR_AAC_STEREO_PROCESS; + } + + /* PNS, TNS, inverse transform */ + for (ch = 0; ch < elementChans; ch++) { + + if (PNS(ch)) + return ERR_AAC_PNS; + + if (m_AACDecInfo->sbDeinterleaveReqd[ch]) { + /* deinterleave short blocks, if required */ + if (DeinterleaveShortBlocks(ch)) + return ERR_AAC_SHORT_BLOCK_DEINT; + m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; + } + + if (TNSFilter(ch)) + return ERR_AAC_TNS; + + if (IMDCT(ch, baseChan + ch, outbuf)) + return ERR_AAC_IMDCT; + } + +#ifdef AAC_ENABLE_SBR + if (m_AACDecInfo->sbrEnabled && (m_AACDecInfo->currBlockID == AAC_ID_FIL || + m_AACDecInfo->currBlockID == AAC_ID_LFE)) { + if (m_AACDecInfo->currBlockID == AAC_ID_LFE) + elementChansSBR = elementNumChans[AAC_ID_LFE]; + else if (m_AACDecInfo->currBlockID == AAC_ID_FIL && (m_AACDecInfo->prevBlockID == AAC_ID_SCE || + m_AACDecInfo->prevBlockID == AAC_ID_CPE)) + elementChansSBR = elementNumChans[m_AACDecInfo->prevBlockID]; + else + elementChansSBR = 0; + + if (baseChanSBR + elementChansSBR > AAC_MAX_NCHANS) + return ERR_AAC_SBR_NCHANS_TOO_HIGH; + + /* parse SBR extension data if present (contained in a fill element) */ + if (DecodeSBRBitstream(baseChanSBR)) + return ERR_AAC_SBR_BITSTREAM; + + /* apply SBR */ + if (DecodeSBRData(baseChanSBR, outbuf)) + return ERR_AAC_SBR_DATA; + + baseChanSBR += elementChansSBR; + } +#endif + + baseChan += elementChans; + } while (m_AACDecInfo->currBlockID != AAC_ID_END); + + /* byte align after each raw_data_block */ + if (bitOffset) { + inptr++; + bitsAvail -= (8-bitOffset); + bitOffset = 0; + if (bitsAvail < 0) + return ERR_AAC_INDATA_UNDERFLOW; + } + + m_AACDecInfo->compressionRatio = (float)(AACGetOutputSamps()) * 2 / (inptr - inbuf); + + /* update pointers */ + m_AACDecInfo->frameCount++; + *bytesLeft -= (inptr - inbuf); + inbuf = inptr; + + return ERR_AAC_NONE; +} +/*********************************************************************************************************************** + * Function: DecodeLPCCoefs + * + * Description: decode LPC coefficients for TNS + * + * Inputs: order of TNS filter + * resolution of coefficients (3 or 4 bits) + * coefficients unpacked from bitstream + * scratch buffer (b) of size >= order + * + * Outputs: LPC coefficients in Q(FBITS_LPC_COEFS), in 'a' + * + * Return: none + * + * Notes: assumes no guard bits in input transform coefficients + * a[i] = Q(FBITS_LPC_COEFS), don't store a0 = 1.0 + * (so a[0] = first delay tap, etc.) + * max abs(a[i]) < log2(order), so for max order = 20 a[i] < 4.4 + * (up to 3 bits of gain) so a[i] has at least 31 - FBITS_LPC_COEFS - 3 + * guard bits + * to ensure no intermediate overflow in all-pole filter, set + * FBITS_LPC_COEFS such that number of guard bits >= log2(max order) + **********************************************************************************************************************/ +void DecodeLPCCoefs(int32_t order, int32_t res, int8_t *filtCoef, int32_t *a, int32_t *b) +{ + int32_t i, m, t; + const uint32_t *invQuantTab; + + if (res == 3) invQuantTab = invQuant3; + else if (res == 4) invQuantTab = invQuant4; + else return; + + for (m = 0; m < order; m++) { + t = invQuantTab[filtCoef[m] & 0x0f]; /* t = Q31 */ + for (i = 0; i < m; i++) + b[i] = a[i] - (MULSHIFT32(t, a[m-i-1]) << 1); + for (i = 0; i < m; i++) + a[i] = b[i]; + a[m] = t >> (31 - FBITS_LPC_COEFS); + } +} + +/*********************************************************************************************************************** + * Function: FilterRegion + * + * Description: apply LPC filter to one region of coefficients + * + * Inputs: number of transform coefficients in this region + * direction flag (forward = 1, backward = -1) + * order of filter + * 'size' transform coefficients + * 'order' LPC coefficients in Q(FBITS_LPC_COEFS) + * scratch buffer for history (must be >= order samples long) + * + * Outputs: filtered transform coefficients + * + * Return: guard bit mask (OR of abs value of all filtered transform coefs) + * + * Notes: assumes no guard bits in input transform coefficients + * gains 0 int32_t bits + * history buffer does not need to be preserved between regions + **********************************************************************************************************************/ +int32_t FilterRegion(int32_t size, int32_t dir, int32_t order, int32_t *audioCoef, int32_t *a, int32_t *hist) +{ + int32_t i, j, y, hi32, inc, gbMask; + U64 sum64; + + /* init history to 0 every time */ + for (i = 0; i < order; i++) + hist[i] = 0; + + sum64.w64 = 0; /* avoid warning */ + gbMask = 0; + inc = (dir ? -1 : 1); + do { + /* sum64 = a0*y[n] = 1.0*y[n] */ + y = *audioCoef; + sum64.r.hi32 = y >> (32 - FBITS_LPC_COEFS); + sum64.r.lo32 = y << FBITS_LPC_COEFS; + + /* sum64 += (a1*y[n-1] + a2*y[n-2] + ... + a[order-1]*y[n-(order-1)]) */ + for (j = order - 1; j > 0; j--) { + sum64.w64 = MADD64(sum64.w64, hist[j], a[j]); + hist[j] = hist[j-1]; + } + sum64.w64 = MADD64(sum64.w64, hist[0], a[0]); + y = (sum64.r.hi32 << (32 - FBITS_LPC_COEFS)) | (sum64.r.lo32 >> FBITS_LPC_COEFS); + + /* clip output (rare) */ + hi32 = sum64.r.hi32; + if ((hi32 >> 31) != (hi32 >> (FBITS_LPC_COEFS-1))) + y = (hi32 >> 31) ^ 0x7fffffff; + + hist[0] = y; + *audioCoef = y; + audioCoef += inc; + gbMask |= FASTABS(y); + } while (--size); + + return gbMask; +} + +/*********************************************************************************************************************** + * Function: TNSFilter + * + * Description: apply temporal noise shaping, if enabled + * + * Inputs: index of current channel + * + * Outputs: updated transform coefficients + * updated minimum guard bit count for this channel + * + * Return: 0 if successful, -1 if error + **********************************************************************************************************************/ +int32_t TNSFilter(int32_t ch) +{ + int32_t win, winLen, nWindows, nSFB, filt, bottom, top, order, maxOrder, dir; + int32_t start, end, size, tnsMaxBand, numFilt, gbMask; + int32_t *audioCoef; + uint8_t *filtLength, *filtOrder, *filtRes, *filtDir; + int8_t *filtCoef; + const uint16_t *tnsMaxBandTab; + const uint16_t *sfbTab; + ICSInfo_t *icsInfo; + TNSInfo_t *ti; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + ti = &m_PSInfoBase->tnsInfo[ch]; + + if (!ti->tnsDataPresent) + return 0; + + if (icsInfo->winSequence == 2) { + nWindows = NWINDOWS_SHORT; + winLen = NSAMPS_SHORT; + nSFB = sfBandTotalShort[m_PSInfoBase->sampRateIdx]; + maxOrder = tnsMaxOrderShort[m_AACDecInfo->profile]; + sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; + tnsMaxBandTab = tnsMaxBandsShort + tnsMaxBandsShortOffset[m_AACDecInfo->profile]; + tnsMaxBand = tnsMaxBandTab[m_PSInfoBase->sampRateIdx]; + } else { + nWindows = NWINDOWS_LONG; + winLen = NSAMPS_LONG; + nSFB = sfBandTotalLong[m_PSInfoBase->sampRateIdx]; + maxOrder = tnsMaxOrderLong[m_AACDecInfo->profile]; + sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; + tnsMaxBandTab = tnsMaxBandsLong + tnsMaxBandsLongOffset[m_AACDecInfo->profile]; + tnsMaxBand = tnsMaxBandTab[m_PSInfoBase->sampRateIdx]; + } + + if (tnsMaxBand > icsInfo->maxSFB) + tnsMaxBand = icsInfo->maxSFB; + + filtRes = ti->coefRes; + filtLength = ti->length; + filtOrder = ti->order; + filtDir = ti->dir; + filtCoef = ti->coef; + + gbMask = 0; + audioCoef = m_PSInfoBase->coef[ch]; + for (win = 0; win < nWindows; win++) { + bottom = nSFB; + numFilt = ti->numFilt[win]; + for (filt = 0; filt < numFilt; filt++) { + top = bottom; + bottom = top - *filtLength++; + bottom = MAX(bottom, (int32_t)0); + order = *filtOrder++; + order = MIN(order, maxOrder); + + if (order) { + start = sfbTab[MIN(bottom, tnsMaxBand)]; + end = sfbTab[MIN(top, tnsMaxBand)]; + size = end - start; + if (size > 0) { + dir = *filtDir++; + if (dir) + start = end - 1; + + DecodeLPCCoefs(order, filtRes[win], filtCoef, m_PSInfoBase->tnsLPCBuf, m_PSInfoBase->tnsWorkBuf); + gbMask |= FilterRegion(size, dir, order, audioCoef + start, m_PSInfoBase->tnsLPCBuf, + m_PSInfoBase->tnsWorkBuf); + } + filtCoef += order; + } + } + audioCoef += winLen; + } + + /* update guard bit count if necessary */ + size = CLZ(gbMask) - 1; + if (m_PSInfoBase->gbCurrent[ch] > size) + m_PSInfoBase->gbCurrent[ch] = size; + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeSingleChannelElement + * + * Description: decode one SCE + * + * Inputs: none + * + * Outputs: updated element instance tag + * + * Return: 0 if successful, -1 if error + * + * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) + **********************************************************************************************************************/ +int32_t DecodeSingleChannelElement() +{ + /* read instance tag */ + m_AACDecInfo->currInstTag = GetBits(NUM_INST_TAG_BITS); + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeChannelPairElement + * + * Description: decode one CPE + * + * Inputs: none + * + * Outputs: updated element instance tag + * updated commonWin + * updated ICS info, if commonWin == 1 + * updated mid-side stereo info, if commonWin == 1 + * + * Return: 0 if successful, -1 if error + * + * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) + **********************************************************************************************************************/ +int32_t DecodeChannelPairElement() +{ + int32_t sfb, gp, maskOffset; + uint8_t currBit, *maskPtr; + ICSInfo_t *icsInfo; + + + icsInfo = m_PSInfoBase->icsInfo; + + /* read instance tag */ + m_AACDecInfo->currInstTag = GetBits(NUM_INST_TAG_BITS); + + /* read common window flag and mid-side info (if present) + * store msMask bits in m_PSInfoBase->msMaskBits[] as follows: + * long blocks - pack bits for each SFB in range [0, maxSFB) starting with lsb of msMaskBits[0] + * short blocks - pack bits for each SFB in range [0, maxSFB), for each group [0, 7] + * msMaskPresent = 0 means no M/S coding + * = 1 means m_PSInfoBase->msMaskBits contains 1 bit per SFB to toggle M/S coding + * = 2 means all SFB's are M/S coded (so m_PSInfoBase->msMaskBits is not needed) + */ + m_PSInfoBase->commonWin = GetBits(1); + if (m_PSInfoBase->commonWin) { + DecodeICSInfo(icsInfo, m_PSInfoBase->sampRateIdx); + m_PSInfoBase->msMaskPresent = GetBits(2); + if (m_PSInfoBase->msMaskPresent == 1) { + maskPtr = m_PSInfoBase->msMaskBits; + *maskPtr = 0; + maskOffset = 0; + for (gp = 0; gp < icsInfo->numWinGroup; gp++) { + for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { + currBit = (uint8_t)GetBits(1); + *maskPtr |= currBit << maskOffset; + if (++maskOffset == 8) { + maskPtr++; + *maskPtr = 0; + maskOffset = 0; + } + } + } + } + } + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeLFEChannelElement + * + * Description: decode one LFE + * + * Inputs: none + * + * Outputs: updated element instance tag + * + * Return: 0 if successful, -1 if error + * + * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) + **********************************************************************************************************************/ +int32_t DecodeLFEChannelElement() +{ + /* read instance tag */ + m_AACDecInfo->currInstTag = GetBits( NUM_INST_TAG_BITS); + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeDataStreamElement + * + * Description: decode one DSE + * + * Inputs: none + * + * Outputs: updated element instance tag + * filled in data stream buffer + * + * Return: 0 if successful, -1 if error + **********************************************************************************************************************/ +int32_t DecodeDataStreamElement() +{ + uint32_t byteAlign, dataCount; + uint8_t *dataBuf; + + m_AACDecInfo->currInstTag = GetBits( NUM_INST_TAG_BITS); + byteAlign = GetBits(1); + dataCount = GetBits(8); + if (dataCount == 255) + dataCount += GetBits(8); + + if (byteAlign) + ByteAlignBitstream(); + + m_PSInfoBase->dataCount = dataCount; + dataBuf = m_PSInfoBase->dataBuf; + while (dataCount--) + *dataBuf++ = GetBits(8); + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeProgramConfigElement + * + * Description: decode one PCE + * + * Inputs: none + * + * Outputs: filled-in ProgConfigElement_t struct + * updated aac_BitStreamInfo_t struct + * + * Return: 0 if successful, error code (< 0) if error + * + * Notes: #define KEEP_PCE_COMMENTS to save the comment field of the PCE + * (otherwise we just skip it in the bitstream, to save memory) + **********************************************************************************************************************/ +int32_t DecodeProgramConfigElement(uint8_t idx) +{ + int32_t i; + + m_pce[idx]->elemInstTag = GetBits(4); + m_pce[idx]->profile = GetBits(2); + m_pce[idx]->sampRateIdx = GetBits(4); + m_pce[idx]->numFCE = GetBits(4); + m_pce[idx]->numSCE = GetBits(4); + m_pce[idx]->numBCE = GetBits(4); + m_pce[idx]->numLCE = GetBits(2); + m_pce[idx]->numADE = GetBits(3); + m_pce[idx]->numCCE = GetBits(4); + + m_pce[idx]->monoMixdown = GetBits(1) << 4; /* present flag */ + if (m_pce[idx]->monoMixdown) + m_pce[idx]->monoMixdown |= GetBits(4); /* element number */ + + m_pce[idx]->stereoMixdown = GetBits(1) << 4; /* present flag */ + if (m_pce[idx]->stereoMixdown) + m_pce[idx]->stereoMixdown |= GetBits(4); /* element number */ + + m_pce[idx]->matrixMixdown = GetBits(1) << 4; /* present flag */ + if (m_pce[idx]->matrixMixdown) { + m_pce[idx]->matrixMixdown |= GetBits(2) << 1; /* index */ + m_pce[idx]->matrixMixdown |= GetBits(1); /* pseudo-surround enable */ + } + + for (i = 0; i < m_pce[idx]->numFCE; i++) { + m_pce[idx]->fce[i] = GetBits(1) << 4; /* is_cpe flag */ + m_pce[idx]->fce[i] |= GetBits(4); /* tag select */ + } + + for (i = 0; i < m_pce[idx]->numSCE; i++) { + m_pce[idx]->sce[i] = GetBits(1) << 4; /* is_cpe flag */ + m_pce[idx]->sce[i] |= GetBits(4); /* tag select */ + } + + for (i = 0; i < m_pce[idx]->numBCE; i++) { + m_pce[idx]->bce[i] = GetBits(1) << 4; /* is_cpe flag */ + m_pce[idx]->bce[i] |= GetBits(4); /* tag select */ + } + + for (i = 0; i < m_pce[idx]->numLCE; i++) + m_pce[idx]->lce[i] = GetBits(4); /* tag select */ + + for (i = 0; i < m_pce[idx]->numADE; i++) + m_pce[idx]->ade[i] = GetBits(4); /* tag select */ + + for (i = 0; i < m_pce[idx]->numCCE; i++) { + m_pce[idx]->cce[i] = GetBits(1) << 4; /* independent/dependent flag */ + m_pce[idx]->cce[i] |= GetBits(4); /* tag select */ + } + + ByteAlignBitstream(); + /* eat comment bytes and throw away */ + i = GetBits(8); + while (i--) + GetBits(8); + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeFillElement + * + * Description: decode one fill element + * + * Inputs: none + * (14496-3, table 4.4.11) + * + * Outputs: updated element instance tag + * unpacked extension payload + * + * Return: 0 if successful, -1 if error + **********************************************************************************************************************/ +int32_t DecodeFillElement() +{ + uint32_t fillCount; + uint8_t *fillBuf; + + fillCount = GetBits(4); + if (fillCount == 15) + fillCount += (GetBits(8) - 1); + + m_PSInfoBase->fillCount = fillCount; + fillBuf = m_PSInfoBase->fillBuf; + while (fillCount--) + *fillBuf++ = GetBits(8); + + m_AACDecInfo->currInstTag = -1; /* fill elements don't have instance tag */ + m_AACDecInfo->fillExtType = 0; + +#ifdef AAC_ENABLE_SBR + /* check for SBR + * aacDecInfo->sbrEnabled is sticky (reset each raw_data_block), so for multichannel + * need to verify that all SCE/CPE/ICCE have valid SBR fill element following, and + * must upsample by 2 for LFE + */ + if (m_PSInfoBase->fillCount > 0) { + m_AACDecInfo->fillExtType = (int32_t)((m_PSInfoBase->fillBuf[0] >> 4) & 0x0f); + if (m_AACDecInfo->fillExtType == EXT_SBR_DATA || m_AACDecInfo->fillExtType == EXT_SBR_DATA_CRC) + m_AACDecInfo->sbrEnabled = 1; + } +#endif + + + m_AACDecInfo->fillBuf = m_PSInfoBase->fillBuf; + m_AACDecInfo->fillCount = m_PSInfoBase->fillCount; + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeNextElement + * + * Description: decode next syntactic element in AAC frame + * + * Inputs: double pointer to buffer containing next element + * pointer to bit offset + * pointer to number of valid bits remaining in buf + * + * Outputs: type of element decoded (aacDecInfo->currBlockID) + * type of element decoded last time (aacDecInfo->prevBlockID) + * updated aacDecInfo state, depending on which element was decoded + * updated buffer pointer + * updated bit offset + * updated number of available bits + * + * Return: 0 if successful, error code (< 0) if error + **********************************************************************************************************************/ +int32_t DecodeNextElement(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail) +{ + int32_t err, bitsUsed; + + /* init bitstream reader */ + SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); + GetBits(*bitOffset); + + m_AACDecInfo->prevBlockID = m_AACDecInfo->currBlockID; + m_AACDecInfo->currBlockID = GetBits(NUM_SYN_ID_BITS); + + /* set defaults (could be overwritten by DecodeXXXElement(), depending on currBlockID) */ + m_PSInfoBase->commonWin = 0; + + err = 0; + switch (m_AACDecInfo->currBlockID) { + case AAC_ID_SCE: + err = DecodeSingleChannelElement(); + break; + case AAC_ID_CPE: + err = DecodeChannelPairElement(); + break; + case AAC_ID_CCE: + break; + case AAC_ID_LFE: + err = DecodeLFEChannelElement(); + break; + case AAC_ID_DSE: + err = DecodeDataStreamElement(); + break; + case AAC_ID_PCE: + err = DecodeProgramConfigElement(0); + break; + case AAC_ID_FIL: + err = DecodeFillElement(); + break; + case AAC_ID_END: + break; + } + if (err) + return ERR_AAC_SYNTAX_ELEMENT; + + /* update bitstream reader */ + bitsUsed = CalcBitsUsed(*buf, *bitOffset); + *buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + *bitsAvail -= bitsUsed; + + if (*bitsAvail < 0) + return ERR_AAC_INDATA_UNDERFLOW; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** + * Function: PreMultiply + * + * Description: pre-twiddle stage of DCT4 + * + * Inputs: table index (for transform size) + * buffer of nmdct samples + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: minimum 1 GB in, 2 GB out, gains 5 (short) or 8 (long) frac bits + * i.e. gains 2-7= -5 int32_t bits (short) or 2-10 = -8 int32_t bits (long) + * normalization by -1/N is rolled into tables here (see trigtabs.c) + * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add + **********************************************************************************************************************/ +void PreMultiply(int32_t tabidx, int32_t *zbuf1) +{ + int32_t i, nmdct, ar1, ai1, ar2, ai2, z1, z2; + int32_t t, cms2, cps2a, sin2a, cps2b, sin2b; + int32_t *zbuf2; + const uint32_t *csptr; + + nmdct = nmdctTab[tabidx]; + zbuf2 = zbuf1 + nmdct - 1; + csptr = cos4sin4tab + cos4sin4tabOffset[tabidx]; + + /* whole thing should fit in registers - verify that compiler does this */ + for (i = nmdct >> 2; i != 0; i--) { + /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ + cps2a = *csptr++; + sin2a = *csptr++; + cps2b = *csptr++; + sin2b = *csptr++; + + ar1 = *(zbuf1 + 0); + ai2 = *(zbuf1 + 1); + ai1 = *(zbuf2 + 0); + ar2 = *(zbuf2 - 1); + + /* gain 2 ints bit from MULSHIFT32 by Q30, but drop 7 or 10 int32_t bits from table scaling of 1/M + * max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414 + * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from + * extra sign bits, and eat one in adding + */ + t = MULSHIFT32(sin2a, ar1 + ai1); + z2 = MULSHIFT32(cps2a, ai1) - t; + cms2 = cps2a - 2*sin2a; + z1 = MULSHIFT32(cms2, ar1) + t; + *zbuf1++ = z1; /* cos*ar1 + sin*ai1 */ + *zbuf1++ = z2; /* cos*ai1 - sin*ar1 */ + + t = MULSHIFT32(sin2b, ar2 + ai2); + z2 = MULSHIFT32(cps2b, ai2) - t; + cms2 = cps2b - 2*sin2b; + z1 = MULSHIFT32(cms2, ar2) + t; + *zbuf2-- = z2; /* cos*ai2 - sin*ar2 */ + *zbuf2-- = z1; /* cos*ar2 + sin*ai2 */ + } +} + +/*********************************************************************************************************************** + * Function: PostMultiply + * + * Description: post-twiddle stage of DCT4 + * + * Inputs: table index (for transform size) + * buffer of nmdct samples + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: minimum 1 GB in, 2 GB out - gains 2 int32_t bits + * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add + **********************************************************************************************************************/ +void PostMultiply(int32_t tabidx, int32_t *fft1) +{ + int32_t i, nmdct, ar1, ai1, ar2, ai2, skipFactor; + int32_t t, cms2, cps2, sin2; + int32_t *fft2; + const int32_t *csptr; + + nmdct = nmdctTab[tabidx]; + csptr = cos1sin1tab; + skipFactor = postSkip[tabidx]; + fft2 = fft1 + nmdct - 1; + + /* load coeffs for first pass + * cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) + */ + cps2 = *csptr++; + sin2 = *csptr; + csptr += skipFactor; + cms2 = cps2 - 2*sin2; + + for (i = nmdct >> 2; i != 0; i--) { + ar1 = *(fft1 + 0); + ai1 = *(fft1 + 1); + ar2 = *(fft2 - 1); + ai2 = *(fft2 + 0); + + /* gain 2 ints bit from MULSHIFT32 by Q30 + * max per-sample gain = MAX(sin(angle)+cos(angle)) = 1.414 + * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from + * extra sign bits, and eat one in adding + */ + t = MULSHIFT32(sin2, ar1 + ai1); + *fft2-- = t - MULSHIFT32(cps2, ai1); /* sin*ar1 - cos*ai1 */ + *fft1++ = t + MULSHIFT32(cms2, ar1); /* cos*ar1 + sin*ai1 */ + cps2 = *csptr++; + sin2 = *csptr; + csptr += skipFactor; + + ai2 = -ai2; + t = MULSHIFT32(sin2, ar2 + ai2); + *fft2-- = t - MULSHIFT32(cps2, ai2); /* sin*ar1 - cos*ai1 */ + cms2 = cps2 - 2*sin2; + *fft1++ = t + MULSHIFT32(cms2, ar2); /* cos*ar1 + sin*ai1 */ + } +} + +/*********************************************************************************************************************** + * Function: PreMultiplyRescale + * + * Description: pre-twiddle stage of DCT4, with rescaling for extra guard bits + * + * Inputs: table index (for transform size) + * buffer of nmdct samples + * number of guard bits to add to input before processing + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: see notes on PreMultiply(), above + **********************************************************************************************************************/ +void PreMultiplyRescale(int32_t tabidx, int32_t *zbuf1, int32_t es) +{ + int32_t i, nmdct, ar1, ai1, ar2, ai2, z1, z2; + int32_t t, cms2, cps2a, sin2a, cps2b, sin2b; + int32_t *zbuf2; + const uint32_t *csptr; + + nmdct = nmdctTab[tabidx]; + zbuf2 = zbuf1 + nmdct - 1; + csptr = cos4sin4tab + cos4sin4tabOffset[tabidx]; + + /* whole thing should fit in registers - verify that compiler does this */ + for (i = nmdct >> 2; i != 0; i--) { + /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ + cps2a = *csptr++; + sin2a = *csptr++; + cps2b = *csptr++; + sin2b = *csptr++; + + ar1 = *(zbuf1 + 0) >> es; + ai1 = *(zbuf2 + 0) >> es; + ai2 = *(zbuf1 + 1) >> es; + + t = MULSHIFT32(sin2a, ar1 + ai1); + z2 = MULSHIFT32(cps2a, ai1) - t; + cms2 = cps2a - 2*sin2a; + z1 = MULSHIFT32(cms2, ar1) + t; + *zbuf1++ = z1; + *zbuf1++ = z2; + + ar2 = *(zbuf2 - 1) >> es; /* do here to free up register used for es */ + + t = MULSHIFT32(sin2b, ar2 + ai2); + z2 = MULSHIFT32(cps2b, ai2) - t; + cms2 = cps2b - 2*sin2b; + z1 = MULSHIFT32(cms2, ar2) + t; + *zbuf2-- = z2; + *zbuf2-- = z1; + + } +} + +/*********************************************************************************************************************** + * Function: PostMultiplyRescale + * + * Description: post-twiddle stage of DCT4, with rescaling for extra guard bits + * + * Inputs: table index (for transform size) + * buffer of nmdct samples + * number of guard bits to remove from output + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: clips output to [-2^30, 2^30 - 1], guaranteeing at least 1 guard bit + * see notes on PostMultiply(), above + **********************************************************************************************************************/ +void PostMultiplyRescale(int32_t tabidx, int32_t *fft1, int32_t es) +{ + int32_t i, nmdct, ar1, ai1, ar2, ai2, skipFactor, z; + int32_t t, cs2, sin2; + int32_t *fft2; + const int32_t *csptr; + + nmdct = nmdctTab[tabidx]; + csptr = cos1sin1tab; + skipFactor = postSkip[tabidx]; + fft2 = fft1 + nmdct - 1; + + /* load coeffs for first pass + * cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) + */ + cs2 = *csptr++; + sin2 = *csptr; + csptr += skipFactor; + + for (i = nmdct >> 2; i != 0; i--) { + ar1 = *(fft1 + 0); + ai1 = *(fft1 + 1); + ai2 = *(fft2 + 0); + + t = MULSHIFT32(sin2, ar1 + ai1); + z = t - MULSHIFT32(cs2, ai1); + {int32_t sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} + *fft2-- = z; + cs2 -= 2*sin2; + z = t + MULSHIFT32(cs2, ar1); + {int32_t sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} + *fft1++ = z; + + cs2 = *csptr++; + sin2 = *csptr; + csptr += skipFactor; + + ar2 = *fft2; + ai2 = -ai2; + t = MULSHIFT32(sin2, ar2 + ai2); + z = t - MULSHIFT32(cs2, ai2); + {int32_t sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} + *fft2-- = z; + cs2 -= 2*sin2; + z = t + MULSHIFT32(cs2, ar2); + {int32_t sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} + *fft1++ = z; + cs2 += 2*sin2; + } +} + +/*********************************************************************************************************************** + * Function: DCT4 + * + * Description: type-IV DCT + * + * Inputs: table index (for transform size) + * buffer of nmdct samples + * number of guard bits in the input buffer + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: operates in-place + * if number of guard bits in input is < GBITS_IN_DCT4, the input is + * scaled (>>) before the DCT4 and rescaled (<<, with clipping) after + * the DCT4 (rare) + * the output has FBITS_LOST_DCT4 fewer fraction bits than the input + * the output will always have at least 1 guard bit (GBITS_IN_DCT4 >= 4) + * int32_t bits gained per stage (PreMul + FFT + PostMul) + * short blocks = (-5 + 4 + 2) = 1 total + * long blocks = (-8 + 7 + 2) = 1 total + **********************************************************************************************************************/ +void DCT4(int32_t tabidx, int32_t *coef, int32_t gb) +{ + int32_t es; + + /* fast in-place DCT-IV - adds guard bits if necessary */ + if (gb < GBITS_IN_DCT4) { + es = GBITS_IN_DCT4 - gb; + PreMultiplyRescale(tabidx, coef, es); + R4FFT(tabidx, coef); + PostMultiplyRescale(tabidx, coef, es); + } else { + PreMultiply(tabidx, coef); + R4FFT(tabidx, coef); + PostMultiply(tabidx, coef); + } +} + +/*********************************************************************************************************************** + * Function: BitReverse + * + * Description: Ken's fast in-place bit reverse, using super-small table + * + * Inputs: buffer of samples + * table index (for transform size) + * + * Outputs: bit-reversed samples in same buffer + * + * Return: none + **********************************************************************************************************************/ +void BitReverse(int32_t *inout, int32_t tabidx) +{ + int32_t *part0, *part1; + int32_t a,b, t; + const uint8_t* tab = bitrevtab + bitrevtabOffset[tabidx]; + int32_t nbits = nfftlog2Tab[tabidx]; + + part0 = inout; + part1 = inout + (1 << nbits); + + while ((a = pgm_read_byte(tab++)) != 0) { + b = pgm_read_byte(tab++); + + t=part0[4*a+0]; part0[4*a+0]=part0[4*b+0]; part0[4*b+0]=t; /* 0xxx0 <-> 0yyy0 */ + t=part0[4*a+1]; part0[4*a+1]=part0[4*b+1]; part0[4*b+1]=t; + + t=part0[4*a+2]; part0[4*a+2]=part1[4*b+0]; part1[4*b+0]=t; /* 0xxx0 <-> 0yyy0 */ + t=part0[4*a+3]; part0[4*a+3]=part1[4*b+1]; part1[4*b+1]=t; + + t=part1[4*a+0]; part1[4*a+0]=part0[4*b+2]; part0[4*b+2]=t; /* 1xxx0 <-> 0yyy1 */ + t=part1[4*a+1]; part1[4*a+1]=part0[4*b+3]; part0[4*b+3]=t; + + t=part1[4*a+2]; part1[4*a+2]=part1[4*b+2]; part1[4*b+2]=t; /* 1xxx1 <-> 1yyy1 */ + t=part1[4*a+3]; part1[4*a+3]=part1[4*b+3]; part1[4*b+3]=t; + } + + do { + t=part0[4*a+2]; part0[4*a+2]=part1[4*a+0]; part1[4*a+0]=t; /* 0xxx1 <-> 1xxx0 */ + t=part0[4*a+3]; part0[4*a+3]=part1[4*a+1]; part1[4*a+1]=t; + } while ((a = pgm_read_byte(tab++)) != 0); + + +} + +/*********************************************************************************************************************** + * Function: R4FirstPass + * + * Description: radix-4 trivial pass for decimation-in-time FFT + * + * Inputs: buffer of (bit-reversed) samples + * number of R4 butterflies per group (i.e. nfft / 4) + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: assumes 2 guard bits, gains no integer bits, + * guard bits out = guard bits in - 2 + **********************************************************************************************************************/ +void R4FirstPass(int32_t *x, int32_t bg) +{ + int32_t ar, ai, br, bi, cr, ci, dr, di; + + for (; bg != 0; bg--) { + + ar = x[0] + x[2]; + br = x[0] - x[2]; + ai = x[1] + x[3]; + bi = x[1] - x[3]; + cr = x[4] + x[6]; + dr = x[4] - x[6]; + ci = x[5] + x[7]; + di = x[5] - x[7]; + + /* max per-sample gain = 4.0 (adding 4 inputs together) */ + x[0] = ar + cr; + x[4] = ar - cr; + x[1] = ai + ci; + x[5] = ai - ci; + x[2] = br + di; + x[6] = br - di; + x[3] = bi - dr; + x[7] = bi + dr; + + x += 8; + } +} + +/*********************************************************************************************************************** + * Function: R8FirstPass + * + * Description: radix-8 trivial pass for decimation-in-time FFT + * + * Inputs: buffer of (bit-reversed) samples + * number of R8 butterflies per group (i.e. nfft / 8) + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: assumes 3 guard bits, gains 1 integer bit + * guard bits out = guard bits in - 3 (if inputs are full scale) + * or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2) + * see scaling comments in code + **********************************************************************************************************************/ +void R8FirstPass(int32_t *x, int32_t bg) +{ + int32_t ar, ai, br, bi, cr, ci, dr, di; + int32_t sr, si, tr, ti, ur, ui, vr, vi; + int32_t wr, wi, xr, xi, yr, yi, zr, zi; + + for (; bg != 0; bg--) { + + ar = x[0] + x[2]; + br = x[0] - x[2]; + ai = x[1] + x[3]; + bi = x[1] - x[3]; + cr = x[4] + x[6]; + dr = x[4] - x[6]; + ci = x[5] + x[7]; + di = x[5] - x[7]; + + sr = ar + cr; + ur = ar - cr; + si = ai + ci; + ui = ai - ci; + tr = br - di; + vr = br + di; + ti = bi + dr; + vi = bi - dr; + + ar = x[ 8] + x[10]; + br = x[ 8] - x[10]; + ai = x[ 9] + x[11]; + bi = x[ 9] - x[11]; + cr = x[12] + x[14]; + dr = x[12] - x[14]; + ci = x[13] + x[15]; + di = x[13] - x[15]; + + /* max gain of wr/wi/yr/yi vs input = 2 + * (sum of 4 samples >> 1) + */ + wr = (ar + cr) >> 1; + yr = (ar - cr) >> 1; + wi = (ai + ci) >> 1; + yi = (ai - ci) >> 1; + + /* max gain of output vs input = 4 + * (sum of 4 samples >> 1 + sum of 4 samples >> 1) + */ + x[ 0] = (sr >> 1) + wr; + x[ 8] = (sr >> 1) - wr; + x[ 1] = (si >> 1) + wi; + x[ 9] = (si >> 1) - wi; + x[ 4] = (ur >> 1) + yi; + x[12] = (ur >> 1) - yi; + x[ 5] = (ui >> 1) - yr; + x[13] = (ui >> 1) + yr; + + ar = br - di; + cr = br + di; + ai = bi + dr; + ci = bi - dr; + + /* max gain of xr/xi/zr/zi vs input = 4*sqrt(2)/2 = 2*sqrt(2) + * (sum of 8 samples, multiply by sqrt(2)/2, implicit >> 1 from Q31) + */ + xr = MULSHIFT32(SQRTHALF, ar - ai); + xi = MULSHIFT32(SQRTHALF, ar + ai); + zr = MULSHIFT32(SQRTHALF, cr - ci); + zi = MULSHIFT32(SQRTHALF, cr + ci); + + /* max gain of output vs input = (2 + 2*sqrt(2) ~= 4.83) + * (sum of 4 samples >> 1, plus xr/xi/zr/zi with gain of 2*sqrt(2)) + * in absolute terms, we have max gain of appx 9.656 (4 + 0.707*8) + * but we also gain 1 int32_t bit (from MULSHIFT32 or from explicit >> 1) + */ + x[ 6] = (tr >> 1) - xr; + x[14] = (tr >> 1) + xr; + x[ 7] = (ti >> 1) - xi; + x[15] = (ti >> 1) + xi; + x[ 2] = (vr >> 1) + zi; + x[10] = (vr >> 1) - zi; + x[ 3] = (vi >> 1) - zr; + x[11] = (vi >> 1) + zr; + + x += 16; + } +} + +/*********************************************************************************************************************** + * Function: R4Core + * + * Description: radix-4 pass for decimation-in-time FFT + * + * Inputs: buffer of samples + * number of R4 butterflies per group + * number of R4 groups per pass + * pointer to twiddle factors tables + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: gain 2 integer bits per pass (see scaling comments in code) + * min 1 GB in + * gbOut = gbIn - 1 (short block) or gbIn - 2 (long block) + * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add + **********************************************************************************************************************/ +void R4Core(int32_t *x, int32_t bg, int32_t gp, int32_t *wtab) +{ + int32_t ar, ai, br, bi, cr, ci, dr, di, tr, ti; + int32_t wd, ws, wi; + int32_t i, j, step; + int32_t *xptr, *wptr; + + for (; bg != 0; gp <<= 2, bg >>= 2) { + + step = 2*gp; + xptr = x; + + /* max per-sample gain, per group < 1 + 3*sqrt(2) ~= 5.25 if inputs x are full-scale + * do 3 groups for long block, 2 groups for short block (gain 2 int32_t bits per group) + * + * very conservative scaling: + * group 1: max gain = 5.25, int32_t bits gained = 2, gb used = 1 (2^3 = 8) + * group 2: max gain = 5.25^2 = 27.6, int32_t bits gained = 4, gb used = 1 (2^5 = 32) + * group 3: max gain = 5.25^3 = 144.7, int32_t bits gained = 6, gb used = 2 (2^8 = 256) + */ + for (i = bg; i != 0; i--) { + + wptr = wtab; + + for (j = gp; j != 0; j--) { + + ar = xptr[0]; + ai = xptr[1]; + xptr += step; + + /* gain 2 int32_t bits for br/bi, cr/ci, dr/di (MULSHIFT32 by Q30) + * gain 1 net GB + */ + ws = wptr[0]; + wi = wptr[1]; + br = xptr[0]; + bi = xptr[1]; + wd = ws + 2*wi; + tr = MULSHIFT32(wi, br + bi); + br = MULSHIFT32(wd, br) - tr; /* cos*br + sin*bi */ + bi = MULSHIFT32(ws, bi) + tr; /* cos*bi - sin*br */ + xptr += step; + + ws = wptr[2]; + wi = wptr[3]; + cr = xptr[0]; + ci = xptr[1]; + wd = ws + 2*wi; + tr = MULSHIFT32(wi, cr + ci); + cr = MULSHIFT32(wd, cr) - tr; + ci = MULSHIFT32(ws, ci) + tr; + xptr += step; + + ws = wptr[4]; + wi = wptr[5]; + dr = xptr[0]; + di = xptr[1]; + wd = ws + 2*wi; + tr = MULSHIFT32(wi, dr + di); + dr = MULSHIFT32(wd, dr) - tr; + di = MULSHIFT32(ws, di) + tr; + wptr += 6; + + tr = ar; + ti = ai; + ar = (tr >> 2) - br; + ai = (ti >> 2) - bi; + br = (tr >> 2) + br; + bi = (ti >> 2) + bi; + + tr = cr; + ti = ci; + cr = tr + dr; + ci = di - ti; + dr = tr - dr; + di = di + ti; + + xptr[0] = ar + ci; + xptr[1] = ai + dr; + xptr -= step; + xptr[0] = br - cr; + xptr[1] = bi - di; + xptr -= step; + xptr[0] = ar - ci; + xptr[1] = ai - dr; + xptr -= step; + xptr[0] = br + cr; + xptr[1] = bi + di; + xptr += 2; + } + xptr += 3*step; + } + wtab += 3*step; + } +} + + +/*********************************************************************************************************************** + * Function: R4FFT + * + * Description: Ken's very fast in-place radix-4 decimation-in-time FFT + * + * Inputs: table index (for transform size) + * buffer of samples (non bit-reversed) + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: assumes 5 guard bits in for nfft <= 512 + * gbOut = gbIn - 4 (assuming input is from PreMultiply) + * gains log2(nfft) - 2 int32_t bits total + * so gain 7 int32_t bits (LONG), 4 int32_t bits (SHORT) + **********************************************************************************************************************/ +void R4FFT(int32_t tabidx, int32_t *x) +{ + int32_t order = nfftlog2Tab[tabidx]; + int32_t nfft = nfftTab[tabidx]; + + /* decimation in time */ + BitReverse(x, tabidx); + + if (order & 0x1) { + /* long block: order = 9, nfft = 512 */ + R8FirstPass(x, nfft >> 3); /* gain 1 int32_t bit, lose 2 GB */ + R4Core(x, nfft >> 5, 8, (int32_t *)twidTabOdd); /* gain 6 int32_t bits, lose 2 GB */ + } else { + /* short block: order = 6, nfft = 64 */ + R4FirstPass(x, nfft >> 2); /* gain 0 int32_t bits, lose 2 GB */ + R4Core(x, nfft >> 4, 4, (int32_t *)twidTabEven); /* gain 4 int32_t bits, lose 1 GB */ + } +} + +/*********************************************************************************************************************** + * Function: UnpackZeros + * + * Description: fill a section of coefficients with zeros + * + * Inputs: number of coefficients + * + * Outputs: nVals zeros, starting at coef + * + * Return: none + * + * Notes: assumes nVals is always a multiple of 4 because all scalefactor bands + * are a multiple of 4 coefficients long + **********************************************************************************************************************/ +void UnpackZeros(int32_t nVals, int32_t *coef) +{ + while (nVals > 0) { + *coef++ = 0; + *coef++ = 0; + *coef++ = 0; + *coef++ = 0; + nVals -= 4; + } +} + +/*********************************************************************************************************************** + * Function: UnpackQuads + * + * Description: decode a section of 4-way vector Huffman coded coefficients + * + * Inputs index of Huffman codebook + * number of coefficients + * + * Outputs: nVals coefficients, starting at coef + * + * Return: none + * + * Notes: assumes nVals is always a multiple of 4 because all scalefactor bands + * are a multiple of 4 coefficients long + **********************************************************************************************************************/ +void UnpackQuads(int32_t cb, int32_t nVals, int32_t *coef) +{ + int32_t w, x, y, z, maxBits, nCodeBits, nSignBits, val; + uint32_t bitBuf; + + maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 4; + while (nVals > 0) { + /* decode quad */ + bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); + nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET], bitBuf, &val); + + w = (((int32_t)(val) << 20) >> 29); /* bits 11-9, sign-extend */ + x = (((int32_t)(val) << 23) >> 29); /* bits 8-6, sign-extend */ + y = (((int32_t)(val) << 26) >> 29); /* bits 5-3, sign-extend */ + z = (((int32_t)(val) << 29) >> 29); /* bits 2-0, sign-extend */ + + bitBuf <<= nCodeBits; + nSignBits = (int32_t)(((uint32_t)(val) << 17) >> 29); /* bits 14-12, unsigned */ + + AdvanceBitstream(nCodeBits + nSignBits); + if (nSignBits) { + if (w) {w ^= ((int32_t)bitBuf >> 31); w -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + if (x) {x ^= ((int32_t)bitBuf >> 31); x -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + } + *coef++ = w; *coef++ = x; *coef++ = y; *coef++ = z; + nVals -= 4; + } +} + +/*********************************************************************************************************************** + * Function: UnpackPairsNoEsc + * + * Description: decode a section of 2-way vector Huffman coded coefficients, + * using non-esc tables (5 through 10) + * + * Inputs index of Huffman codebook (must not be the escape codebook) + * number of coefficients + * + * Outputs: nVals coefficients, starting at coef + * + * Return: none + * + * Notes: assumes nVals is always a multiple of 2 because all scalefactor bands + * are a multiple of 4 coefficients long + **********************************************************************************************************************/ +void UnpackPairsNoEsc(int32_t cb, int32_t nVals, int32_t *coef) +{ + int32_t y, z, maxBits, nCodeBits, nSignBits, val; + uint32_t bitBuf; + + maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2; + while (nVals > 0) { + /* decode pair */ + bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); + nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val); + + y = (((int32_t)(val) << 22) >> 27); /* bits 9-5, sign-extend */ + z = (((int32_t)(val) << 27) >> 27); /* bits 4-0, sign-extend */ + + bitBuf <<= nCodeBits; + nSignBits = (((uint32_t)(val) << 20) >> 30); /* bits 11-10, unsigned */ + AdvanceBitstream(nCodeBits + nSignBits); + if (nSignBits) { + if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + } + *coef++ = y; *coef++ = z; + nVals -= 2; + } +} + +/*********************************************************************************************************************** + * Function: UnpackPairsEsc + * + * Description: decode a section of 2-way vector Huffman coded coefficients, + * using esc table (11) + * + * Inputs index of Huffman codebook (must be the escape codebook) + * number of coefficients + * + * Outputs: nVals coefficients, starting at coef + * + * Return: none + * + * Notes: assumes nVals is always a multiple of 2 because all scalefactor bands + * are a multiple of 4 coefficients long + **********************************************************************************************************************/ +void UnpackPairsEsc(int32_t cb, int32_t nVals, int32_t *coef) +{ + int32_t y, z, maxBits, nCodeBits, nSignBits, n, val; + uint32_t bitBuf; + + maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2; + while (nVals > 0) { + /* decode pair with escape value */ + bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); + nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val); + + y = (((int32_t)(val) << 20) >> 26); /* bits 11-6, sign-extend */ + z = (((int32_t)(val) << 26) >> 26); /* bits 5-0, sign-extend */ + + bitBuf <<= nCodeBits; + nSignBits = (((uint32_t)(val) << 18) >> 30); /* bits 13-12, unsigned */ + AdvanceBitstream(nCodeBits + nSignBits); + + if (y == 16) { + n = 4; + while (GetBits(1) == 1) + n++; + y = (1 << n) + GetBits(n); + } + if (z == 16) { + n = 4; + while (GetBits(1) == 1) + n++; + z = (1 << n) + GetBits(n); + } + + if (nSignBits) { + if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} + } + + *coef++ = y; *coef++ = z; + nVals -= 2; + } +} + +/*********************************************************************************************************************** + * Function: DecodeSpectrumLong + * + * Description: decode transform coefficients for frame with one long block + * + * Inputs: index of current channel + * + * Outputs: decoded, quantized coefficients for this channel + * + * Return: none + * + * Notes: adds in pulse data if present + * fills coefficient buffer with zeros in any region not coded with + * codebook in range [1, 11] (including sfb's above sfbMax) + **********************************************************************************************************************/ +void DecodeSpectrumLong(int32_t ch) +{ + int32_t i, sfb, cb, nVals, offset; + const uint16_t *sfbTab; + uint8_t *sfbCodeBook; + int32_t *coef; + ICSInfo_t *icsInfo; + + coef = m_PSInfoBase->coef[ch]; + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + /* decode long block */ + sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; + sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; + for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { + cb = *sfbCodeBook++; + nVals = sfbTab[sfb+1] - sfbTab[sfb]; + + if (cb == 0) + UnpackZeros(nVals, coef); + else if (cb <= 4) + UnpackQuads(cb, nVals, coef); + else if (cb <= 10) + UnpackPairsNoEsc(cb, nVals, coef); + else if (cb == 11) + UnpackPairsEsc(cb, nVals, coef); + else + UnpackZeros(nVals, coef); + + coef += nVals; + } + + /* fill with zeros above maxSFB */ + nVals = NSAMPS_LONG - sfbTab[sfb]; + UnpackZeros(nVals, coef); + + /* add pulse data, if present */ + if (m_pulseInfo[ch].pulseDataPresent) { + coef = m_PSInfoBase->coef[ch]; + offset = sfbTab[m_pulseInfo[ch].startSFB]; + for (i = 0; i < m_pulseInfo[ch].numPulse; i++) { + offset += m_pulseInfo[ch].offset[i]; + if (coef[offset] > 0) + coef[offset] += m_pulseInfo[ch].amp[i]; + else + coef[offset] -= m_pulseInfo[ch].amp[i]; + } + ASSERT(offset < NSAMPS_LONG); + } +} + +/*********************************************************************************************************************** + * Function: DecodeSpectrumShort + * + * Description: decode transform coefficients for frame with eight short blocks + * + * Inputs: index of current channel + * + * Outputs: decoded, quantized coefficients for this channel + * + * Return: none + * + * Notes: fills coefficient buffer with zeros in any region not coded with + * codebook in range [1, 11] (including sfb's above sfbMax) + * deinterleaves window groups into 8 windows + **********************************************************************************************************************/ +void DecodeSpectrumShort(int32_t ch) +{ + int32_t gp, cb, nVals=0, win, offset, sfb; + const uint16_t *sfbTab; + uint8_t *sfbCodeBook; + int32_t *coef; + ICSInfo_t *icsInfo; + + coef = m_PSInfoBase->coef[ch]; + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + /* decode short blocks, deinterleaving in-place */ + sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; + sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; + for (gp = 0; gp < icsInfo->numWinGroup; gp++) { + for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { + nVals = sfbTab[sfb+1] - sfbTab[sfb]; + cb = *sfbCodeBook++; + + for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { + offset = win*NSAMPS_SHORT; + if (cb == 0) + UnpackZeros(nVals, coef + offset); + else if (cb <= 4) + UnpackQuads(cb, nVals, coef + offset); + else if (cb <= 10) + UnpackPairsNoEsc(cb, nVals, coef + offset); + else if (cb == 11) + UnpackPairsEsc(cb, nVals, coef + offset); + else + UnpackZeros(nVals, coef + offset); + } + coef += nVals; + } + + /* fill with zeros above maxSFB */ + for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { + offset = win*NSAMPS_SHORT; + nVals = NSAMPS_SHORT - sfbTab[sfb]; + UnpackZeros(nVals, coef + offset); + } + coef += nVals; + coef += (icsInfo->winGroupLen[gp] - 1)*NSAMPS_SHORT; + } + + ASSERT(coef == m_PSInfoBase->coef[ch] + NSAMPS_LONG); +} + +#ifndef AAC_ENABLE_SBR +/*********************************************************************************************************************** + * Function: DecWindowOverlap + * + * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, + * for winSequence LONG-LONG + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * number of channels + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans + * + * Return: none + * + * Notes: this processes one channel at a time, but skips every other sample in + * the output buffer (pcm) for stereo interleaving + * this should fit in registers on ARM + * + **********************************************************************************************************************/ +void DecWindowOverlap(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev) +{ + int32_t in, w0, w1, f0, f1; + int32_t *buf1, *over1; + int16_t *pcm1; + const int32_t *wndCurr, *wndPrev; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + pcm1 = pcm0 + (1024 - 1) * nChans; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + if (winTypeCurr == winTypePrev) { + /* cut window loads in half since current and overlap sections use same symmetric window */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } else { + /* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */ + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } +} + +/*********************************************************************************************************************** + * Function: DecWindowOverlapLongStart + * + * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, + * for winSequence LONG-START + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * number of channels + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans + * + * Return: none + * + * Notes: this processes one channel at a time, but skips every other sample in + * the output buffer (pcm) for stereo interleaving + * this should fit in registers on ARM + **********************************************************************************************************************/ +void DecWindowOverlapLongStart(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev) +{ + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1; + int16_t *pcm1; + const int32_t *wndPrev, *wndCurr; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + pcm1 = pcm0 + (1024 - 1) * nChans; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + i = 448; /* 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + in = *buf1--; + + *over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */ + *over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */ + } while (--i); + + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + + /* do 64 more loops - 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */ + w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */ + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */ + *over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */ + } while (over0 < over1); +} + +/*********************************************************************************************************************** + * Function: DecWindowOverlapLongStop + * + * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, + * for winSequence LONG-STOP + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * number of channels + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans + * + * Return: none + * + * Notes: this processes one channel at a time, but skips every other sample in + * the output buffer (pcm) for stereo interleaving + * this should fit in registers on ARM + **********************************************************************************************************************/ +void DecWindowOverlapLongStop(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev) +{ + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1; + int16_t *pcm1; + const int32_t *wndPrev, *wndCurr; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + pcm1 = pcm0 + (1024 - 1) * nChans; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + + i = 448; /* 2 outputs, 2 overlaps per loop */ + do { + /* Wn = 0 for n = (0, 1, ... 447) */ + /* Wn = 1 for n = (576, 577, ... 1023) */ + in = *buf0++; + f1 = in >> 1; /* scale since skipping multiply by Q31 */ + + in = *over0; + *pcm0 = CLIPTOSHORT( (in + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (--i); + + /* do 64 more loops - 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ + w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); +} + +/*********************************************************************************************************************** + * Function: DecWindowOverlapShort + * + * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, + * for winSequence EIGHT-SHORT (does all 8 short blocks) + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * number of channels + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans + * + * Return: none + * + * Notes: this processes one channel at a time, but skips every other sample in + * the output buffer (pcm) for stereo interleaving + * this should fit in registers on ARM + **********************************************************************************************************************/ +void DecWindowOverlapShort(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev) +{ + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1; + int16_t *pcm1; + const int32_t *wndPrev, *wndCurr; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + + /* pcm[0-447] = 0 + overlap[0-447] */ + i = 448; + do { + f0 = *over0++; + f1 = *over0++; + *pcm0 = CLIPTOSHORT( (f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; + *pcm0 = CLIPTOSHORT( (f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; + i -= 2; + } while (i); + + /* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */ + pcm1 = pcm0 + (128 - 1) * nChans; + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + do { + w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ + w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *over1; + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + /* save over0/over1 for next short block, in the slots just vacated */ + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + + /* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703] + * pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831] + * pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959] + */ + for (i = 0; i < 3; i++) { + pcm0 += 64 * nChans; + pcm1 = pcm0 + (128 - 1) * nChans; + over0 += 64; + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *(over0 - 128); /* from last short block */ + in += *(over0 + 0); /* from last full frame */ + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *(over1 - 128); /* from last short block */ + in += *(over1 + 0); /* from last full frame */ + *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm1 -= nChans; + + /* save over0/over1 for next short block, in the slots just vacated */ + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } + + /* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023] + * over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127] + */ + pcm0 += 64 * nChans; + over0 -= 832; /* points at overlap[64] */ + over1 = over0 + 128 - 1; /* points at overlap[191] */ + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *(over0 + 768); /* from last short block */ + in += *(over0 + 896); /* from last full frame */ + *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); + pcm0 += nChans; + + in = *(over1 + 768); /* from last short block */ + *(over1 - 128) = in + f1; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */ + *over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */ + } while (over0 < over1); + + /* over0 now points at overlap[128] */ + + /* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127] + * over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127] + * over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127] + * over[448-576] = Wc[128-255] * block7[128-255] + */ + for (i = 0; i < 3; i++) { + over0 += 64; + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + /* from last short block */ + *(over0 - 128) -= f0; + *(over1 - 128)+= f1; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } + + /* over[576-1024] = 0 */ + i = 448; + over0 += 64; + do { + *over0++ = 0; + *over0++ = 0; + *over0++ = 0; + *over0++ = 0; + i -= 4; + } while (i); +} + +#endif /* !AAC_ENABLE_SBR */ + +/*********************************************************************************************************************** + * Function: IMDCT + * + * Description: inverse transform and convert to 16-bit PCM + * + * Inputs: index of current channel (0 for SCE/LFE, 0 or 1 for CPE) + * output channel (range = [0, nChans-1]) + * + * Outputs: complete frame of decoded PCM, after inverse transform + * + * Return: 0 if successful, -1 if error + * + * Notes: If AAC_ENABLE_SBR is defined at compile time then window + overlap + * does NOT clip to 16-bit PCM and does NOT interleave channels + * If AAC_ENABLE_SBR is NOT defined at compile time, then window + overlap + * does clip to 16-bit PCM and interleaves channels + * If SBR is enabled at compile time, but we don't know whether it is + * actually used for this frame (e.g. the first frame of a stream), + * we need to produce both clipped 16-bit PCM in outbuf AND + * unclipped 32-bit PCM in the SBR input buffer. In this case we make + * a separate pass over the 32-bit PCM to produce 16-bit PCM output. + * This inflicts a slight performance hit when decoding non-SBR files. + **********************************************************************************************************************/ +int32_t IMDCT(int32_t ch, int32_t chOut, int16_t *outbuf) +{ + int32_t i; + ICSInfo_t *icsInfo; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + outbuf += chOut; + + /* optimized type-IV DCT (operates inplace) */ + if (icsInfo->winSequence == 2) { + /* 8 short blocks */ + for (i = 0; i < 8; i++) + DCT4(0, m_PSInfoBase->coef[ch] + i*128, m_PSInfoBase->gbCurrent[ch]); + } else { + /* 1 long block */ + DCT4(1, m_PSInfoBase->coef[ch], m_PSInfoBase->gbCurrent[ch]); + } + +#ifdef AAC_ENABLE_SBR + /* window, overlap-add, don't clip to short (send to SBR decoder) + * store the decoded 32-bit samples in top half (second AAC_MAX_NSAMPS samples) of coef buffer + */ + if (icsInfo->winSequence == 0) + DecWindowOverlapNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], + m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 1) + DecWindowOverlapLongStartNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], + m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 2) + DecWindowOverlapShortNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], + m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 3) + DecWindowOverlapLongStopNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], + m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + + if (!m_AACDecInfo->sbrEnabled) { + for (i = 0; i < AAC_MAX_NSAMPS; i++) { + *outbuf = CLIPTOSHORT((m_PSInfoBase->sbrWorkBuf[ch][i] + RND_VAL) >> FBITS_OUT_IMDCT); + outbuf += m_AACDecInfo->nChans; + } + } + + m_AACDecInfo->rawSampleBuf[ch] = m_PSInfoBase->sbrWorkBuf[ch]; + m_AACDecInfo->rawSampleBytes = sizeof(int32_t); + m_AACDecInfo->rawSampleFBits = FBITS_OUT_IMDCT; +#else + /* window, overlap-add, round to PCM - optimized for each window sequence */ + if (icsInfo->winSequence == 0) + DecWindowOverlap(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, + icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 1) + DecWindowOverlapLongStart(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, + icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 2) + DecWindowOverlapShort(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, + icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + else if (icsInfo->winSequence == 3) + DecWindowOverlapLongStop(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, + icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); + + m_AACDecInfo->rawSampleBuf[ch] = 0; + m_AACDecInfo->rawSampleBytes = 0; + m_AACDecInfo->rawSampleFBits = 0; +#endif + + m_PSInfoBase->prevWinShape[chOut] = icsInfo->winShape; + + return 0; +} + +/*********************************************************************************************************************** + * Function: DecodeICSInfo + * + * Description: decode individual channel stream info + * + * Inputs: sample rate index + * + * Outputs: updated icsInfo struct + * + * Return: none + **********************************************************************************************************************/ +void DecodeICSInfo(ICSInfo_t *icsInfo, int32_t sampRateIdx) +{ + int32_t sfb, g, mask; + + icsInfo->icsResBit = GetBits(1); + icsInfo->winSequence = GetBits(2); + icsInfo->winShape = GetBits(1); + if (icsInfo->winSequence == 2) { + /* short block */ + icsInfo->maxSFB = GetBits(4); + icsInfo->sfGroup = GetBits(7); + icsInfo->numWinGroup = 1; + icsInfo->winGroupLen[0] = 1; + mask = 0x40; /* start with bit 6 */ + for (g = 0; g < 7; g++) { + if (icsInfo->sfGroup & mask) { + icsInfo->winGroupLen[icsInfo->numWinGroup - 1]++; + } else { + icsInfo->numWinGroup++; + icsInfo->winGroupLen[icsInfo->numWinGroup - 1] = 1; + } + mask >>= 1; + } + } else { + /* long block */ + icsInfo->maxSFB = GetBits(6); + icsInfo->predictorDataPresent = GetBits(1); + if (icsInfo->predictorDataPresent) { + icsInfo->predictorReset = GetBits(1); + if (icsInfo->predictorReset) + icsInfo->predictorResetGroupNum = GetBits(5); + for (sfb = 0; sfb < MIN(icsInfo->maxSFB, predSFBMax[sampRateIdx]); sfb++) + icsInfo->predictionUsed[sfb] = GetBits(1); + } + icsInfo->numWinGroup = 1; + icsInfo->winGroupLen[0] = 1; + } +} + +/*********************************************************************************************************************** + * Function: DecodeSectionData + * + * Description: decode section data (scale factor band groupings and + * associated Huffman codebooks) + * + * Inputs: window sequence (short or long blocks) + * number of window groups (1 for long blocks, 1-8 for short blocks) + * max coded scalefactor band + * + * Outputs: index of Huffman codebook for each scalefactor band in each section + * + * Return: none + * + * Notes: sectCB, sectEnd, sfbCodeBook, ordered by window groups for short blocks + **********************************************************************************************************************/ +void DecodeSectionData(int32_t winSequence, int32_t numWinGrp, int32_t maxSFB, uint8_t *sfbCodeBook) +{ + int32_t g, cb, sfb; + int32_t sectLen, sectLenBits, sectLenIncr, sectEscapeVal; + + sectLenBits = (winSequence == 2 ? 3 : 5); + sectEscapeVal = (1 << sectLenBits) - 1; + + for (g = 0; g < numWinGrp; g++) { + sfb = 0; + while (sfb < maxSFB) { + cb = GetBits(4); /* next section codebook */ + sectLen = 0; + do { + sectLenIncr = GetBits(sectLenBits); + sectLen += sectLenIncr; + } while (sectLenIncr == sectEscapeVal); + + sfb += sectLen; + while (sectLen--) + *sfbCodeBook++ = (uint8_t)cb; + } + ASSERT(sfb == maxSFB); + } +} + +/*********************************************************************************************************************** + * Function: DecodeOneScaleFactor + * + * Description: decode one scalefactor using scalefactor Huffman codebook + * + * Inputs: none + * + * Outputs: none + * + * Return: one decoded scalefactor, including index_offset of -60 + **********************************************************************************************************************/ +int32_t DecodeOneScaleFactor() +{ + int32_t nBits, val; + uint32_t bitBuf; + + /* decode next scalefactor from bitstream */ + bitBuf = GetBitsNoAdvance(huffTabScaleFactInfo.maxBits) << (32 - huffTabScaleFactInfo.maxBits); + nBits = DecodeHuffmanScalar(huffTabScaleFact, &huffTabScaleFactInfo, bitBuf, &val); + AdvanceBitstream(nBits); + return val; +} + +/*********************************************************************************************************************** + * Function: DecodeScaleFactors + * + * Description: decode scalefactors, PNS energy, and intensity stereo weights + * + * Inputs: number of window groups (1 for long blocks, 1-8 for short blocks) + * max coded scalefactor band + * global gain (starting value for differential scalefactor coding) + * index of Huffman codebook for each scalefactor band in each section + * + * Outputs: decoded scalefactor for each section + * + * Return: none + * + * Notes: sfbCodeBook, scaleFactors ordered by window groups for short blocks + * for section with codebook 13, scaleFactors buffer has decoded PNS + * energy instead of regular scalefactor + * for section with codebook 14 or 15, scaleFactors buffer has intensity + * stereo weight instead of regular scalefactor + **********************************************************************************************************************/ +void DecodeScaleFactors(int32_t numWinGrp, int32_t maxSFB, int32_t globalGain, + uint8_t *sfbCodeBook, int16_t *scaleFactors) +{ + int32_t g, sfbCB, nrg, npf, val, sf, is; + + /* starting values for differential coding */ + sf = globalGain; + is = 0; + nrg = globalGain - 90 - 256; + npf = 1; + + for (g = 0; g < numWinGrp * maxSFB; g++) { + sfbCB = *sfbCodeBook++; + + if (sfbCB == 14 || sfbCB == 15) { + /* intensity stereo - differential coding */ + val = DecodeOneScaleFactor(); + is += val; + *scaleFactors++ = (int16_t)is; + } else if (sfbCB == 13) { + /* PNS - first energy is directly coded, rest are Huffman coded (npf = noise_pcm_flag) */ + if (npf) { + val = GetBits(9); + npf = 0; + } else { + val = DecodeOneScaleFactor(); + } + nrg += val; + *scaleFactors++ = (int16_t)nrg; + } else if (sfbCB >= 1 && sfbCB <= 11) { + /* regular (non-zero) region - differential coding */ + val = DecodeOneScaleFactor(); + sf += val; + *scaleFactors++ = (int16_t)sf; + } else { + /* inactive scalefactor band if codebook 0 */ + *scaleFactors++ = 0; + } + } +} + +/*********************************************************************************************************************** + * Function: DecodePulseInfo + * + * Description: decode pulse information + * + * Inputs: none + * + * Outputs: updated PulseInfo_t struct + * + * Return: none + **********************************************************************************************************************/ +void DecodePulseInfo(uint8_t ch) +{ + int32_t i; + + m_pulseInfo[ch].numPulse = GetBits(2) + 1; /* add 1 here */ + m_pulseInfo[ch].startSFB = GetBits(6); + for (i = 0; i < m_pulseInfo[ch].numPulse; i++) { + m_pulseInfo[ch].offset[i] = GetBits(5); + m_pulseInfo[ch].amp[i] = GetBits(4); + } +} + +/*********************************************************************************************************************** + * Function: DecodeTNSInfo + * + * Description: decode TNS filter information + * + * Inputs: window sequence (short or long blocks) + * + * Outputs: updated TNSInfo_t struct + * buffer of decoded (signed) TNS filter coefficients + * + * Return: none + **********************************************************************************************************************/ +void DecodeTNSInfo(int32_t winSequence, TNSInfo_t *ti, int8_t *tnsCoef) +{ + int32_t i, w, f, coefBits, compress; + int8_t c, s, n; + uint8_t *filtLength, *filtOrder, *filtDir; + + filtLength = ti->length; + filtOrder = ti->order; + filtDir = ti->dir; + + if (winSequence == 2) { + /* short blocks */ + for (w = 0; w < NWINDOWS_SHORT; w++) { + ti->numFilt[w] = GetBits(1); + if (ti->numFilt[w]) { + ti->coefRes[w] = GetBits(1) + 3; + *filtLength = GetBits(4); + *filtOrder = GetBits(3); + if (*filtOrder) { + *filtDir++ = GetBits(1); + compress = GetBits(1); + coefBits = (int32_t)ti->coefRes[w] - compress; /* 2, 3, or 4 */ + s = sgnMask[coefBits - 2]; + n = negMask[coefBits - 2]; + for (i = 0; i < *filtOrder; i++) { + c = GetBits(coefBits); + if (c & s) c |= n; + *tnsCoef++ = c; + } + } + filtLength++; + filtOrder++; + } + } + } else { + /* long blocks */ + ti->numFilt[0] = GetBits(2); + if (ti->numFilt[0]) + ti->coefRes[0] = GetBits(1) + 3; + for (f = 0; f < ti->numFilt[0]; f++) { + *filtLength = GetBits(6); + *filtOrder = GetBits(5); + if (*filtOrder) { + *filtDir++ = GetBits(1); + compress = GetBits(1); + coefBits = (int32_t)ti->coefRes[0] - compress; /* 2, 3, or 4 */ + s = sgnMask[coefBits - 2]; + n = negMask[coefBits - 2]; + for (i = 0; i < *filtOrder; i++) { + c = GetBits(coefBits); + if (c & s) c |= n; + *tnsCoef++ = c; + } + } + filtLength++; + filtOrder++; + } + } +} + +/* bitstream field lengths for gain control data: + * gainBits[winSequence][0] = maxWindow (how many gain windows there are) + * gainBits[winSequence][1] = locBitsZero (bits for alocCode if window == 0) + * gainBits[winSequence][2] = locBits (bits for alocCode if window != 0) + */ +static const uint8_t gainBits[4][3] = { + {1, 5, 5}, /* long */ + {2, 4, 2}, /* start */ + {8, 2, 2}, /* short */ + {2, 4, 5}, /* stop */ +}; + +/*********************************************************************************************************************** + * Function: DecodeGainControlInfo + * + * Description: decode gain control information (SSR profile only) + * + * Inputs: window sequence (short or long blocks) + * + * Outputs: updated GainControlInfo_t struct + * + * Return: none + **********************************************************************************************************************/ +void DecodeGainControlInfo(int32_t winSequence, GainControlInfo_t *gi) +{ + int32_t bd, wd, ad; + int32_t locBits, locBitsZero, maxWin; + + gi->maxBand = GetBits(2); + maxWin = (int32_t)gainBits[winSequence][0]; + locBitsZero = (int32_t)gainBits[winSequence][1]; + locBits = (int32_t)gainBits[winSequence][2]; + + for (bd = 1; bd <= gi->maxBand; bd++) { + for (wd = 0; wd < maxWin; wd++) { + gi->adjNum[bd][wd] = GetBits(3); + for (ad = 0; ad < gi->adjNum[bd][wd]; ad++) { + gi->alevCode[bd][wd][ad] = GetBits(4); + gi->alocCode[bd][wd][ad] = GetBits(wd == 0 ? locBitsZero : locBits); + } + } + } +} + +/*********************************************************************************************************************** + * Function: DecodeICS + * + * Description: decode individual channel stream + * + * Inputs: index of current channel + * + * Outputs: updated section data, scale factor data, pulse data, TNS data, + * and gain control data + * + * Return: none + **********************************************************************************************************************/ +void DecodeICS(int32_t ch) +{ + int32_t globalGain; + ICSInfo_t *icsInfo; + TNSInfo_t *ti; + GainControlInfo_t *gi; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + globalGain = GetBits(8); + if (!m_PSInfoBase->commonWin) + DecodeICSInfo(icsInfo, m_PSInfoBase->sampRateIdx); + + DecodeSectionData(icsInfo->winSequence, icsInfo->numWinGroup, icsInfo->maxSFB, m_PSInfoBase->sfbCodeBook[ch]); + + DecodeScaleFactors(icsInfo->numWinGroup, icsInfo->maxSFB, globalGain, m_PSInfoBase->sfbCodeBook[ch], + m_PSInfoBase->scaleFactors[ch]); + + m_pulseInfo[ch].pulseDataPresent = GetBits(1); + if (m_pulseInfo[ch].pulseDataPresent) + DecodePulseInfo(ch); + + ti = &m_PSInfoBase->tnsInfo[ch]; + ti->tnsDataPresent = GetBits(1); + if (ti->tnsDataPresent) + DecodeTNSInfo(icsInfo->winSequence, ti, ti->coef); + + gi = &m_PSInfoBase->gainControlInfo[ch]; + gi->gainControlDataPresent = GetBits(1); + if (gi->gainControlDataPresent) + DecodeGainControlInfo(icsInfo->winSequence, gi); +} + +/*********************************************************************************************************************** + * Function: DecodeNoiselessData + * + * Description: decode noiseless data (side info and transform coefficients) + * + * Inputs: double pointer to buffer pointing to start of individual channel stream + * (14496-3, table 4.4.24) + * pointer to bit offset + * pointer to number of valid bits remaining in buf + * index of current channel + * + * Outputs: updated global gain, section data, scale factor data, pulse data, + * TNS data, gain control data, and spectral data + * + * Return: 0 if successful, error code (< 0) if error + **********************************************************************************************************************/ +int32_t DecodeNoiselessData(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail, int32_t ch) +{ + int32_t bitsUsed; + ICSInfo_t *icsInfo; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + SetBitstreamPointer((*bitsAvail+7) >> 3, *buf); + GetBits(*bitOffset); + + DecodeICS(ch); + + if (icsInfo->winSequence == 2) + DecodeSpectrumShort(ch); + else + DecodeSpectrumLong(ch); + + bitsUsed = CalcBitsUsed(*buf, *bitOffset); + *buf += ((bitsUsed + *bitOffset) >> 3); + *bitOffset = ((bitsUsed + *bitOffset) & 0x07); + *bitsAvail -= bitsUsed; + + m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; + m_AACDecInfo->tnsUsed |= m_PSInfoBase->tnsInfo[ch].tnsDataPresent; /* set flag if TNS used for any channel */ + + return ERR_AAC_NONE; +} +/*********************************************************************************************************************** + * Function: DecodeHuffmanScalar + * + * Description: decode one Huffman symbol from bitstream + * + * Inputs: pointers to Huffman table and info struct + * left-aligned bit buffer with >= huffTabInfo->maxBits bits + * + * Outputs: decoded symbol in *val + * + * Return: number of bits in symbol + * + * Notes: assumes canonical Huffman codes: + * first CW always 0, we have "count" CW's of length "nBits" bits + * starting CW for codes of length nBits+1 = + * (startCW[nBits] + count[nBits]) << 1 + * if there are no codes at nBits, then we just keep << 1 each time + * (since count[nBits] = 0) + **********************************************************************************************************************/ +int32_t DecodeHuffmanScalar(const uint16_t *huffTab, const HuffInfo_t *huffTabInfo, uint32_t bitBuf, int32_t *val) +{ + uint32_t count, start, shift, t; + const uint8_t *countPtr; + const uint16_t *map; + + map = huffTab + huffTabInfo->offset; + countPtr = huffTabInfo->count; + + start = 0; + count = 0; + shift = 32; + do { + start += count; + start <<= 1; + map += count; + count = *countPtr++; + shift--; + t = (bitBuf >> shift) - start; + } while (t >= count); + + *val = (int32_t)map[t]; + return (countPtr - huffTabInfo->count); +} + +/*********************************************************************************************************************** +* Function: UnpackADTSHeader +* +* Description: parse the ADTS frame header and initialize decoder state, Audio Data Transport Stream +* +* Inputs: double pointer to buffer with complete ADTS frame header (byte aligned) +* header size = 7 bytes, plus 2 if CRC +* +* Outputs: filled in ADTS struct +* updated buffer pointer +* updated bit offset +* updated number of available bits +* +* Return: 0 if successful, error code (< 0) if error +* verify that fixed fields don't change between frames +***********************************************************************************************************************/ +int32_t UnpackADTSHeader(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail) +{ + int32_t bitsUsed; + + /* init bitstream reader */ + SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); + GetBits(*bitOffset); + + /* verify that first 12 bits of header are syncword */ + if (GetBits(12) != 0x0fff) { + return ERR_AAC_INVALID_ADTS_HEADER; + } + + /* fixed fields - should not change from frame to frame */ + m_fhADTS.id = GetBits(1); + m_fhADTS.layer = GetBits(2); + m_fhADTS.protectBit = GetBits(1); + m_fhADTS.profile = GetBits(2); + m_fhADTS.sampRateIdx = GetBits(4); + m_fhADTS.privateBit = GetBits(1); + m_fhADTS.channelConfig = GetBits(3); + m_fhADTS.origCopy = GetBits(1); + m_fhADTS.home = GetBits(1); + + /* variable fields - can change from frame to frame */ + m_fhADTS.copyBit = GetBits(1); + m_fhADTS.copyStart = GetBits(1); + m_fhADTS.frameLength = GetBits(13); + m_fhADTS.bufferFull = GetBits(11); + m_fhADTS.numRawDataBlocks = GetBits(2) + 1; + + /* note - MPEG4 spec, correction 1 changes how CRC is handled when protectBit == 0 and numRawDataBlocks > 1 */ + if (m_fhADTS.protectBit == 0) + m_fhADTS.crcCheckWord = GetBits(16); + + /* byte align */ + ByteAlignBitstream(); /* should always be aligned anyway */ + + /* check validity of header */ + if (m_fhADTS.layer != 0 || m_fhADTS.profile != AAC_PROFILE_LC || + m_fhADTS.sampRateIdx >= NUM_SAMPLE_RATES || m_fhADTS.channelConfig >= NUM_DEF_CHAN_MAPS) + return ERR_AAC_INVALID_ADTS_HEADER; + +#ifndef AAC_ENABLE_MPEG4 + if (m_fhADTS.id != 1) + return ERR_AAC_MPEG4_UNSUPPORTED; +#endif + + + /* update codec info */ + m_PSInfoBase->sampRateIdx = m_fhADTS.sampRateIdx; + if (!m_PSInfoBase->useImpChanMap) + m_PSInfoBase->nChans = channelMapTab[m_fhADTS.channelConfig]; + + /* syntactic element fields will be read from bitstream for each element */ + m_AACDecInfo->prevBlockID = AAC_ID_INVALID; + m_AACDecInfo->currBlockID = AAC_ID_INVALID; + m_AACDecInfo->currInstTag = -1; + + /* fill in user-accessible data */ + m_AACDecInfo->bitRate = 0; + m_AACDecInfo->nChans = m_PSInfoBase->nChans; + m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; + m_AACDecInfo->id = m_fhADTS.id; + m_AACDecInfo->profile = m_fhADTS.profile; + m_AACDecInfo->sbrEnabled = 0; + m_AACDecInfo->adtsBlocksLeft = m_fhADTS.numRawDataBlocks; + + /* update bitstream reader */ + bitsUsed = CalcBitsUsed(*buf, *bitOffset); + *buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + *bitsAvail -= bitsUsed ; + if (*bitsAvail < 0) + return ERR_AAC_INDATA_UNDERFLOW; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** +* Function: GetADTSChannelMapping +* +* Description: determine the number of channels from implicit mapping rules +* +* Inputs: pointer to start of raw_data_block +* bit offset +* bits available +* +* Outputs: updated number of channels +* +* Return: 0 if successful, error code (< 0) if error +* +* Notes: calculates total number of channels using rules in 14496-3, 4.5.1.2.1 +* does not attempt to deduce speaker geometry +***********************************************************************************************************************/ +int32_t GetADTSChannelMapping(uint8_t *buf, int32_t bitOffset, int32_t bitsAvail) +{ + int32_t ch, nChans, elementChans, err; + + nChans = 0; + do { + /* parse next syntactic element */ + err = DecodeNextElement(&buf, &bitOffset, &bitsAvail); + if (err) + return err; + + elementChans = elementNumChans[m_AACDecInfo->currBlockID]; + nChans += elementChans; + + for (ch = 0; ch < elementChans; ch++) { + err = DecodeNoiselessData(&buf, &bitOffset, &bitsAvail, ch); + if (err) + return err; + } + } while (m_AACDecInfo->currBlockID != AAC_ID_END); + + if (nChans <= 0) + return ERR_AAC_CHANNEL_MAP; + + /* update number of channels in codec state and user-accessible info structs */ + m_PSInfoBase->nChans = nChans; + m_AACDecInfo->nChans = m_PSInfoBase->nChans; + m_PSInfoBase->useImpChanMap = 1; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** +* Function: GetNumChannelsADIF +* +* Description: get number of channels from program config elements in an ADIF file +* +* Inputs: array of filled-in program config element structures +* number of PCE's +* +* Outputs: none +* +* Return: total number of channels in file +* -1 if error (invalid number of PCE's or unsupported mode) +***********************************************************************************************************************/ +int32_t GetNumChannelsADIF(int32_t nPCE) +{ + int32_t i, j, nChans; + + if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF) + return -1; + + nChans = 0; + for (i = 0; i < nPCE; i++) { + /* for now: only support LC, no channel coupling */ + if (m_pce[i]->profile != AAC_PROFILE_LC || m_pce[i]->numCCE > 0) + return -1; + + /* add up number of channels in all channel elements (assume all single-channel) */ + nChans += m_pce[i]->numFCE; + nChans += m_pce[i]->numSCE; + nChans += m_pce[i]->numBCE; + nChans += m_pce[i]->numLCE; + + /* add one more for every element which is a channel pair */ + for (j = 0; j < m_pce[i]->numFCE; j++) { + if ((m_pce[i]->fce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ + nChans++; + } + for (j = 0; j < m_pce[i]->numSCE; j++) { + if ((m_pce[i]->sce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ + nChans++; + } + for (j = 0; j < m_pce[i]->numBCE; j++) { + if ((m_pce[i]->bce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ + nChans++; + } + + } + + return nChans; +} + +/*********************************************************************************************************************** +* Function: GetSampleRateIdxADIF +* +* Description: get sampling rate index from program config elements in an ADIF file +* +* Inputs: array of filled-in program config element structures +* number of PCE's +* +* Outputs: none +* +* Return: sample rate of file +* -1 if error (invalid number of PCE's or sample rate mismatch) +***********************************************************************************************************************/ +int32_t GetSampleRateIdxADIF(int32_t nPCE) +{ + int32_t i, idx; + + if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF) + return -1; + + /* make sure all PCE's have the same sample rate */ + idx = m_pce[0]->sampRateIdx; + for (i = 1; i < nPCE; i++) { + if (m_pce[i]->sampRateIdx != idx) + return -1; + } + + return idx; +} + +/*********************************************************************************************************************** +* Function: UnpackADIFHeader +* +* Description: parse the ADIF file header and initialize decoder state +* +* Inputs: double pointer to buffer with complete ADIF header +* (starting at 'A' in 'ADIF' tag) +* pointer to bit offset +* pointer to number of valid bits remaining in inbuf +* +* Outputs: filled-in ADIF struct +* updated buffer pointer +* updated bit offset +* updated number of available bits +* +* Return: 0 if successful, error code (< 0) if error +***********************************************************************************************************************/ +int32_t UnpackADIFHeader(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail) +{ + uint8_t i; + int32_t bitsUsed; + + /* init bitstream reader */ + SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); + GetBits(*bitOffset); + + /* verify that first 32 bits of header are "ADIF" */ + if (GetBits(8) != 'A' || GetBits(8) != 'D' || GetBits(8) != 'I' || GetBits(8) != 'F') + return ERR_AAC_INVALID_ADIF_HEADER; + + /* read ADIF header fields */ + m_fhADIF.copyBit = GetBits(1); + if (m_fhADIF.copyBit) { + for (i = 0; i < ADIF_COPYID_SIZE; i++) + m_fhADIF.copyID[i] = GetBits(8); + } + m_fhADIF.origCopy = GetBits(1); + m_fhADIF.home = GetBits(1); + m_fhADIF.bsType = GetBits(1); + m_fhADIF.bitRate = GetBits(23); + m_fhADIF.numPCE = GetBits(4) + 1; /* add 1 (so range = [1, 16]) */ + if (m_fhADIF.bsType == 0) + m_fhADIF.bufferFull = GetBits(20); + + /* parse all program config elements */ + for (i = 0; i < m_fhADIF.numPCE; i++) + DecodeProgramConfigElement(i); + + /* byte align */ + ByteAlignBitstream(); + + /* update codec info */ + m_PSInfoBase->nChans = GetNumChannelsADIF(m_fhADIF.numPCE); + m_PSInfoBase->sampRateIdx = GetSampleRateIdxADIF(m_fhADIF.numPCE); + + /* check validity of header */ + if (m_PSInfoBase->nChans < 0 || m_PSInfoBase->sampRateIdx < 0 || m_PSInfoBase->sampRateIdx >= NUM_SAMPLE_RATES) + return ERR_AAC_INVALID_ADIF_HEADER; + + /* syntactic element fields will be read from bitstream for each element */ + m_AACDecInfo->prevBlockID = AAC_ID_INVALID; + m_AACDecInfo->currBlockID = AAC_ID_INVALID; + m_AACDecInfo->currInstTag = -1; + + /* fill in user-accessible data */ + m_AACDecInfo->bitRate = 0; + m_AACDecInfo->nChans = m_PSInfoBase->nChans; + m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; + m_AACDecInfo->profile = m_pce[0]->profile; + m_AACDecInfo->sbrEnabled = 0; + + /* update bitstream reader */ + bitsUsed = CalcBitsUsed(*buf, *bitOffset); + *buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + *bitsAvail -= bitsUsed ; + if (*bitsAvail < 0) + return ERR_AAC_INDATA_UNDERFLOW; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** +* Function: SetRawBlockParams +* +* Description: set internal state variables for decoding a stream of raw data blocks +* +* Inputs: flag indicating source of parameters (from previous headers or passed +* explicitly by caller) +* number of channels +* sample rate +* profile ID +* +* Outputs: updated state variables in aacDecInfo +* +* Return: 0 if successful, error code (< 0) if error +* +* Notes: if copyLast == 1, then m_PSInfoBase->nChans, m_PSInfoBase->sampRateIdx, and +* aacDecInfo->profile are not changed (it's assumed that we already +* set them, such as by a previous call to UnpackADTSHeader()) +* if copyLast == 0, then the parameters we passed in are used instead +***********************************************************************************************************************/ +int32_t SetRawBlockParams(int32_t copyLast, int32_t nChans, int32_t sampRate, int32_t profile) +{ + int32_t idx; + + if (!copyLast) { + m_AACDecInfo->profile = profile; + m_PSInfoBase->nChans = nChans; + for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) { + if (sampRate == sampRateTab[idx]) { + m_PSInfoBase->sampRateIdx = idx; + break; + } + } + if (idx == NUM_SAMPLE_RATES) + return ERR_AAC_INVALID_FRAME; + } + m_AACDecInfo->nChans = m_PSInfoBase->nChans; + m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; + + /* check validity of header */ + if (m_PSInfoBase->sampRateIdx >= NUM_SAMPLE_RATES || m_PSInfoBase->sampRateIdx < 0 || + m_AACDecInfo->profile != AAC_PROFILE_LC) + return ERR_AAC_RAWBLOCK_PARAMS; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** +* Function: PrepareRawBlock +* +* Description: reset per-block state variables for raw blocks (no ADTS/ADIF headers) +* +* Inputs: none +* +* Outputs: updated state variables in aacDecInfo +* +* Return: 0 if successful, error code (< 0) if error +***********************************************************************************************************************/ +int32_t PrepareRawBlock() +{ + /* syntactic element fields will be read from bitstream for each element */ + m_AACDecInfo->prevBlockID = AAC_ID_INVALID; + m_AACDecInfo->currBlockID = AAC_ID_INVALID; + m_AACDecInfo->currInstTag = -1; + + /* fill in user-accessible data */ + m_AACDecInfo->bitRate = 0; + m_AACDecInfo->sbrEnabled = 0; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** + * Function: DequantBlock + * + * Description: dequantize one block of transform coefficients (in-place) + * + * Inputs: quantized transform coefficients, range = [0, 8191] + * number of samples to dequantize + * scalefactor for this block of data, range = [0, 256] + * + * Outputs: dequantized transform coefficients in Q(FBITS_OUT_DQ_OFF) + * + * Return: guard bit mask (OR of abs value of all dequantized coefs) + * + * Notes: applies dequant formula y = pow(x, 4.0/3.0) * pow(2, (scale - 100)/4.0) + * * pow(2, FBITS_OUT_DQ_OFF) + * clips outputs to Q(FBITS_OUT_DQ_OFF) + * output has no minimum number of guard bits + **********************************************************************************************************************/ +int32_t DequantBlock(int32_t *inbuf, int32_t nSamps, int32_t scale) +{ + int32_t iSamp, scalef, scalei, x, y, gbMask, shift, tab4[4]; + const uint32_t *tab16, *coef; + + if (nSamps <= 0) + return 0; + + scale -= SF_OFFSET; /* new range = [-100, 156] */ + + /* with two's complement numbers, scalei/scalef factorization works for pos and neg values of scale: + * [+4...+7] >> 2 = +1, [ 0...+3] >> 2 = 0, [-4...-1] >> 2 = -1, [-8...-5] >> 2 = -2 ... + * (-1 & 0x3) = 3, (-2 & 0x3) = 2, (-3 & 0x3) = 1, (0 & 0x3) = 0 + * + * Example: 2^(-5/4) = 2^(-1) * 2^(-1/4) = 2^-2 * 2^(3/4) + */ + tab16 = pow43_14[scale & 0x3]; + scalef = pow14[scale & 0x3]; + scalei = (scale >> 2) + FBITS_OUT_DQ_OFF; + + /* cache first 4 values: + * tab16[j] = Q28 for j = [0,3] + * tab4[x] = x^(4.0/3.0) * 2^(0.25*scale), Q(FBITS_OUT_DQ_OFF) + */ + shift = 28 - scalei; + if (shift > 31) { + tab4[0] = tab4[1] = tab4[2] = tab4[3] = 0; + } else if (shift <= 0) { + shift = -shift; + if (shift > 31) + shift = 31; + for (x = 0; x < 4; x++) { + y = tab16[x]; + if (y > (0x7fffffff >> shift)) + y = 0x7fffffff; /* clip (rare) */ + else + y <<= shift; + tab4[x] = y; + } + } else { + tab4[0] = 0; + tab4[1] = tab16[1] >> shift; + tab4[2] = tab16[2] >> shift; + tab4[3] = tab16[3] >> shift; + } + + gbMask = 0; + do { + iSamp = *inbuf; + x = FASTABS(iSamp); + + if (x < 4) { + y = tab4[x]; + } else { + + if (x < 16) { + /* result: y = Q25 (tab16 = Q25) */ + y = tab16[x]; + shift = 25 - scalei; + } else if (x < 64) { + /* result: y = Q21 (pow43tab[j] = Q23, scalef = Q30) */ + y = pow43[x-16]; + shift = 21 - scalei; + y = MULSHIFT32(y, scalef); + } else { + /* normalize to [0x40000000, 0x7fffffff] + * input x = [64, 8191] = [64, 2^13-1] + * ranges: + * shift = 7: 64 - 127 + * shift = 6: 128 - 255 + * shift = 5: 256 - 511 + * shift = 4: 512 - 1023 + * shift = 3: 1024 - 2047 + * shift = 2: 2048 - 4095 + * shift = 1: 4096 - 8191 + */ + x <<= 17; + shift = 0; + if (x < 0x08000000) + x <<= 4, shift += 4; + if (x < 0x20000000) + x <<= 2, shift += 2; + if (x < 0x40000000) + x <<= 1, shift += 1; + + coef = (x < SQRTHALF) ? poly43lo : poly43hi; + + /* polynomial */ + y = coef[0]; + y = MULSHIFT32(y, x) + coef[1]; + y = MULSHIFT32(y, x) + coef[2]; + y = MULSHIFT32(y, x) + coef[3]; + y = MULSHIFT32(y, x) + coef[4]; + y = MULSHIFT32(y, pow2frac[shift]) << 3; + + /* fractional scale + * result: y = Q21 (pow43tab[j] = Q23, scalef = Q30) + */ + y = MULSHIFT32(y, scalef); /* now y is Q24 */ + shift = 24 - scalei - pow2exp[shift]; + } + + /* integer scale */ + if (shift <= 0) { + shift = -shift; + if (shift > 31) + shift = 31; + + if (y > (0x7fffffff >> shift)) + y = 0x7fffffff; /* clip (rare) */ + else + y <<= shift; + } else { + if (shift > 31) + shift = 31; + y >>= shift; + } + } + + /* sign and store (gbMask used to count GB's) */ + gbMask |= y; + + /* apply sign */ + iSamp >>= 31; + y ^= iSamp; + y -= iSamp; + + *inbuf++ = y; + } while (--nSamps); + + return gbMask; +} + +/*********************************************************************************************************************** + * Function: AACDequantize + * + * Description: dequantize all transform coefficients for one channel + * + * Inputs: index of current channel + * + * Outputs: dequantized coefficients, including short-block deinterleaving + * flags indicating if intensity and/or PNS is active + * minimum guard bit count for dequantized coefficients + * + * Return: 0 if successful, error code (< 0) if error + **********************************************************************************************************************/ +int32_t AACDequantize(int32_t ch) +{ + int32_t gp, cb, sfb, win, width, nSamps, gbMask; + int32_t *coef; + const uint16_t *sfbTab; + uint8_t *sfbCodeBook; + int16_t *scaleFactors; + ICSInfo_t *icsInfo; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + if (icsInfo->winSequence == 2) { + sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_SHORT; + } else { + sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_LONG; + } + coef = m_PSInfoBase->coef[ch]; + sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; + scaleFactors = m_PSInfoBase->scaleFactors[ch]; + + m_PSInfoBase->intensityUsed[ch] = 0; + m_PSInfoBase->pnsUsed[ch] = 0; + gbMask = 0; + for (gp = 0; gp < icsInfo->numWinGroup; gp++) { + for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { + for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { + /* dequantize one scalefactor band (not necessary if codebook is intensity or PNS) + * for zero codebook, still run dequantizer in case non-zero pulse data was added + */ + cb = (int32_t)(sfbCodeBook[sfb]); + width = sfbTab[sfb+1] - sfbTab[sfb]; + if (cb >= 0 && cb <= 11) + gbMask |= DequantBlock(coef, width, scaleFactors[sfb]); + else if (cb == 13) + m_PSInfoBase->pnsUsed[ch] = 1; + else if (cb == 14 || cb == 15) + m_PSInfoBase->intensityUsed[ch] = 1; /* should only happen if ch == 1 */ + coef += width; + } + coef += (nSamps - sfbTab[icsInfo->maxSFB]); + } + sfbCodeBook += icsInfo->maxSFB; + scaleFactors += icsInfo->maxSFB; + } + m_AACDecInfo->pnsUsed |= m_PSInfoBase->pnsUsed[ch]; /* set flag if PNS used for any channel */ + + /* calculate number of guard bits in dequantized data */ + m_PSInfoBase->gbCurrent[ch] = CLZ(gbMask) - 1; + + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** + * Function: DeinterleaveShortBlocks + * + * Description: deinterleave transform coefficients in short blocks for one channel + * + * Inputs: index of current channel + * + * Outputs: deinterleaved coefficients (window groups into 8 separate windows) + * + * Return: 0 if successful, error code (< 0) if error + * + * Notes: only necessary if deinterleaving not part of Huffman decoding + **********************************************************************************************************************/ +int32_t DeinterleaveShortBlocks(int32_t ch) +{ +// (void)aacDecInfo; +// (void)ch; + /* not used for this implementation - short block deinterleaving performed during Huffman decoding */ + return ERR_AAC_NONE; +} + +/*********************************************************************************************************************** + * Function: Get32BitVal + * + * Description: generate 32-bit unsigned random number + * + * Inputs: last number calculated (seed, first time through) + * + * Outputs: new number, saved in *last + * + * Return: 32-bit number, uniformly distributed between [0, 2^32) + * + * Notes: uses simple linear congruential generator + **********************************************************************************************************************/ +uint32_t Get32BitVal(uint32_t *last) +{ + uint32_t r = *last; + + /* use same coefs as MPEG reference code (classic LCG) + * use unsigned multiply to force reliable wraparound behavior in C (mod 2^32) + */ + r = (1664525U * r) + 1013904223U; + *last = r; + + return r; +} + +/*********************************************************************************************************************** + * Function: InvRootR + * + * Description: use Newton's method to solve for x = 1/sqrt(r) + * + * Inputs: r in Q30 format, range = [0.25, 1] (normalize inputs to this range) + * + * Outputs: none + * + * Return: x = Q29, range = (1, 2) + * + * Notes: guaranteed to converge and not overflow for any r in this range + * + * xn+1 = xn - f(xn)/f'(xn) + * f(x) = 1/sqrt(r) - x = 0 (find root) + * = 1/x^2 - r + * f'(x) = -2/x^3 + * + * so xn+1 = xn/2 * (3 - r*xn^2) + * + * NUM_ITER_INVSQRT = 3, maxDiff = 1.3747e-02 + * NUM_ITER_INVSQRT = 4, maxDiff = 3.9832e-04 + **********************************************************************************************************************/ +int32_t InvRootR(int32_t r) +{ + int32_t i, xn, t; + + /* use linear equation for initial guess + * x0 = -2*r + 3 (so x0 always >= correct answer in range [0.25, 1)) + * xn = Q29 (at every step) + */ + xn = (MULSHIFT32(r, X0_COEF_2) << 2) + X0_OFF_2; + + for (i = 0; i < NUM_ITER_INVSQRT; i++) { + t = MULSHIFT32(xn, xn); /* Q26 = Q29*Q29 */ + t = Q26_3 - (MULSHIFT32(r, t) << 2); /* Q26 = Q26 - (Q31*Q26 << 1) */ + xn = MULSHIFT32(xn, t) << (6 - 1); /* Q29 = (Q29*Q26 << 6), and -1 for division by 2 */ + } + + /* clip to range (1.0, 2.0) + * (because of rounding, this can converge to xn slightly > 2.0 when r is near 0.25) + */ + if (xn >> 30) + xn = (1 << 30) - 1; + + return xn; +} + +/*********************************************************************************************************************** + * Function: ScaleNoiseVector + * + * Description: apply scaling to vector of noise coefficients for one scalefactor band + * + * Inputs: unscaled coefficients + * number of coefficients in vector (one scalefactor band of coefs) + * scalefactor for this band (i.e. noise energy) + * + * Outputs: nVals coefficients in Q(FBITS_OUT_DQ_OFF) + * + * Return: guard bit mask (OR of abs value of all noise coefs) + **********************************************************************************************************************/ +int32_t ScaleNoiseVector(int32_t *coef, int32_t nVals, int32_t sf) +{ + +/* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */ +static const int32_t pow14[4] PROGMEM = { + 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 +}; + + int32_t i, c, spec, energy, sq, scalef, scalei, invSqrtEnergy, z, gbMask; + + energy = 0; + for (i = 0; i < nVals; i++) { + spec = coef[i]; + + /* max nVals = max SFB width = 96, so energy can gain < 2^7 bits in accumulation */ + sq = (spec * spec) >> 8; /* spec*spec range = (-2^30, 2^30) */ + energy += sq; + } + + /* unless nVals == 1 (or the number generator is broken...), this should not happen */ + if (energy == 0) + return 0; /* coef[i] must = 0 for i = [0, nVals-1], so gbMask = 0 */ + + /* pow(2, sf/4) * pow(2, FBITS_OUT_DQ_OFF) */ + scalef = pow14[sf & 0x3]; + scalei = (sf >> 2) + FBITS_OUT_DQ_OFF; + + /* energy has implied factor of 2^-8 since we shifted the accumulator + * normalize energy to range [0.25, 1.0), calculate 1/sqrt(1), and denormalize + * i.e. divide input by 2^(30-z) and convert to Q30 + * output of 1/sqrt(i) now has extra factor of 2^((30-z)/2) + * for energy > 0, z is an even number between 0 and 28 + * final scaling of invSqrtEnergy: + * 2^(15 - z/2) to compensate for implicit 2^(30-z) factor in input + * +4 to compensate for implicit 2^-8 factor in input + */ + z = CLZ(energy) - 2; /* energy has at least 2 leading zeros (see acc loop) */ + z &= 0xfffffffe; /* force even */ + invSqrtEnergy = InvRootR(energy << z); /* energy << z must be in range [0x10000000, 0x40000000] */ + scalei -= (15 - z/2 + 4); /* nInt = 1/sqrt(energy) in Q29 */ + + /* normalize for final scaling */ + z = CLZ(invSqrtEnergy) - 1; + invSqrtEnergy <<= z; + scalei -= (z - 3 - 2); /* -2 for scalef, z-3 for invSqrtEnergy */ + scalef = MULSHIFT32(scalef, invSqrtEnergy); /* scalef (input) = Q30, invSqrtEnergy = Q29 * 2^z */ + gbMask = 0; + + if (scalei < 0) { + scalei = -scalei; + if (scalei > 31) + scalei = 31; + for (i = 0; i < nVals; i++) { + c = MULSHIFT32(coef[i], scalef) >> scalei; + gbMask |= FASTABS(c); + coef[i] = c; + } + } else { + /* for scalei <= 16, no clipping possible (coef[i] is < 2^15 before scaling) + * for scalei > 16, just saturate exponent (rare) + * scalef is close to full-scale (since we normalized invSqrtEnergy) + * remember, we are just producing noise here + */ + if (scalei > 16) + scalei = 16; + for (i = 0; i < nVals; i++) { + c = MULSHIFT32(coef[i] << scalei, scalef); + coef[i] = c; + gbMask |= FASTABS(c); + } + } + + return gbMask; +} + +/*********************************************************************************************************************** + * Function: GenerateNoiseVector + * + * Description: create vector of noise coefficients for one scalefactor band + * + * Inputs: seed for number generator + * number of coefficients to generate + * + * Outputs: buffer of nVals coefficients, range = [-2^15, 2^15) + * updated seed for number generator + * + * Return: none + **********************************************************************************************************************/ +void GenerateNoiseVector(int32_t *coef, int32_t *last, int32_t nVals) +{ + int32_t i; + + for (i = 0; i < nVals; i++) + coef[i] = ((int32_t)Get32BitVal((uint32_t *)last)) >> 16; +} + +/*********************************************************************************************************************** + * Function: CopyNoiseVector + * + * Description: copy vector of noise coefficients for one scalefactor band from L to R + * + * Inputs: buffer of left coefficients + * number of coefficients to copy + * + * Outputs: buffer of right coefficients + * + * Return: none + **********************************************************************************************************************/ +void CopyNoiseVector(int32_t *coefL, int32_t *coefR, int32_t nVals) +{ + int32_t i; + + for (i = 0; i < nVals; i++) + coefR[i] = coefL[i]; +} + +/*********************************************************************************************************************** + * Function: PNS + * + * Description: apply perceptual noise substitution, if enabled (MPEG-4 only) + * + * Inputs: index of current channel + * + * Outputs: shaped noise in scalefactor bands where PNS is active + * updated minimum guard bit count for this channel + * + * Return: 0 if successful, -1 if error + **********************************************************************************************************************/ +int32_t PNS(int32_t ch) +{ + int32_t gp, sfb, win, width, nSamps, gb, gbMask; + int32_t *coef; + const uint16_t *sfbTab; + uint8_t *sfbCodeBook; + int16_t *scaleFactors; + int32_t msMaskOffset, checkCorr, genNew; + uint8_t msMask; + uint8_t *msMaskPtr; + ICSInfo_t *icsInfo; + + icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); + + if (!m_PSInfoBase->pnsUsed[ch]) + return 0; + + if (icsInfo->winSequence == 2) { + sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_SHORT; + } else { + sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_LONG; + } + coef = m_PSInfoBase->coef[ch]; + sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; + scaleFactors = m_PSInfoBase->scaleFactors[ch]; + checkCorr = (m_AACDecInfo->currBlockID == AAC_ID_CPE && m_PSInfoBase->commonWin == 1 ? 1 : 0); + + gbMask = 0; + for (gp = 0; gp < icsInfo->numWinGroup; gp++) { + for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { + msMaskPtr = m_PSInfoBase->msMaskBits + ((gp*icsInfo->maxSFB) >> 3); + msMaskOffset = ((gp*icsInfo->maxSFB) & 0x07); + msMask = (*msMaskPtr++) >> msMaskOffset; + + for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { + width = sfbTab[sfb+1] - sfbTab[sfb]; + if (sfbCodeBook[sfb] == 13) { + if (ch == 0) { + /* generate new vector, copy into ch 1 if it's possible that the channels will be correlated + * if ch 1 has PNS enabled for this SFB but it's uncorrelated (i.e. ms_used == 0), + * the copied values will be overwritten when we process ch 1 + */ + GenerateNoiseVector(coef, &m_PSInfoBase->pnsLastVal, width); + if (checkCorr && m_PSInfoBase->sfbCodeBook[1][gp*icsInfo->maxSFB + sfb] == 13) + CopyNoiseVector(coef, m_PSInfoBase->coef[1] + (coef - m_PSInfoBase->coef[0]), width); + } else { + /* generate new vector if no correlation between channels */ + genNew = 1; + if (checkCorr && m_PSInfoBase->sfbCodeBook[0][gp*icsInfo->maxSFB + sfb] == 13) { + if((m_PSInfoBase->msMaskPresent==1 && (msMask & 0x01)) || m_PSInfoBase->msMaskPresent == 2 ) + genNew = 0; + } + if (genNew) + GenerateNoiseVector(coef, &m_PSInfoBase->pnsLastVal, width); + } + gbMask |= ScaleNoiseVector(coef, width, m_PSInfoBase->scaleFactors[ch][gp*icsInfo->maxSFB + sfb]); + } + coef += width; + + /* get next mask bit (should be branchless on ARM) */ + msMask >>= 1; + if (++msMaskOffset == 8) { + msMask = *msMaskPtr++; + msMaskOffset = 0; + } + } + coef += (nSamps - sfbTab[icsInfo->maxSFB]); + } + sfbCodeBook += icsInfo->maxSFB; + scaleFactors += icsInfo->maxSFB; + } + + /* update guard bit count if necessary */ + gb = CLZ(gbMask) - 1; + if (m_PSInfoBase->gbCurrent[ch] > gb) + m_PSInfoBase->gbCurrent[ch] = gb; + + return 0; +} + +/*********************************************************************************************************************** + * Function: GetSampRateIdx + * + * Description: get index of given sample rate + * + * Inputs: sample rate (in Hz) + * + * Outputs: none + * + * Return: index of sample rate (table 1.15 in 14496-3:2001(E)) + * -1 if sample rate not found in table + **********************************************************************************************************************/ +int32_t GetSampRateIdx(int32_t sampRate) +{ + int32_t idx; + + for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) { + if (sampRate == sampRateTab[idx]) + return idx; + } + + return -1; +} + +/*********************************************************************************************************************** + * Function: StereoProcessGroup + * + * Description: apply mid-side and intensity stereo to group of transform coefficients + * + * Inputs: dequantized transform coefficients for both channels + * pointer to appropriate scalefactor band table + * mid-side mask enabled flag + * buffer with mid-side mask (one bit for each scalefactor band) + * bit offset into mid-side mask buffer + * max coded scalefactor band + * buffer of codebook indices for right channel + * buffer of scalefactors for right channel, range = [0, 256] + * + * Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF) + * updated minimum guard bit count for both channels + * + * Return: none + * + * Notes: assume no guard bits in input + * gains 0 int32_t bits + **********************************************************************************************************************/ +void StereoProcessGroup(int32_t *coefL, int32_t *coefR, const uint16_t *sfbTab, + int32_t msMaskPres, uint8_t *msMaskPtr, int32_t msMaskOffset, int32_t maxSFB, + uint8_t *cbRight, int16_t *sfRight, int32_t *gbCurrent) +{ +//fb +static const uint32_t pow14[2][4] PROGMEM = { + { 0xc0000000, 0xb3e407d7, 0xa57d8666, 0x945d819b }, + { 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 } +}; + + int32_t sfb, width, cbIdx, sf, cl, cr, scalef, scalei; + int32_t gbMaskL, gbMaskR; + uint8_t msMask; + + msMask = (*msMaskPtr++) >> msMaskOffset; + gbMaskL = 0; + gbMaskR = 0; + + for (sfb = 0; sfb < maxSFB; sfb++) { + width = sfbTab[sfb+1] - sfbTab[sfb]; /* assume >= 0 (see sfBandTabLong/sfBandTabShort) */ + cbIdx = cbRight[sfb]; + + if (cbIdx == 14 || cbIdx == 15) { + /* intensity stereo */ + if (msMaskPres == 1 && (msMask & 0x01)) + cbIdx ^= 0x01; /* invert_intensity(): 14 becomes 15, or 15 becomes 14 */ + sf = -sfRight[sfb]; /* negative since we use identity 0.5^(x) = 2^(-x) (see spec) */ + cbIdx &= 0x01; /* choose - or + scale factor */ + scalef = pow14[cbIdx][sf & 0x03]; + scalei = (sf >> 2) + 2; /* +2 to compensate for scalef = Q30 */ + + if (scalei > 0) { + if (scalei > 30) + scalei = 30; + do { + cr = MULSHIFT32(*coefL++, scalef); + {int32_t sign = (cr) >> 31; if (sign != (cr) >> (31-scalei)) {(cr) = sign ^ ((1 << (31-scalei)) - 1);}} + cr <<= scalei; + gbMaskR |= FASTABS(cr); + *coefR++ = cr; + } while (--width); + } else { + scalei = -scalei; + if (scalei > 31) + scalei = 31; + do { + cr = MULSHIFT32(*coefL++, scalef) >> scalei; + gbMaskR |= FASTABS(cr); + *coefR++ = cr; + } while (--width); + } + } else if ( cbIdx != 13 && ((msMaskPres == 1 && (msMask & 0x01)) || msMaskPres == 2) ) { + /* mid-side stereo (assumes no GB in inputs) */ + do { + cl = *coefL; + cr = *coefR; + + if ( (FASTABS(cl) | FASTABS(cr)) >> 30 ) { + /* avoid overflow (rare) */ + cl >>= 1; + sf = cl + (cr >> 1); + {int32_t sign = (sf) >> 31; if (sign != (sf) >> (30)) {(sf) = sign ^ ((1 << (30)) - 1);}} + sf <<= 1; + cl = cl - (cr >> 1); + {int32_t sign = (cl) >> 31; if (sign != (cl) >> (30)) {(cl) = sign ^ ((1 << (30)) - 1);}} + cl <<= 1; + } else { + /* usual case */ + sf = cl + cr; + cl -= cr; + } + + *coefL++ = sf; + gbMaskL |= FASTABS(sf); + *coefR++ = cl; + gbMaskR |= FASTABS(cl); + } while (--width); + + } else { + /* nothing to do */ + coefL += width; + coefR += width; + } + + /* get next mask bit (should be branchless on ARM) */ + msMask >>= 1; + if (++msMaskOffset == 8) { + msMask = *msMaskPtr++; + msMaskOffset = 0; + } + } + + cl = CLZ(gbMaskL) - 1; + if (gbCurrent[0] > cl) + gbCurrent[0] = cl; + + cr = CLZ(gbMaskR) - 1; + if (gbCurrent[1] > cr) + gbCurrent[1] = cr; + + return; +} + +/*********************************************************************************************************************** + * Function: StereoProcess + * + * Description: apply mid-side and intensity stereo, if enabled + * + * Inputs: none + * + * Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF) + * updated minimum guard bit count for both channels + * + * Return: 0 if successful, -1 if error + **********************************************************************************************************************/ +int32_t StereoProcess() +{ + ICSInfo_t *icsInfo; + int32_t gp, win, nSamps, msMaskOffset; + int32_t *coefL, *coefR; + uint8_t *msMaskPtr; + const uint16_t *sfbTab; + + + /* mid-side and intensity stereo require common_window == 1 (see MPEG4 spec, Correction 2, 2004) */ + if (m_PSInfoBase->commonWin != 1 || m_AACDecInfo->currBlockID != AAC_ID_CPE) + return 0; + + /* nothing to do */ + if (!m_PSInfoBase->msMaskPresent && !m_PSInfoBase->intensityUsed[1]) + return 0; + + icsInfo = &(m_PSInfoBase->icsInfo[0]); + if (icsInfo->winSequence == 2) { + sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_SHORT; + } else { + sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; + nSamps = NSAMPS_LONG; + } + coefL = m_PSInfoBase->coef[0]; + coefR = m_PSInfoBase->coef[1]; + + /* do fused mid-side/intensity processing for each block (one long or eight short) */ + msMaskOffset = 0; + msMaskPtr = m_PSInfoBase->msMaskBits; + for (gp = 0; gp < icsInfo->numWinGroup; gp++) { + for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { + StereoProcessGroup(coefL, coefR, sfbTab, m_PSInfoBase->msMaskPresent, + msMaskPtr, msMaskOffset, icsInfo->maxSFB, m_PSInfoBase->sfbCodeBook[1] + gp*icsInfo->maxSFB, + m_PSInfoBase->scaleFactors[1] + gp*icsInfo->maxSFB, m_PSInfoBase->gbCurrent); + coefL += nSamps; + coefR += nSamps; + } + /* we use one bit per sfb, so there are maxSFB bits for each window group */ + msMaskPtr += (msMaskOffset + icsInfo->maxSFB) >> 3; + msMaskOffset = (msMaskOffset + icsInfo->maxSFB) & 0x07; + } + + ASSERT(coefL == m_PSInfoBase->coef[0] + 1024); + ASSERT(coefR == m_PSInfoBase->coef[1] + 1024); + + return 0; +} + +/*********************************************************************************************************************** + * Function: RatioPowInv + * + * Description: use Taylor (MacLaurin) series expansion to calculate (a/b) ^ (1/c) + * + * Inputs: a = [1, 64], b = [1, 64], c = [1, 64], a >= b + * + * Outputs: none + * + * Return: y = Q24, range ~= [0.015625, 64] + **********************************************************************************************************************/ +int32_t RatioPowInv(int32_t a, int32_t b, int32_t c) +{ + int32_t lna, lnb, i, p, t, y; + + if (a < 1 || b < 1 || c < 1 || a > 64 || b > 64 || c > 64 || a < b) + return 0; + + lna = MULSHIFT32(log2Tab[a], LOG2_EXP_INV) << 1; /* ln(a), Q28 */ + lnb = MULSHIFT32(log2Tab[b], LOG2_EXP_INV) << 1; /* ln(b), Q28 */ + p = (lna - lnb) / c; /* Q28 */ + + /* sum in Q24 */ + y = (1 << 24); + t = p >> 4; /* t = p^1 * 1/1! (Q24)*/ + y += t; + + for (i = 2; i <= NUM_TERMS_RPI; i++) { + t = MULSHIFT32(invTab[i-1], t) << 2; + t = MULSHIFT32(p, t) << 4; /* t = p^i * 1/i! (Q24) */ + y += t; + } + + return y; +} + +/*********************************************************************************************************************** + * Function: SqrtFix + * + * Description: use binary search to calculate sqrt(q) + * + * Inputs: q = Q30 + * number of fraction bits in input + * + * Outputs: number of fraction bits in output + * + * Return: lo = Q(fBitsOut) + * + * Notes: absolute precision varies depending on fBitsIn + * normalizes input to range [0x200000000, 0x7fffffff] and takes + * floor(sqrt(input)), and sets fBitsOut appropriately + **********************************************************************************************************************/ +int32_t SqrtFix(int32_t q, int32_t fBitsIn, int32_t *fBitsOut) +{ + int32_t z, lo, hi, mid; + + if (q <= 0) { + *fBitsOut = fBitsIn; + return 0; + } + + /* force even fBitsIn */ + z = fBitsIn & 0x01; + q >>= z; + fBitsIn -= z; + + /* for max precision, normalize to [0x20000000, 0x7fffffff] */ + z = (CLZ(q) - 1); + z >>= 1; + q <<= (2*z); + + /* choose initial bounds */ + lo = 1; + if (q >= 0x10000000) + lo = 16384; /* (int32_t)sqrt(0x10000000) */ + hi = 46340; /* (int32_t)sqrt(0x7fffffff) */ + + /* do binary search with 32x32->32 multiply test */ + do { + mid = (lo + hi) >> 1; + if (mid*mid > q) + hi = mid - 1; + else + lo = mid + 1; + } while (hi >= lo); + lo--; + + *fBitsOut = ((fBitsIn + 2*z) >> 1); + return lo; +} + +/*********************************************************************************************************************** + * Function: InvRNormalized + * + * Description: use Newton's method to solve for x = 1/r + * + * Inputs: r = Q31, range = [0.5, 1) (normalize your inputs to this range) + * + * Outputs: none + * + * Return: x = Q29, range ~= [1.0, 2.0] + * + * Notes: guaranteed to converge and not overflow for any r in [0.5, 1) + * + * xn+1 = xn - f(xn)/f'(xn) + * f(x) = 1/r - x = 0 (find root) + * = 1/x - r + * f'(x) = -1/x^2 + * + * so xn+1 = xn - (1/xn - r) / (-1/xn^2) + * = xn * (2 - r*xn) + * + * NUM_ITER_IRN = 2, maxDiff = 6.2500e-02 (precision of about 4 bits) + * NUM_ITER_IRN = 3, maxDiff = 3.9063e-03 (precision of about 8 bits) + * NUM_ITER_IRN = 4, maxDiff = 1.5288e-05 (precision of about 16 bits) + * NUM_ITER_IRN = 5, maxDiff = 3.0034e-08 (precision of about 24 bits) + **********************************************************************************************************************/ +int32_t InvRNormalized(int32_t r) +{ + int32_t i, xn, t; + + /* r = [0.5, 1.0) + * 1/r = (1.0, 2.0] + * so use 1.5 as initial guess + */ + xn = Q28_15; + + /* xn = xn*(2.0 - r*xn) */ + for (i = NUM_ITER_IRN; i != 0; i--) { + t = MULSHIFT32(r, xn); /* Q31*Q29 = Q28 */ + t = Q28_2 - t; /* Q28 */ + xn = MULSHIFT32(xn, t) << 4; /* Q29*Q28 << 4 = Q29 */ + } + + return xn; +} + + + +/*********************************************************************************************************************** + * Function: BitReverse32 + * + * Description: Ken's fast in-place bit reverse + * + * Inputs: buffer of 32 complex samples + * + * Outputs: bit-reversed samples in same buffer + * + * Return: none +***********************************************************************************************************************/ +void BitReverse32(int32_t *inout) +{ + int32_t t; + t=inout[2] ; inout[2]=inout[32]; inout[32]=t; + t=inout[3] ; inout[3]=inout[33]; inout[33]=t; + + t=inout[4] ; inout[4]=inout[16]; inout[16]=t; + t=inout[5] ; inout[5]=inout[17]; inout[17]=t; + + t=inout[6] ; inout[6]=inout[48]; inout[48]=t; + t=inout[7] ; inout[7]=inout[49]; inout[49]=t; + + t=inout[10]; inout[10]=inout[40]; inout[40]=t; + t=inout[11]; inout[11]=inout[41]; inout[41]=t; + + t=inout[12]; inout[12]=inout[24]; inout[24]=t; + t=inout[13]; inout[13]=inout[25]; inout[25]=t; + + t=inout[14]; inout[14]=inout[56]; inout[56]=t; + t=inout[15]; inout[15]=inout[57]; inout[57]=t; + + t=inout[18]; inout[18]=inout[36]; inout[36]=t; + t=inout[19]; inout[19]=inout[37]; inout[37]=t; + + t=inout[22]; inout[22]=inout[52]; inout[52]=t; + t=inout[23]; inout[23]=inout[53]; inout[53]=t; + + t=inout[26]; inout[26]=inout[44]; inout[44]=t; + t=inout[27]; inout[27]=inout[45]; inout[45]=t; + + t=inout[30]; inout[30]=inout[60]; inout[60]=t; + t=inout[31]; inout[31]=inout[61]; inout[61]=t; + + t=inout[38]; inout[38]=inout[50]; inout[50]=t; + t=inout[39]; inout[39]=inout[51]; inout[51]=t; + + t=inout[46]; inout[46]=inout[58]; inout[58]=t; + t=inout[47]; inout[47]=inout[59]; inout[59]=t; + +} + +/*********************************************************************************************************************** + * Function: R8FirstPass32 + * + * Description: radix-8 trivial pass for decimation-in-time FFT (log2(N) = 5) + * + * Inputs: buffer of (bit-reversed) samples + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: assumes 3 guard bits, gains 1 integer bit + * guard bits out = guard bits in - 3 (if inputs are full scale) + * or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2) + * see scaling comments in fft.c for base AAC + * should compile with no stack spills on ARM (verify compiled output) + * current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU + **********************************************************************************************************************/ +void R8FirstPass32(int32_t *r0) +{ + int32_t r1, r2, r3, r4, r5, r6, r7; + int32_t r8, r9, r10, r11, r12, r14; + + /* number of passes = fft size / 8 = 32 / 8 = 4 */ + r1 = (32 >> 3); + do { + + r2 = r0[8]; + r3 = r0[9]; + r4 = r0[10]; + r5 = r0[11]; + r6 = r0[12]; + r7 = r0[13]; + r8 = r0[14]; + r9 = r0[15]; + + r10 = r2 + r4; + r11 = r3 + r5; + r12 = r6 + r8; + r14 = r7 + r9; + + r2 -= r4; + r3 -= r5; + r6 -= r8; + r7 -= r9; + + r4 = r2 - r7; + r5 = r2 + r7; + r8 = r3 - r6; + r9 = r3 + r6; + + r2 = r4 - r9; + r3 = r4 + r9; + r6 = r5 - r8; + r7 = r5 + r8; + + r2 = MULSHIFT32(SQRTHALF, r2); /* can use r4, r5, r8, or r9 for constant and lo32 scratch reg */ + r3 = MULSHIFT32(SQRTHALF, r3); + r6 = MULSHIFT32(SQRTHALF, r6); + r7 = MULSHIFT32(SQRTHALF, r7); + + r4 = r10 + r12; + r5 = r10 - r12; + r8 = r11 + r14; + r9 = r11 - r14; + + r10 = r0[0]; + r11 = r0[2]; + r12 = r0[4]; + r14 = r0[6]; + + r10 += r11; + r12 += r14; + + r4 >>= 1; + r10 += r12; + r4 += (r10 >> 1); + r0[ 0] = r4; + r4 -= (r10 >> 1); + r4 = (r10 >> 1) - r4; + r0[ 8] = r4; + + r9 >>= 1; + r10 -= 2*r12; + r4 = (r10 >> 1) + r9; + r0[ 4] = r4; + r4 = (r10 >> 1) - r9; + r0[12] = r4; + r10 += r12; + + r10 -= 2*r11; + r12 -= 2*r14; + + r4 = r0[1]; + r9 = r0[3]; + r11 = r0[5]; + r14 = r0[7]; + + r4 += r9; + r11 += r14; + + r8 >>= 1; + r4 += r11; + r8 += (r4 >> 1); + r0[ 1] = r8; + r8 -= (r4 >> 1); + r8 = (r4 >> 1) - r8; + r0[ 9] = r8; + + r5 >>= 1; + r4 -= 2*r11; + r8 = (r4 >> 1) - r5; + r0[ 5] = r8; + r8 = (r4 >> 1) + r5; + r0[13] = r8; + r4 += r11; + + r4 -= 2*r9; + r11 -= 2*r14; + + r9 = r10 - r11; + r10 += r11; + r14 = r4 + r12; + r4 -= r12; + + r5 = (r10 >> 1) + r7; + r8 = (r4 >> 1) - r6; + r0[ 2] = r5; + r0[ 3] = r8; + + r5 = (r9 >> 1) - r2; + r8 = (r14 >> 1) - r3; + r0[ 6] = r5; + r0[ 7] = r8; + + r5 = (r10 >> 1) - r7; + r8 = (r4 >> 1) + r6; + r0[10] = r5; + r0[11] = r8; + + r5 = (r9 >> 1) + r2; + r8 = (r14 >> 1) + r3; + r0[14] = r5; + r0[15] = r8; + + r0 += 16; + r1--; + } while (r1 != 0); +} + +/*********************************************************************************************************************** + * Function: R4Core32 + * + * Description: radix-4 pass for 32-point decimation-in-time FFT + * + * Inputs: buffer of samples + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: gain 2 integer bits + * guard bits out = guard bits in - 1 (if inputs are full scale) + * see scaling comments in fft.c for base AAC + * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add + * should compile with no stack spills on ARM (verify compiled output) + * current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU + **********************************************************************************************************************/ +void R4Core32(int32_t *r0) +{ + int32_t r2, r3, r4, r5, r6, r7; + int32_t r8, r9, r10, r12, r14; + int32_t *r1; + + r1 = (int32_t *)twidTabOdd32; + r10 = 8; + do { + /* can use r14 for lo32 scratch register in all MULSHIFT32 */ + r2 = r1[0]; + r3 = r1[1]; + r4 = r0[16]; + r5 = r0[17]; + r12 = r4 + r5; + r12 = MULSHIFT32(r3, r12); + r5 = MULSHIFT32(r2, r5) + r12; + r2 += 2*r3; + r4 = MULSHIFT32(r2, r4) - r12; + + r2 = r1[2]; + r3 = r1[3]; + r6 = r0[32]; + r7 = r0[33]; + r12 = r6 + r7; + r12 = MULSHIFT32(r3, r12); + r7 = MULSHIFT32(r2, r7) + r12; + r2 += 2*r3; + r6 = MULSHIFT32(r2, r6) - r12; + + r2 = r1[4]; + r3 = r1[5]; + r8 = r0[48]; + r9 = r0[49]; + r12 = r8 + r9; + r12 = MULSHIFT32(r3, r12); + r9 = MULSHIFT32(r2, r9) + r12; + r2 += 2*r3; + r8 = MULSHIFT32(r2, r8) - r12; + + r2 = r0[0]; + r3 = r0[1]; + + r12 = r6 + r8; + r8 = r6 - r8; + r14 = r9 - r7; + r9 = r9 + r7; + + r6 = (r2 >> 2) - r4; + r7 = (r3 >> 2) - r5; + r4 += (r2 >> 2); + r5 += (r3 >> 2); + + r2 = r4 + r12; + r3 = r5 + r9; + r0[0] = r2; + r0[1] = r3; + r2 = r6 - r14; + r3 = r7 - r8; + r0[16] = r2; + r0[17] = r3; + r2 = r4 - r12; + r3 = r5 - r9; + r0[32] = r2; + r0[33] = r3; + r2 = r6 + r14; + r3 = r7 + r8; + r0[48] = r2; + r0[49] = r3; + + r0 += 2; + r1 += 6; + r10--; + } while (r10 != 0); +} + +/*********************************************************************************************************************** + * Function: FFT32C + * + * Description: Ken's very fast in-place radix-4 decimation-in-time FFT + * + * Inputs: buffer of 32 complex samples (before bit-reversal) + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: assumes 3 guard bits in, gains 3 integer bits + * guard bits out = guard bits in - 2 + * (guard bit analysis includes assumptions about steps immediately + * before and after, i.e. PreMul and PostMul for DCT) + **********************************************************************************************************************/ +void FFT32C(int32_t *x) +{ + /* decimation in time */ + BitReverse32(x); + + /* 32-point complex FFT */ + R8FirstPass32(x); /* gain 1 int32_t bit, lose 2 GB (making assumptions about input) */ + R4Core32(x); /* gain 2 int32_t bits, lose 0 GB (making assumptions about input) */ +} + +/*********************************************************************************************************************** + * Function: CVKernel1 + * + * Description: kernel of covariance matrix calculation for p01, p11, p12, p22 + * + * Inputs: buffer of low-freq samples, starting at time index = 0, + * freq index = patch subband + * + * Outputs: 64-bit accumulators for p01re, p01im, p12re, p12im, p11re, p22re + * stored in accBuf + * + * Return: none + * + * Notes: this is carefully written to be efficient on ARM + * use the assembly code version in sbrcov.s when building for ARM! + **********************************************************************************************************************/ +void CVKernel1(int32_t *XBuf, int32_t *accBuf) +{ + U64 p01re, p01im, p12re, p12im, p11re, p22re; + int32_t n, x0re, x0im, x1re, x1im; + + x0re = XBuf[0]; + x0im = XBuf[1]; + XBuf += (2*64); + x1re = XBuf[0]; + x1im = XBuf[1]; + XBuf += (2*64); + + p01re.w64 = p01im.w64 = 0; + p12re.w64 = p12im.w64 = 0; + p11re.w64 = 0; + p22re.w64 = 0; + + p12re.w64 = MADD64(p12re.w64, x1re, x0re); + p12re.w64 = MADD64(p12re.w64, x1im, x0im); + p12im.w64 = MADD64(p12im.w64, x0re, x1im); + p12im.w64 = MADD64(p12im.w64, -x0im, x1re); + p22re.w64 = MADD64(p22re.w64, x0re, x0re); + p22re.w64 = MADD64(p22re.w64, x0im, x0im); + for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) { + /* 4 input, 3*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */ + x0re = x1re; + x0im = x1im; + x1re = XBuf[0]; + x1im = XBuf[1]; + + p01re.w64 = MADD64(p01re.w64, x1re, x0re); + p01re.w64 = MADD64(p01re.w64, x1im, x0im); + p01im.w64 = MADD64(p01im.w64, x0re, x1im); + p01im.w64 = MADD64(p01im.w64, -x0im, x1re); + p11re.w64 = MADD64(p11re.w64, x0re, x0re); + p11re.w64 = MADD64(p11re.w64, x0im, x0im); + + XBuf += (2*64); + } + /* these can be derived by slight changes to account for boundary conditions */ + p12re.w64 += p01re.w64; + p12re.w64 = MADD64(p12re.w64, x1re, -x0re); + p12re.w64 = MADD64(p12re.w64, x1im, -x0im); + p12im.w64 += p01im.w64; + p12im.w64 = MADD64(p12im.w64, x0re, -x1im); + p12im.w64 = MADD64(p12im.w64, x0im, x1re); + p22re.w64 += p11re.w64; + p22re.w64 = MADD64(p22re.w64, x0re, -x0re); + p22re.w64 = MADD64(p22re.w64, x0im, -x0im); + + accBuf[0] = p01re.r.lo32; accBuf[1] = p01re.r.hi32; + accBuf[2] = p01im.r.lo32; accBuf[3] = p01im.r.hi32; + accBuf[4] = p11re.r.lo32; accBuf[5] = p11re.r.hi32; + accBuf[6] = p12re.r.lo32; accBuf[7] = p12re.r.hi32; + accBuf[8] = p12im.r.lo32; accBuf[9] = p12im.r.hi32; + accBuf[10] = p22re.r.lo32; accBuf[11] = p22re.r.hi32; +} + +/*********************************************************************************************************************** + * Function: CVKernel2 + * + * Description: kernel of covariance matrix calculation for p02 + * + * Inputs: buffer of low-freq samples, starting at time index = 0, + * freq index = patch subband + * + * Outputs: 64-bit accumulators for p02re, p02im stored in accBuf + * + * Return: none + * + * Notes: this is carefully written to be efficient on ARM + * use the assembly code version in sbrcov.s when building for ARM! + **********************************************************************************************************************/ +void CVKernel2(int32_t *XBuf, int32_t *accBuf) +{ + U64 p02re, p02im; + int32_t n, x0re, x0im, x1re, x1im, x2re, x2im; + + p02re.w64 = p02im.w64 = 0; + + x0re = XBuf[0]; + x0im = XBuf[1]; + XBuf += (2*64); + x1re = XBuf[0]; + x1im = XBuf[1]; + XBuf += (2*64); + + for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) { + /* 6 input, 2*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */ + x2re = XBuf[0]; + x2im = XBuf[1]; + + p02re.w64 = MADD64(p02re.w64, x2re, x0re); + p02re.w64 = MADD64(p02re.w64, x2im, x0im); + p02im.w64 = MADD64(p02im.w64, x0re, x2im); + p02im.w64 = MADD64(p02im.w64, -x0im, x2re); + + x0re = x1re; + x0im = x1im; + x1re = x2re; + x1im = x2im; + XBuf += (2*64); + } + + accBuf[0] = p02re.r.lo32; + accBuf[1] = p02re.r.hi32; + accBuf[2] = p02im.r.lo32; + accBuf[3] = p02im.r.hi32; +} + +/*********************************************************************************************************************** + * Function: SetBitstreamPointer + * + * Description: initialize bitstream reader + * + * Inputs: number of bytes in bitstream + * pointer to byte-aligned buffer of data to read from + * + * Outputs: initialized bitstream info struct + * + * Return: none + **********************************************************************************************************************/ +void SetBitstreamPointer(int32_t nBytes, uint8_t *buf) +{ + /* init bitstream */ + m_aac_BitStreamInfo.bytePtr = buf; + m_aac_BitStreamInfo.iCache = 0; /* 4-byte uint32_t */ + m_aac_BitStreamInfo.cachedBits = 0; /* i.e. zero bits in cache */ + m_aac_BitStreamInfo.nBytes = nBytes; +} + +/*********************************************************************************************************************** + * Function: RefillBitstreamCache + * + * Description: read new data from bitstream buffer into 32-bit cache + * + * Inputs: none + * + * Outputs: updated bitstream info struct + * + * Return: none + * + * Notes: only call when iCache is completely drained (resets bitOffset to 0) + * always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer) + * stores data as big-endian in cache, regardless of machine endian-ness + **********************************************************************************************************************/ +//Optimized for REV16, REV32 (FB) +inline void RefillBitstreamCache() +{ + int32_t nBytes = m_aac_BitStreamInfo.nBytes; + if (nBytes >= 4) { + /* optimize for common case, independent of machine endian-ness */ + m_aac_BitStreamInfo.iCache = (*m_aac_BitStreamInfo.bytePtr++) << 24; + m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++) << 16; + m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++) << 8; + m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++); + + m_aac_BitStreamInfo.cachedBits = 32; + m_aac_BitStreamInfo.nBytes -= 4; + } else { + m_aac_BitStreamInfo.iCache = 0; + while (nBytes--) { + m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++); + m_aac_BitStreamInfo.iCache <<= 8; + } + m_aac_BitStreamInfo.iCache <<= ((3 - m_aac_BitStreamInfo.nBytes)*8); + m_aac_BitStreamInfo.cachedBits = 8*m_aac_BitStreamInfo.nBytes; + m_aac_BitStreamInfo.nBytes = 0; + } +} + +/*********************************************************************************************************************** + * Function: GetBits + * + * Description: get bits from bitstream, advance bitstream pointer + * + * Inputs: pointer to initialized aac_BitStreamInfo_t struct + * number of bits to get from bitstream + * + * Outputs: updated bitstream info struct + * + * Return: the next nBits bits of data from bitstream buffer + * + * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f + * for speed, does not indicate error if you overrun bit buffer + * if nBits == 0, returns 0 + **********************************************************************************************************************/ +uint32_t GetBits(int32_t nBits) +{ + uint32_t data, lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ + data = m_aac_BitStreamInfo.iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + m_aac_BitStreamInfo.iCache <<= nBits; /* left-justify cache */ + m_aac_BitStreamInfo.cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ + + /* if we cross an int32_t boundary, refill the cache */ + if (m_aac_BitStreamInfo.cachedBits < 0) { + lowBits = -m_aac_BitStreamInfo.cachedBits; + RefillBitstreamCache(); + data |= m_aac_BitStreamInfo.iCache >> (32 - lowBits); /* get the low-order bits */ + + m_aac_BitStreamInfo.cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ + m_aac_BitStreamInfo.iCache <<= lowBits; /* left-justify cache */ + } + + return data; +} + +/*********************************************************************************************************************** + * Function: GetBitsNoAdvance + * + * Description: get bits from bitstream, do not advance bitstream pointer + * + * Inputs: pointer to initialized aac_BitStreamInfo_t struct + * number of bits to get from bitstream + * + * Outputs: none (state of aac_BitStreamInfo_t struct left unchanged) + * + * Return: the next nBits bits of data from bitstream buffer + * + * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f + * for speed, does not indicate error if you overrun bit buffer + * if nBits == 0, returns 0 + **********************************************************************************************************************/ +uint32_t GetBitsNoAdvance(int32_t nBits) +{ + uint8_t *buf; + uint32_t data, iCache; + int32_t lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ + data = m_aac_BitStreamInfo.iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + lowBits = nBits - m_aac_BitStreamInfo.cachedBits; /* how many bits do we have left to read */ + + /* if we cross an int32_t boundary, read next bytes in buffer */ + if (lowBits > 0) { + iCache = 0; + buf = m_aac_BitStreamInfo.bytePtr; + while (lowBits > 0) { + iCache <<= 8; + if (buf < m_aac_BitStreamInfo.bytePtr + m_aac_BitStreamInfo.nBytes) + iCache |= (uint32_t)*buf++; + lowBits -= 8; + } + lowBits = -lowBits; + data |= iCache >> lowBits; + } + + return data; +} + +/*********************************************************************************************************************** + * Function: AdvanceBitstream + * + * Description: move bitstream pointer ahead + * + * Inputs: number of bits to advance bitstream + * + * Outputs: updated bitstream info struct + * + * Return: none + * + * Notes: generally used following GetBitsNoAdvance(bsi, maxBits) + **********************************************************************************************************************/ +void AdvanceBitstream(int32_t nBits) +{ + nBits &= 0x1f; + if (nBits > m_aac_BitStreamInfo.cachedBits) { + nBits -= m_aac_BitStreamInfo.cachedBits; + RefillBitstreamCache(); + } + m_aac_BitStreamInfo.iCache <<= nBits; + m_aac_BitStreamInfo.cachedBits -= nBits; +} + +/*********************************************************************************************************************** + * Function: CalcBitsUsed + * + * Description: calculate how many bits have been read from bitstream + * + * Inputs: pointer to start of bitstream buffer + * bit offset into first byte of startBuf (0-7) + * + * Outputs: none + * + * Return: number of bits read from bitstream, as offset from startBuf:startOffset + **********************************************************************************************************************/ +int32_t CalcBitsUsed(uint8_t *startBuf, int32_t startOffset) { + + int32_t bitsUsed; + + bitsUsed = (m_aac_BitStreamInfo.bytePtr - startBuf) * 8; + bitsUsed -= m_aac_BitStreamInfo.cachedBits; + bitsUsed -= startOffset; + + return bitsUsed; +} +/*********************************************************************************************************************** + * Function: ByteAlignBitstream + * + * Description: bump bitstream pointer to start of next byte + * + * Inputs: none + * + * Outputs: byte-aligned bitstream aac_BitStreamInfo_t struct + * + * Return: none + * + * Notes: if bitstream is already byte-aligned, do nothing + **********************************************************************************************************************/ +void ByteAlignBitstream(){ + + int32_t offset; + + offset = m_aac_BitStreamInfo.cachedBits & 0x07; + AdvanceBitstream(offset); +} + +#ifdef AAC_ENABLE_SBR + +/************************************************************************************** + * Function: InitSBRState + * + * Description: initialize PSInfoSBR struct at start of stream or after flush + * + * Inputs: valid AACDecInfo struct + * + * Outputs: PSInfoSBR struct with proper initial state + * + * Return: none + **************************************************************************************/ +void InitSBRState() { + + int32_t i, ch; + uint8_t *c; + + if (!m_PSInfoSBR) + return; + + /* clear SBR state structure */ + c = (uint8_t *)m_PSInfoSBR; + for (i = 0; i < (int32_t)sizeof(m_PSInfoSBR); i++) + *c++ = 0; + + /* initialize non-zero state variables */ + for (ch = 0; ch < AAC_MAX_NCHANS; ch++) { + m_PSInfoSBR->sbrChan[ch].reset = 1; + m_PSInfoSBR->sbrChan[ch].laPrev = -1; + } +} +#endif + +/*********************************************************************************************************************** + * Function: DecodeSBRBitstream + * + * Description: decode sideband information for SBR + * + * Inputs: base output channel (range = [0, nChans-1]) + * + * Outputs: initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan) + * + * Return: 0 if successful, error code (< 0) if error + * + * Notes: SBR payload should be in aacDecInfo->fillBuf + * returns with no error if fill buffer is not an SBR extension block, + * or if current block is not a fill block (e.g. for LFE upsampling) + **********************************************************************************************************************/ +int32_t DecodeSBRBitstream(int32_t chBase) { + + int32_t headerFlag; + + if(m_AACDecInfo->currBlockID != AAC_ID_FIL + || (m_AACDecInfo->fillExtType != EXT_SBR_DATA && m_AACDecInfo->fillExtType != EXT_SBR_DATA_CRC)) + return ERR_AAC_NONE; + + SetBitstreamPointer(m_AACDecInfo->fillCount, m_AACDecInfo->fillBuf); + if(GetBits(4) != (uint32_t) m_AACDecInfo->fillExtType) return ERR_AAC_SBR_BITSTREAM; + + if(m_AACDecInfo->fillExtType == EXT_SBR_DATA_CRC) m_PSInfoSBR->crcCheckWord = GetBits(10); + + headerFlag = GetBits(1); + if(headerFlag) { + /* get sample rate index for output sample rate (2x base rate) */ + m_PSInfoSBR->sampRateIdx = GetSampRateIdx(2 * m_AACDecInfo->sampRate); + if(m_PSInfoSBR->sampRateIdx < 0 || m_PSInfoSBR->sampRateIdx >= NUM_SAMPLE_RATES) + return ERR_AAC_SBR_BITSTREAM; + else if(m_PSInfoSBR->sampRateIdx >= NUM_SAMPLE_RATES_SBR) return ERR_AAC_SBR_SINGLERATE_UNSUPPORTED; + + /* reset flag = 1 if header values changed */ + if(UnpackSBRHeader(&(m_PSInfoSBR->sbrHdr[chBase]))) m_PSInfoSBR->sbrChan[chBase].reset = 1; + + /* first valid SBR header should always trigger CalcFreqTables(), since psi->reset was set in InitSBR() */ + if(m_PSInfoSBR->sbrChan[chBase].reset) + CalcFreqTables(&(m_PSInfoSBR->sbrHdr[chBase + 0]), &(m_PSInfoSBR->sbrFreq[chBase]), + m_PSInfoSBR->sampRateIdx); + + /* copy and reset state to right channel for CPE */ + if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) + m_PSInfoSBR->sbrChan[chBase + 1].reset = m_PSInfoSBR->sbrChan[chBase + 0].reset; + } + + /* if no header has been received, upsample only */ + if(m_PSInfoSBR->sbrHdr[chBase].count == 0) return ERR_AAC_NONE; + + if(m_AACDecInfo->prevBlockID == AAC_ID_SCE) { + UnpackSBRSingleChannel(chBase); + } + else if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) { + UnpackSBRChannelPair(chBase); + } + else { + return ERR_AAC_SBR_BITSTREAM; + } + + ByteAlignBitstream(); + + return ERR_AAC_NONE; +} + +#ifdef AAC_ENABLE_SBR + +/*********************************************************************************************************************** + * Function: DecodeSBRData + * + * Description: apply SBR to one frame of PCM data + * + * Inputs: 1024 samples of decoded 32-bit PCM, before SBR + * size of input PCM samples (must be 4 bytes) + * number of fraction bits in input PCM samples + * base output channel (range = [0, nChans-1]) + * initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan) + * + * Outputs: 2048 samples of decoded 16-bit PCM, after SBR + * + * Return: 0 if successful, error code (< 0) if error + **********************************************************************************************************************/ +int32_t DecodeSBRData(int32_t chBase, int16_t *outbuf) { + + int32_t k, l, ch, chBlock, qmfaBands, qmfsBands; + int32_t upsampleOnly, gbIdx, gbMask; + int32_t *inbuf; + int16_t *outptr; + + SBRHeader *sbrHdr; + SBRGrid *sbrGrid; + SBRFreq *sbrFreq; + SBRChan *sbrChan; + + /* same header and freq tables for both channels in CPE */ + sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); + sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); + + /* upsample only if we haven't received an SBR header yet or if we have an LFE block */ + if(m_AACDecInfo->currBlockID == AAC_ID_LFE) { + chBlock = 1; + upsampleOnly = 1; + } + else if(m_AACDecInfo->currBlockID == AAC_ID_FIL) { + if(m_AACDecInfo->prevBlockID == AAC_ID_SCE) + chBlock = 1; + else if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) + chBlock = 2; + else + return ERR_AAC_NONE; + + upsampleOnly = (sbrHdr->count == 0 ? 1 : 0); + if(m_AACDecInfo->fillExtType != EXT_SBR_DATA && m_AACDecInfo->fillExtType != EXT_SBR_DATA_CRC) + return ERR_AAC_NONE; + } + else { + /* ignore non-SBR blocks */ + return ERR_AAC_NONE; + } + + if(upsampleOnly) { + sbrFreq->kStart = 32; + sbrFreq->numQMFBands = 0; + } + + for(ch = 0; ch < chBlock; ch++) { + sbrGrid = &(m_PSInfoSBR->sbrGrid[chBase + ch]); + sbrChan = &(m_PSInfoSBR->sbrChan[chBase + ch]); + + if(m_AACDecInfo->rawSampleBuf[ch] == 0 || m_AACDecInfo->rawSampleBytes != 4) return ERR_AAC_SBR_PCM_FORMAT; + inbuf = (int32_t*) m_AACDecInfo->rawSampleBuf[ch]; + outptr = outbuf + chBase + ch; + + /* restore delay buffers (could use ring buffer or keep in temp buffer for nChans == 1) */ + for(l = 0; l < HF_GEN; l++) { + for(k = 0; k < 64; k++) { + m_PSInfoSBR->XBuf[l][k][0] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0]; + m_PSInfoSBR->XBuf[l][k][1] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1]; + } + } + + /* step 1 - analysis QMF */ + qmfaBands = sbrFreq->kStart; + for(l = 0; l < 32; l++) { + gbMask = QMFAnalysis(inbuf + l * 32, m_PSInfoSBR->delayQMFA[chBase + ch], m_PSInfoSBR->XBuf[l + HF_GEN][0], + m_AACDecInfo->rawSampleFBits, &(m_PSInfoSBR->delayIdxQMFA[chBase + ch]), qmfaBands); + + gbIdx = ((l + HF_GEN) >> 5) & 0x01; + sbrChan->gbMask[gbIdx] |= gbMask; /* gbIdx = (0 if i < 32), (1 if i >= 32) */ + } + + if(upsampleOnly) { + /* no SBR - just run synthesis QMF to upsample by 2x */ + qmfsBands = 32; + for(l = 0; l < 32; l++) { + /* step 4 - synthesis QMF */ + QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], + &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); + outptr += 64 * m_AACDecInfo->nChans; + } + } + else { + /* if previous frame had lower SBR starting freq than current, zero out the synthesized QMF + * bands so they aren't used as sources for patching + * after patch generation, restore from delay buffer + * can only happen after header reset + */ + for(k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) { + for(l = 0; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) { + m_PSInfoSBR->XBuf[l][k][0] = 0; + m_PSInfoSBR->XBuf[l][k][1] = 0; + } + } + + /* step 2 - HF generation */ + GenerateHighFreq(sbrGrid, sbrFreq, sbrChan, ch); + + /* restore SBR bands that were cleared before patch generation (time slots 0, 1 no longer needed) */ + for(k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) { + for(l = HF_ADJ; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) { + m_PSInfoSBR->XBuf[l][k][0] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0]; + m_PSInfoSBR->XBuf[l][k][1] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1]; + } + } + + /* step 3 - HF adjustment */ + AdjustHighFreq(sbrHdr, sbrGrid, sbrFreq, sbrChan, ch); + + /* step 4 - synthesis QMF */ + qmfsBands = sbrFreq->kStartPrev + sbrFreq->numQMFBandsPrev; + for(l = 0; l < sbrGrid->envTimeBorder[0]; l++) { + /* if new envelope starts mid-frame, use old settings until start of first envelope in this frame */ + QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], + &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); + outptr += 64 * m_AACDecInfo->nChans; + } + + qmfsBands = sbrFreq->kStart + sbrFreq->numQMFBands; + for(; l < 32; l++) { + /* use new settings for rest of frame (usually the entire frame, unless the first envelope starts mid-frame) */ + QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], + &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); + outptr += 64 * m_AACDecInfo->nChans; + } + } + + /* save delay */ + for(l = 0; l < HF_GEN; l++) { + for(k = 0; k < 64; k++) { + m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0] = m_PSInfoSBR->XBuf[l + 32][k][0]; + m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1] = m_PSInfoSBR->XBuf[l + 32][k][1]; + } + } + sbrChan->gbMask[0] = sbrChan->gbMask[1]; + sbrChan->gbMask[1] = 0; + + if(sbrHdr->count > 0) sbrChan->reset = 0; + } + sbrFreq->kStartPrev = sbrFreq->kStart; + sbrFreq->numQMFBandsPrev = sbrFreq->numQMFBands; + + if(m_AACDecInfo->nChans > 0 && (chBase + ch) == m_AACDecInfo->nChans) m_PSInfoSBR->frameCount++; + + return ERR_AAC_NONE; +} + +#endif + +/*********************************************************************************************************************** + * Function: BubbleSort + * + * Description: in-place sort of uint8_ts + * + * Inputs: buffer of elements to sort + * number of elements to sort + * + * Outputs: sorted buffer + * + * Return: none + **********************************************************************************************************************/ +void BubbleSort(uint8_t *v, int32_t nItems) { + + int32_t i; + uint8_t t; + + while(nItems >= 2) { + for(i = 0; i < nItems - 1; i++) { + if(v[i + 1] < v[i]) { + t = v[i + 1]; + v[i + 1] = v[i]; + v[i] = t; + } + } + nItems--; + } +} +/*********************************************************************************************************************** + * Function: VMin + * + * Description: find smallest element in a buffer of uint8_ts + * + * Inputs: buffer of elements to search + * number of elements to search + * + * Outputs: none + * + * Return: smallest element in buffer + **********************************************************************************************************************/ +uint8_t VMin(uint8_t *v, int32_t nItems) { + + int32_t i; + uint8_t vMin; + + vMin = v[0]; + for(i = 1; i < nItems; i++) { + if(v[i] < vMin) vMin = v[i]; + } + return vMin; +} +/*********************************************************************************************************************** + * Function: VMax + * + * Description: find largest element in a buffer of uint8_ts + * + * Inputs: buffer of elements to search + * number of elements to search + * + * Outputs: none + * + * Return: largest element in buffer + **********************************************************************************************************************/ +uint8_t VMax(uint8_t *v, int32_t nItems) { + + int32_t i; + uint8_t vMax; + + vMax = v[0]; + for(i = 1; i < nItems; i++) { + if(v[i] > vMax) vMax = v[i]; + } + return vMax; +} +/*********************************************************************************************************************** + * Function: CalcFreqMasterScaleZero + * + * Description: calculate master frequency table when freqScale == 0 + * (4.6.18.3.2.1, figure 4.39) + * + * Inputs: alterScale flag + * index of first QMF subband in master freq table (k0) + * index of last QMF subband (k2) + * + * Outputs: master frequency table + * + * Return: number of bands in master frequency table + * + * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) + **********************************************************************************************************************/ +int32_t CalcFreqMasterScaleZero(uint8_t *freqMaster, int32_t alterScale, int32_t k0, int32_t k2) { + + int32_t nMaster, k, nBands, k2Achieved, dk, vDk[64], k2Diff; + + if(alterScale) { + dk = 2; + nBands = 2 * ((k2 - k0 + 2) >> 2); + } + else { + dk = 1; + nBands = 2 * ((k2 - k0) >> 1); + } + + if(nBands <= 0) return 0; + + k2Achieved = k0 + nBands * dk; + k2Diff = k2 - k2Achieved; + for(k = 0; k < nBands; k++) + vDk[k] = dk; + + if(k2Diff > 0) { + k = nBands - 1; + while(k2Diff) { + vDk[k]++; + k--; + k2Diff--; + } + } + else if(k2Diff < 0) { + k = 0; + while(k2Diff) { + vDk[k]--; + k++; + k2Diff++; + } + } + + nMaster = nBands; + freqMaster[0] = k0; + for(k = 1; k <= nBands; k++) + freqMaster[k] = freqMaster[k - 1] + vDk[k - 1]; + + return nMaster; +} + +/* mBandTab[i] = temp1[i] / 2 */ +static const int32_t mBandTab[3] PROGMEM = {6, 5, 4}; + +/* invWarpTab[i] = 1.0 / temp2[i], Q30 (see 4.6.18.3.2.1) */ +static const int32_t invWarpTab[2] PROGMEM = {0x40000000, 0x313b13b1}; + +/*********************************************************************************************************************** + * Function: CalcFreqMasterScale + * + * Description: calculate master frequency table when freqScale > 0 + * (4.6.18.3.2.1, figure 4.39) + * + * Inputs: alterScale flag + * freqScale flag + * index of first QMF subband in master freq table (k0) + * index of last QMF subband (k2) + * + * Outputs: master frequency table + * + * Return: number of bands in master frequency table + * + * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) + **********************************************************************************************************************/ +int32_t CalcFreqMaster(uint8_t *freqMaster, int32_t freqScale, int32_t alterScale, int32_t k0, int32_t k2) { + + int32_t bands, twoRegions, k, k1, t, vLast, vCurr, pCurr; + int32_t invWarp, nBands0, nBands1, change; + uint8_t vDk1Min, vDk0Max; + uint8_t *vDelta; + + if(freqScale < 1 || freqScale > 3) return -1; + + bands = mBandTab[freqScale - 1]; + invWarp = invWarpTab[alterScale]; + + /* tested for all k0 = [5, 64], k2 = [k0, 64] */ + if(k2 * 10000 > 22449 * k0) { + twoRegions = 1; + k1 = 2 * k0; + } + else { + twoRegions = 0; + k1 = k2; + } + + /* tested for all k0 = [5, 64], k1 = [k0, 64], freqScale = [1,3] */ + t = (log2Tab[k1] - log2Tab[k0]) >> 3; /* log2(k1/k0), Q28 to Q25 */ + nBands0 = 2 * (((bands * t) + (1 << 24)) >> 25); /* multiply by bands/2, round to nearest int32_t (mBandTab has factor of 1/2 rolled in) */ + + /* tested for all valid combinations of k0, k1, nBands (from sampRate, freqScale, alterScale) + * roundoff error can be a problem with fixpt (e.g. pCurr = 12.499999 instead of 12.50003) + * because successive multiplication always undershoots a little bit, but this + * doesn't occur in any of the ratios we encounter from the valid k0/k1 bands in the spec + */ + t = RatioPowInv(k1, k0, nBands0); + pCurr = k0 << 24; + vLast = k0; + vDelta = freqMaster + 1; /* operate in-place */ + for(k = 0; k < nBands0; k++) { + pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ + vCurr = (pCurr + (1 << 23)) >> 24; + vDelta[k] = (vCurr - vLast); + vLast = vCurr; + } + + /* sort the deltas and find max delta for first region */ + BubbleSort(vDelta, nBands0); + vDk0Max = VMax(vDelta, nBands0); + + /* fill master frequency table with bands from first region */ + freqMaster[0] = k0; + for(k = 1; k <= nBands0; k++) + freqMaster[k] += freqMaster[k - 1]; + + /* if only one region, then the table is complete */ + if(!twoRegions) return nBands0; + + /* tested for all k1 = [10, 64], k2 = [k0, 64], freqScale = [1,3] */ + t = (log2Tab[k2] - log2Tab[k1]) >> 3; /* log2(k1/k0), Q28 to Q25 */ + t = MULSHIFT32(bands * t, invWarp) << 2; /* multiply by bands/2, divide by warp factor, keep Q25 */ + nBands1 = 2 * ((t + (1 << 24)) >> 25); /* round to nearest int32_t */ + + /* see comments above for calculations in first region */ + t = RatioPowInv(k2, k1, nBands1); + pCurr = k1 << 24; + vLast = k1; + vDelta = freqMaster + nBands0 + 1; /* operate in-place */ + for(k = 0; k < nBands1; k++) { + pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ + vCurr = (pCurr + (1 << 23)) >> 24; + vDelta[k] = (vCurr - vLast); + vLast = vCurr; + } + + /* sort the deltas, adjusting first and last if the second region has smaller deltas than the first */ + vDk1Min = VMin(vDelta, nBands1); + if(vDk1Min < vDk0Max) { + BubbleSort(vDelta, nBands1); + change = vDk0Max - vDelta[0]; + if(change > ((vDelta[nBands1 - 1] - vDelta[0]) >> 1)) change = ((vDelta[nBands1 - 1] - vDelta[0]) >> 1); + vDelta[0] += change; + vDelta[nBands1 - 1] -= change; + } + BubbleSort(vDelta, nBands1); + + /* fill master frequency table with bands from second region + * Note: freqMaster[nBands0] = k1 + */ + for(k = 1; k <= nBands1; k++) + freqMaster[k + nBands0] += freqMaster[k + nBands0 - 1]; + + return (nBands0 + nBands1); +} +/*********************************************************************************************************************** + * Function: CalcFreqHigh + * + * Description: calculate high resolution frequency table (4.6.18.3.2.2) + * + * Inputs: master frequency table + * number of bands in master frequency table + * crossover band from header + * + * Outputs: high resolution frequency table + * + * Return: number of bands in high resolution frequency table + **********************************************************************************************************************/ +int32_t CalcFreqHigh(uint8_t *freqHigh, uint8_t *freqMaster, int32_t nMaster, int32_t crossOverBand) { + + int32_t k, nHigh; + + nHigh = nMaster - crossOverBand; + + for(k = 0; k <= nHigh; k++) + freqHigh[k] = freqMaster[k + crossOverBand]; + + return nHigh; +} +/*********************************************************************************************************************** + * Function: CalcFreqLow + * + * Description: calculate low resolution frequency table (4.6.18.3.2.2) + * + * Inputs: high resolution frequency table + * number of bands in high resolution frequency table + * + * Outputs: low resolution frequency table + * + * Return: number of bands in low resolution frequency table + **********************************************************************************************************************/ +int32_t CalcFreqLow(uint8_t *freqLow, uint8_t *freqHigh, int32_t nHigh) { + + int32_t k, nLow, oddFlag; + + nLow = nHigh - (nHigh >> 1); + freqLow[0] = freqHigh[0]; + oddFlag = nHigh & 0x01; + + for(k = 1; k <= nLow; k++) + freqLow[k] = freqHigh[2 * k - oddFlag]; + + return nLow; +} +/*********************************************************************************************************************** + * Function: CalcFreqNoise + * + * Description: calculate noise floor frequency table (4.6.18.3.2.2) + * + * Inputs: low resolution frequency table + * number of bands in low resolution frequency table + * index of starting QMF subband for SBR (kStart) + * index of last QMF subband (k2) + * number of noise bands + * + * Outputs: noise floor frequency table + * + * Return: number of bands in noise floor frequency table + **********************************************************************************************************************/ +int32_t CalcFreqNoise(uint8_t *freqNoise, uint8_t *freqLow, int32_t nLow, int32_t kStart, int32_t k2, int32_t noiseBands) { + + int32_t i, iLast, k, nQ, lTop, lBottom; + + lTop = log2Tab[k2]; + lBottom = log2Tab[kStart]; + nQ = noiseBands * ((lTop - lBottom) >> 2); /* Q28 to Q26, noiseBands = [0,3] */ + nQ = (nQ + (1 << 25)) >> 26; + if(nQ < 1) nQ = 1; + + ASSERT(nQ <= MAX_NUM_NOISE_FLOOR_BANDS); /* required from 4.6.18.3.6 */ + + iLast = 0; + freqNoise[0] = freqLow[0]; + for(k = 1; k <= nQ; k++) { + i = iLast + (nLow - iLast) / (nQ + 1 - k); /* truncating division */ + freqNoise[k] = freqLow[i]; + iLast = i; + } + + return nQ; +} +/*********************************************************************************************************************** + * Function: BuildPatches + * + * Description: build high frequency patches (4.6.18.6.3) + * + * Inputs: master frequency table + * number of bands in low resolution frequency table + * index of first QMF subband in master freq table (k0) + * index of starting QMF subband for SBR (kStart) + * number of QMF bands in high resolution frequency table + * sample rate index + * + * Outputs: starting subband for each patch + * number of subbands in each patch + * + * Return: number of patches + **********************************************************************************************************************/ +int32_t BuildPatches(uint8_t *patchNumSubbands, uint8_t *patchStartSubband, uint8_t *freqMaster, int32_t nMaster, int32_t k0, + int32_t kStart, int32_t numQMFBands, int32_t sampRateIdx) { + + int32_t i, j, k; + int32_t msb, sb, usb, numPatches, goalSB, oddFlag; + + msb = k0; + usb = kStart; + numPatches = 0; + goalSB = goalSBTab[sampRateIdx]; + + if(nMaster == 0) { + patchNumSubbands[0] = 0; + patchStartSubband[0] = 0; + return 0; + } + + if(goalSB < kStart + numQMFBands) { + k = 0; + for(i = 0; freqMaster[i] < goalSB; i++) + k = i + 1; + } + else { + k = nMaster; + } + + do { + j = k + 1; + do { + j--; + sb = freqMaster[j]; + oddFlag = (sb - 2 + k0) & 0x01; + } while(sb > k0 - 1 + msb - oddFlag); + + patchNumSubbands[numPatches] = MAX(sb - usb, (int32_t)0); + patchStartSubband[numPatches] = k0 - oddFlag - patchNumSubbands[numPatches]; + + /* from MPEG reference code - slightly different from spec */ + if((patchNumSubbands[numPatches] < 3) && (numPatches > 0)) break; + + if(patchNumSubbands[numPatches] > 0) { + usb = sb; + msb = sb; + numPatches++; + } + else { + msb = kStart; + } + + if(freqMaster[k] - sb < 3) k = nMaster; + + } while(sb != (kStart + numQMFBands) && numPatches <= MAX_NUM_PATCHES); + + return numPatches; +} +/*********************************************************************************************************************** + * Function: FindFreq + * + * Description: search buffer of uint8_ts for a specific value + * + * Inputs: buffer of elements to search + * number of elements to search + * value to search for + * + * Outputs: none + * + * Return: non-zero if the value is found anywhere in the buffer, zero otherwise + **********************************************************************************************************************/ +int32_t FindFreq(uint8_t *freq, int32_t nFreq, uint8_t val) { + + int32_t k; + + for(k = 0; k < nFreq; k++) { + if(freq[k] == val) return 1; + } + + return 0; +} +/*********************************************************************************************************************** + * Function: RemoveFreq + * + * Description: remove one element from a buffer of uint8_ts + * + * Inputs: buffer of elements + * number of elements + * index of element to remove + * + * Outputs: new buffer of length nFreq-1 + * + * Return: none + **********************************************************************************************************************/ +void RemoveFreq(uint8_t *freq, int32_t nFreq, int32_t removeIdx) { + + int32_t k; + + if(removeIdx >= nFreq) return; + + for(k = removeIdx; k < nFreq - 1; k++) + freq[k] = freq[k + 1]; +} +/*********************************************************************************************************************** + * Function: CalcFreqLimiter + * + * Description: calculate limiter frequency table (4.6.18.3.2.3) + * + * Inputs: number of subbands in each patch + * low resolution frequency table + * number of bands in low resolution frequency table + * index of starting QMF subband for SBR (kStart) + * number of limiter bands + * number of patches + * + * Outputs: limiter frequency table + * + * Return: number of bands in limiter frequency table + **********************************************************************************************************************/ +int32_t CalcFreqLimiter(uint8_t *freqLimiter, uint8_t *patchNumSubbands, uint8_t *freqLow, int32_t nLow, int32_t kStart, + int32_t limiterBands, int32_t numPatches) { + + int32_t k, bands, nLimiter, nOctaves; + int32_t limBandsPerOctave[3] = { 120, 200, 300 }; /* [1.2, 2.0, 3.0] * 100 */ + uint8_t patchBorders[MAX_NUM_PATCHES + 1]; + + /* simple case */ + if(limiterBands == 0) { + freqLimiter[0] = freqLow[0] - kStart; + freqLimiter[1] = freqLow[nLow] - kStart; + return 1; + } + + bands = limBandsPerOctave[limiterBands - 1]; + patchBorders[0] = kStart; + + /* from MPEG reference code - slightly different from spec (top border) */ + for(k = 1; k < numPatches; k++) + patchBorders[k] = patchBorders[k - 1] + patchNumSubbands[k - 1]; + patchBorders[k] = freqLow[nLow]; + + for(k = 0; k <= nLow; k++) + freqLimiter[k] = freqLow[k]; + + for(k = 1; k < numPatches; k++) + freqLimiter[k + nLow] = patchBorders[k]; + + k = 1; + nLimiter = nLow + numPatches - 1; + BubbleSort(freqLimiter, nLimiter + 1); + + while(k <= nLimiter) { + nOctaves = log2Tab[freqLimiter[k]] - log2Tab[freqLimiter[k - 1]]; /* Q28 */ + nOctaves = (nOctaves >> 9) * bands; /* Q19, max bands = 300 < 2^9 */ + if(nOctaves < (49 << 19)) { /* compare with 0.49*100, in Q19 */ + if(freqLimiter[k] == freqLimiter[k - 1] || FindFreq(patchBorders, numPatches + 1, freqLimiter[k]) == 0) { + RemoveFreq(freqLimiter, nLimiter + 1, k); + nLimiter--; + } + else if(FindFreq(patchBorders, numPatches + 1, freqLimiter[k - 1]) == 0) { + RemoveFreq(freqLimiter, nLimiter + 1, k - 1); + nLimiter--; + } + else { + k++; + } + } + else { + k++; + } + } + + /* store limiter boundaries as offsets from kStart */ + for(k = 0; k <= nLimiter; k++) + freqLimiter[k] -= kStart; + + return nLimiter; +} +/*********************************************************************************************************************** + * Function: CalcFreqTables + * + * Description: calulate master and derived frequency tables, and patches + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRFreq struct for this SCE/CPE block + * sample rate index of output sample rate (after SBR) + * + * Outputs: master and derived frequency tables, and patches + * + * Return: non-zero if error, zero otherwise + **********************************************************************************************************************/ +int32_t CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int32_t sampRateIdx) { + int32_t k0, k2; + + k0 = k0Tab[sampRateIdx][sbrHdr->startFreq]; + + if(sbrHdr->stopFreq == 14) + k2 = 2 * k0; + else if(sbrHdr->stopFreq == 15) + k2 = 3 * k0; + else + k2 = k2Tab[sampRateIdx][sbrHdr->stopFreq]; + if(k2 > 64) k2 = 64; + + /* calculate master frequency table */ + if(sbrHdr->freqScale == 0) + sbrFreq->nMaster = CalcFreqMasterScaleZero(sbrFreq->freqMaster, sbrHdr->alterScale, k0, k2); + else + sbrFreq->nMaster = CalcFreqMaster(sbrFreq->freqMaster, sbrHdr->freqScale, sbrHdr->alterScale, k0, k2); + + /* calculate high frequency table and related parameters */ + sbrFreq->nHigh = CalcFreqHigh(sbrFreq->freqHigh, sbrFreq->freqMaster, sbrFreq->nMaster, sbrHdr->crossOverBand); + sbrFreq->numQMFBands = sbrFreq->freqHigh[sbrFreq->nHigh] - sbrFreq->freqHigh[0]; + sbrFreq->kStart = sbrFreq->freqHigh[0]; + + /* calculate low frequency table */ + sbrFreq->nLow = CalcFreqLow(sbrFreq->freqLow, sbrFreq->freqHigh, sbrFreq->nHigh); + + /* calculate noise floor frequency table */ + sbrFreq->numNoiseFloorBands = CalcFreqNoise(sbrFreq->freqNoise, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, + k2, sbrHdr->noiseBands); + + /* calculate limiter table */ + sbrFreq->numPatches = BuildPatches(sbrFreq->patchNumSubbands, sbrFreq->patchStartSubband, sbrFreq->freqMaster, + sbrFreq->nMaster, k0, sbrFreq->kStart, sbrFreq->numQMFBands, sampRateIdx); + sbrFreq->nLimiter = CalcFreqLimiter(sbrFreq->freqLimiter, sbrFreq->patchNumSubbands, sbrFreq->freqLow, + sbrFreq->nLow, sbrFreq->kStart, sbrHdr->limiterBands, sbrFreq->numPatches); + + return 0; +} +/*********************************************************************************************************************** + * Function: EstimateEnvelope + * + * Description: estimate power of generated HF QMF bands in one time-domain envelope + * (4.6.18.7.3) + * + * Inputs: initialized PSInfoSBR struct + * initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * index of current envelope + * + * Outputs: power of each QMF subband, stored as integer (Q0) * 2^N, N >= 0 + * + * Return: none + **********************************************************************************************************************/ +void EstimateEnvelope(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int32_t env) { + + int32_t i, m, iStart, iEnd, xre, xim, nScale, expMax; + int32_t p, n, mStart, mEnd, invFact, t; + int32_t *XBuf; + U64 eCurr; + uint8_t *freqBandTab; + + /* estimate current envelope */ + iStart = sbrGrid->envTimeBorder[env] + HF_ADJ; + iEnd = sbrGrid->envTimeBorder[env + 1] + HF_ADJ; + if(sbrGrid->freqRes[env]) { + n = sbrFreq->nHigh; + freqBandTab = sbrFreq->freqHigh; + } + else { + n = sbrFreq->nLow; + freqBandTab = sbrFreq->freqLow; + } + + /* ADS should inline MADD64 (smlal) properly, but check to make sure */ + expMax = 0; + if(sbrHdr->interpFreq) { + for(m = 0; m < sbrFreq->numQMFBands; m++) { + eCurr.w64 = 0; + XBuf = m_PSInfoSBR->XBuf[iStart][sbrFreq->kStart + m]; + for(i = iStart; i < iEnd; i++) { + /* scale to int32_t before calculating power (precision not critical, and avoids overflow) */ + xre = (*XBuf) >> FBITS_OUT_QMFA; + XBuf += 1; + xim = (*XBuf) >> FBITS_OUT_QMFA; + XBuf += (2 * 64 - 1); + eCurr.w64 = MADD64(eCurr.w64, xre, xre); + eCurr.w64 = MADD64(eCurr.w64, xim, xim); + } + + /* eCurr.w64 is now Q(64 - 2*FBITS_OUT_QMFA) (64-bit word) + * if energy is too big to fit in 32-bit word (> 2^31) scale down by power of 2 + */ + nScale = 0; + if(eCurr.r.hi32) { + nScale = (32 - CLZ(eCurr.r.hi32)) + 1; + t = (int32_t) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ + t |= eCurr.r.hi32 << (32 - nScale); + } + else if(eCurr.r.lo32 >> 31) { + nScale = 1; + t = (int32_t) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ + } + else { + t = (int32_t) eCurr.r.lo32; + } + + invFact = invBandTab[(iEnd - iStart) - 1]; + m_PSInfoSBR->eCurr[m] = MULSHIFT32(t, invFact); + m_PSInfoSBR->eCurrExp[m] = nScale + 1; /* +1 for invFact = Q31 */ + if(m_PSInfoSBR->eCurrExp[m] > expMax) expMax = m_PSInfoSBR->eCurrExp[m]; + } + } + else { + for(p = 0; p < n; p++) { + mStart = freqBandTab[p]; + mEnd = freqBandTab[p + 1]; + eCurr.w64 = 0; + for(i = iStart; i < iEnd; i++) { + XBuf = m_PSInfoSBR->XBuf[i][mStart]; + for(m = mStart; m < mEnd; m++) { + xre = (*XBuf++) >> FBITS_OUT_QMFA; + xim = (*XBuf++) >> FBITS_OUT_QMFA; + eCurr.w64 = MADD64(eCurr.w64, xre, xre); + eCurr.w64 = MADD64(eCurr.w64, xim, xim); + } + } + + nScale = 0; + if(eCurr.r.hi32) { + nScale = (32 - CLZ(eCurr.r.hi32)) + 1; + t = (int32_t) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ + t |= eCurr.r.hi32 << (32 - nScale); + } + else if(eCurr.r.lo32 >> 31) { + nScale = 1; + t = (int32_t) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ + } + else { + t = (int32_t) eCurr.r.lo32; + } + + invFact = invBandTab[(iEnd - iStart) - 1]; + invFact = MULSHIFT32(invBandTab[(mEnd - mStart) - 1], invFact) << 1; + t = MULSHIFT32(t, invFact); + + for(m = mStart; m < mEnd; m++) { + m_PSInfoSBR->eCurr[m - sbrFreq->kStart] = t; + m_PSInfoSBR->eCurrExp[m - sbrFreq->kStart] = nScale + 1; /* +1 for invFact = Q31 */ + } + if(m_PSInfoSBR->eCurrExp[mStart - sbrFreq->kStart] > expMax) + expMax = m_PSInfoSBR->eCurrExp[mStart - sbrFreq->kStart]; + } + } + m_PSInfoSBR->eCurrExpMax = expMax; +} +/*********************************************************************************************************************** + * Function: GetSMapped + * + * Description: calculate SMapped (4.6.18.7.2) + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current envelope + * index of current QMF band + * la flag for this envelope + * + * Outputs: none + * + * Return: 1 if a sinusoid is present in this band, 0 if not + **********************************************************************************************************************/ +int32_t GetSMapped(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t env, int32_t band, int32_t la) { + + int32_t bandStart, bandEnd, oddFlag, r; + + if (sbrGrid->freqRes[env]) { + /* high resolution */ + bandStart = band; + bandEnd = band+1; + } else { + /* low resolution (see CalcFreqLow() for mapping) */ + oddFlag = sbrFreq->nHigh & 0x01; + bandStart = (band > 0 ? 2*band - oddFlag : 0); /* starting index for freqLow[band] */ + bandEnd = 2*(band+1) - oddFlag; /* ending index for freqLow[band+1] */ + } + + /* sMapped = 1 if sIndexMapped == 1 for any frequency in this band */ + for (band = bandStart; band < bandEnd; band++) { + if (sbrChan->addHarmonic[1][band]) { + r = ((sbrFreq->freqHigh[band+1] + sbrFreq->freqHigh[band]) >> 1); + if (env >= la || sbrChan->addHarmonic[0][r] == 1) + return 1; + } + } + return 0; +} + +#define GBOOST_MAX 0x2830afd3 /* Q28, 1.584893192 squared */ +#define ACC_SCALE 6 + +/* squared version of table in 4.6.18.7.5 */ /* Q30 (0x80000000 = sentinel for GMAX) */ +static const uint32_t limGainTab[4] PROGMEM = {0x20138ca7, 0x40000000, 0x7fb27dce, 0x80000000}; + +/*********************************************************************************************************************** + * Function: CalcMaxGain + * + * Description: calculate max gain in one limiter band (4.6.18.7.5) + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * index of current channel (0 for SCE, 0 or 1 for CPE) + * index of current envelope + * index of current limiter band + * number of fraction bits in dequantized envelope + * (max = Q(FBITS_OUT_DQ_ENV - 6) = Q23, can go negative) + * + * Outputs: updated gainMax, gainMaxFBits, and sumEOrigMapped in PSInfoSBR struct + * + * Return: none + **********************************************************************************************************************/ +void CalcMaxGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int32_t ch, int32_t env, int32_t lim, int32_t fbitsDQ) { + + int32_t m, mStart, mEnd, q, z, r; + int32_t sumEOrigMapped, sumECurr, gainMax, eOMGainMax, envBand; + uint8_t eCurrExpMax; + uint8_t *freqBandTab; + + mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ + mEnd = sbrFreq->freqLimiter[lim + 1]; + freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow); + + /* calculate max gain to apply to signal in this limiter band */ + sumECurr = 0; + sumEOrigMapped = 0; + eCurrExpMax = m_PSInfoSBR->eCurrExpMax; + eOMGainMax = m_PSInfoSBR->eOMGainMax; + envBand = m_PSInfoSBR->envBand; + for(m = mStart; m < mEnd; m++) { + /* map current QMF band to appropriate envelope band */ + if(m == freqBandTab[envBand + 1] - sbrFreq->kStart) { + envBand++; + eOMGainMax = m_PSInfoSBR->envDataDequant[ch][env][envBand] >> ACC_SCALE; /* summing max 48 bands */ + } + sumEOrigMapped += eOMGainMax; + + /* easy test for overflow on ARM */ + sumECurr += (m_PSInfoSBR->eCurr[m] >> (eCurrExpMax - m_PSInfoSBR->eCurrExp[m])); + if(sumECurr >> 30) { + sumECurr >>= 1; + eCurrExpMax++; + } + } + m_PSInfoSBR->eOMGainMax = eOMGainMax; + m_PSInfoSBR->envBand = envBand; + + m_PSInfoSBR->gainMaxFBits = 30; /* Q30 tables */ + if(sumECurr == 0) { + /* any non-zero numerator * 1/EPS_0 is > G_MAX */ + gainMax = (sumEOrigMapped == 0 ? (int32_t) limGainTab[sbrHdr->limiterGains] : (int32_t) 0x80000000); + } + else if(sumEOrigMapped == 0) { + /* 1/(any non-zero denominator) * EPS_0 * limGainTab[x] is appx. 0 */ + gainMax = 0; + } + else { + /* sumEOrigMapped = Q(fbitsDQ - ACC_SCALE), sumECurr = Q(-eCurrExpMax) */ + gainMax = limGainTab[sbrHdr->limiterGains]; + if(sbrHdr->limiterGains != 3) { + q = MULSHIFT32(sumEOrigMapped, gainMax); /* Q(fbitsDQ - ACC_SCALE - 2), gainMax = Q30 */ + z = CLZ(sumECurr) - 1; + r = InvRNormalized(sumECurr << z); /* in = Q(z - eCurrExpMax), out = Q(29 + 31 - z + eCurrExpMax) */ + gainMax = MULSHIFT32(q, r); /* Q(29 + 31 - z + eCurrExpMax + fbitsDQ - ACC_SCALE - 2 - 32) */ + m_PSInfoSBR->gainMaxFBits = 26 - z + eCurrExpMax + fbitsDQ - ACC_SCALE; + } + } + m_PSInfoSBR->sumEOrigMapped = sumEOrigMapped; + m_PSInfoSBR->gainMax = gainMax; +} +/*********************************************************************************************************************** + * Function: CalcNoiseDivFactors + * + * Description: calculate 1/(1+Q) and Q/(1+Q) (4.6.18.7.4; 4.6.18.7.5) + * + * Inputs: dequantized noise floor scalefactor + * + * Outputs: 1/(1+Q) and Q/(1+Q), format = Q31 + * + * Return: none + **********************************************************************************************************************/ +void CalcNoiseDivFactors(int32_t q, int32_t *qp1Inv, int32_t *qqp1Inv) { + + int32_t z, qp1, t, s; + + /* 1 + Q_orig */ + qp1 = (q >> 1); + qp1 += (1 << (FBITS_OUT_DQ_NOISE - 1)); /* >> 1 to avoid overflow when adding 1.0 */ + z = CLZ(qp1) - 1; /* z <= 31 - FBITS_OUT_DQ_NOISE */ + qp1 <<= z; /* Q(FBITS_OUT_DQ_NOISE + z) = Q31 * 2^-(31 - (FBITS_OUT_DQ_NOISE + z)) */ + t = InvRNormalized(qp1) << 1; /* Q30 * 2^(31 - (FBITS_OUT_DQ_NOISE + z)), guaranteed not to overflow */ + + /* normalize to Q31 */ + s = (31 - (FBITS_OUT_DQ_NOISE - 1) - z - 1); /* clearly z >= 0, z <= (30 - (FBITS_OUT_DQ_NOISE - 1)) */ + *qp1Inv = (t >> s); /* s = [0, 31 - FBITS_OUT_DQ_NOISE] */ + *qqp1Inv = MULSHIFT32(t, q) << (32 - FBITS_OUT_DQ_NOISE - s); +} +/*********************************************************************************************************************** + * Function: CalcComponentGains + * + * Description: calculate gain of envelope, sinusoids, and noise in one limiter band + * (4.6.18.7.5) + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * index of current envelope + * index of current limiter band + * number of fraction bits in dequantized envelope + * + * Outputs: gains for envelope, sinusoids and noise + * number of fraction bits for envelope gain + * sum of the total gain for each component in this band + * other updated state variables + * + * Return: none + **********************************************************************************************************************/ +void CalcComponentGains(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch, int32_t env, int32_t lim, int32_t fbitsDQ) { + + int32_t d, m, mStart, mEnd, q, qm, noiseFloor, sIndexMapped; + int32_t shift, eCurr, maxFlag, gainMax, gainMaxFBits; + int32_t gain, sm, z, r, fbitsGain, gainScale; + uint8_t *freqBandTab; + + mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ + mEnd = sbrFreq->freqLimiter[lim + 1]; + + gainMax = m_PSInfoSBR->gainMax; + gainMaxFBits = m_PSInfoSBR->gainMaxFBits; + + d = (env == m_PSInfoSBR->la || env == sbrChan->laPrev ? 0 : 1); + freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow); + + /* figure out which noise floor this envelope is in (only 1 or 2 noise floors allowed) */ + noiseFloor = 0; + if(sbrGrid->numNoiseFloors == 2 && sbrGrid->noiseTimeBorder[1] <= sbrGrid->envTimeBorder[env]) noiseFloor++; + + m_PSInfoSBR->sumECurrGLim = 0; + m_PSInfoSBR->sumSM = 0; + m_PSInfoSBR->sumQM = 0; + /* calculate energy of noise to add in this limiter band */ + for(m = mStart; m < mEnd; m++) { + if(m == sbrFreq->freqNoise[m_PSInfoSBR->noiseFloorBand + 1] - sbrFreq->kStart) { + /* map current QMF band to appropriate noise floor band (NOTE: freqLimiter[0] == freqLow[0] = freqHigh[0]) */ + m_PSInfoSBR->noiseFloorBand++; + CalcNoiseDivFactors(m_PSInfoSBR->noiseDataDequant[ch][noiseFloor][m_PSInfoSBR->noiseFloorBand], + &(m_PSInfoSBR->qp1Inv), &(m_PSInfoSBR->qqp1Inv)); + } + if(m == sbrFreq->freqHigh[m_PSInfoSBR->highBand + 1] - sbrFreq->kStart) m_PSInfoSBR->highBand++; + if(m == freqBandTab[m_PSInfoSBR->sBand + 1] - sbrFreq->kStart) { + m_PSInfoSBR->sBand++; + m_PSInfoSBR->sMapped = GetSMapped(sbrGrid, sbrFreq, sbrChan, env, m_PSInfoSBR->sBand, m_PSInfoSBR->la); + } + + /* get sIndexMapped for this QMF subband */ + sIndexMapped = 0; + r = ((sbrFreq->freqHigh[m_PSInfoSBR->highBand + 1] + sbrFreq->freqHigh[m_PSInfoSBR->highBand]) >> 1); + if(m + sbrFreq->kStart == r) { + /* r = center frequency, deltaStep = (env >= la || sIndexMapped'(r, numEnv'-1) == 1) */ + if(env >= m_PSInfoSBR->la || sbrChan->addHarmonic[0][r] == 1) sIndexMapped = + sbrChan->addHarmonic[1][m_PSInfoSBR->highBand]; + } + + /* save sine flags from last envelope in this frame: + * addHarmonic[0][0...63] = saved sine present flag from previous frame, for each QMF subband + * addHarmonic[1][0...nHigh-1] = addHarmonic bit from current frame, for each high-res frequency band + * from MPEG reference code - slightly different from spec + * (sIndexMapped'(m,LE'-1) can still be 0 when numEnv == psi->la) + */ + if(env == sbrGrid->numEnv - 1) { + if(m + sbrFreq->kStart == r) + sbrChan->addHarmonic[0][m + sbrFreq->kStart] = sbrChan->addHarmonic[1][m_PSInfoSBR->highBand]; + else + sbrChan->addHarmonic[0][m + sbrFreq->kStart] = 0; + } + + gain = m_PSInfoSBR->envDataDequant[ch][env][m_PSInfoSBR->sBand]; + qm = MULSHIFT32(gain, m_PSInfoSBR->qqp1Inv) << 1; + sm = (sIndexMapped ? MULSHIFT32(gain, m_PSInfoSBR->qp1Inv) << 1 : 0); + + /* three cases: (sMapped == 0 && delta == 1), (sMapped == 0 && delta == 0), (sMapped == 1) */ + if(d == 1 && m_PSInfoSBR->sMapped == 0) + gain = MULSHIFT32(m_PSInfoSBR->qp1Inv, gain) << 1; + else if(m_PSInfoSBR->sMapped != 0) gain = MULSHIFT32(m_PSInfoSBR->qqp1Inv, gain) << 1; + + /* gain, qm, sm = Q(fbitsDQ), gainMax = Q(fbitsGainMax) */ + eCurr = m_PSInfoSBR->eCurr[m]; + if(eCurr) { + z = CLZ(eCurr) - 1; + r = InvRNormalized(eCurr << z); /* in = Q(z - eCurrExp), out = Q(29 + 31 - z + eCurrExp) */ + gainScale = MULSHIFT32(gain, r); /* out = Q(29 + 31 - z + eCurrExp + fbitsDQ - 32) */ + fbitsGain = 29 + 31 - z + m_PSInfoSBR->eCurrExp[m] + fbitsDQ - 32; + } + else { + /* if eCurr == 0, then gain is unchanged (divide by EPS = 1) */ + gainScale = gain; + fbitsGain = fbitsDQ; + } + + /* see if gain for this band exceeds max gain */ + maxFlag = 0; + if(gainMax != (int32_t) 0x80000000) { + if(fbitsGain >= gainMaxFBits) { + shift = MIN(fbitsGain - gainMaxFBits, (int32_t)31); + maxFlag = ((gainScale >> shift) > gainMax ? 1 : 0); + } + else { + shift = MIN(gainMaxFBits - fbitsGain, (int32_t)31); + maxFlag = (gainScale > (gainMax >> shift) ? 1 : 0); + } + } + + if(maxFlag) { + /* gainScale > gainMax, calculate ratio with 32/16 division */ + q = 0; + r = gainScale; /* guaranteed > 0, else maxFlag could not have been set */ + z = CLZ(r); + if(z < 16) { + q = 16 - z; + r >>= q; /* out = Q(fbitsGain - q) */ + } + + z = CLZ(gainMax) - 1; + r = (gainMax << z) / r; /* out = Q((fbitsGainMax + z) - (fbitsGain - q)) */ + q = (gainMaxFBits + z) - (fbitsGain - q); /* r = Q(q) */ + if(q > 30) { + r >>= MIN(q - 30, (int32_t)31); + } + else { + z = MIN((int32_t)30 - q, (int32_t)30); + r = CLIP_2N_SHIFT30(r, z); /* let r = Q30 since range = [0.0, 1.0) (clip to 0x3fffffff = 0.99999) */ + } + + qm = MULSHIFT32(qm, r) << 2; + gain = MULSHIFT32(gain, r) << 2; + m_PSInfoSBR->gLimBuf[m] = gainMax; + m_PSInfoSBR->gLimFbits[m] = gainMaxFBits; + } + else { + m_PSInfoSBR->gLimBuf[m] = gainScale; + m_PSInfoSBR->gLimFbits[m] = fbitsGain; + } + + /* sumSM, sumQM, sumECurrGLim = Q(fbitsDQ - ACC_SCALE) */ + m_PSInfoSBR->smBuf[m] = sm; + m_PSInfoSBR->sumSM += (sm >> ACC_SCALE); + + m_PSInfoSBR->qmLimBuf[m] = qm; + if(env != m_PSInfoSBR->la && env != sbrChan->laPrev && sm == 0) m_PSInfoSBR->sumQM += (qm >> ACC_SCALE); + + /* eCurr * gain^2 same as gain^2, before division by eCurr + * (but note that gain != 0 even if eCurr == 0, since it's divided by eps) + */ + if(eCurr) m_PSInfoSBR->sumECurrGLim += (gain >> ACC_SCALE); + } +} +/*********************************************************************************************************************** + * Function: ApplyBoost + * + * Description: calculate and apply boost factor for envelope, sinusoids, and noise + * in this limiter band (4.6.18.7.5) + * + * Inputs: initialized SBRFreq struct for this SCE/CPE block + * index of current limiter band + * number of fraction bits in dequantized envelope + * + * Outputs: envelope gain, sinusoids and noise after scaling by gBoost + * format = Q(FBITS_GLIM_BOOST) for envelope gain, + * = Q(FBITS_QLIM_BOOST) for noise + * = Q(FBITS_OUT_QMFA) for sinusoids + * + * Return: none + * + * Notes: after scaling, each component has at least 1 GB + **********************************************************************************************************************/ +void ApplyBoost(SBRFreq *sbrFreq, int32_t lim, int32_t fbitsDQ) { + + int32_t m, mStart, mEnd, q, z, r; + int32_t sumEOrigMapped, gBoost; + + mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ + mEnd = sbrFreq->freqLimiter[lim + 1]; + + sumEOrigMapped = m_PSInfoSBR->sumEOrigMapped >> 1; + r = (m_PSInfoSBR->sumECurrGLim >> 1) + (m_PSInfoSBR->sumSM >> 1) + (m_PSInfoSBR->sumQM >> 1); /* 1 GB fine (sm and qm are mutually exclusive in acc) */ + if(r < (1 << (31 - 28))) { + /* any non-zero numerator * 1/EPS_0 is > GBOOST_MAX + * round very small r to zero to avoid scaling problems + */ + gBoost = (sumEOrigMapped == 0 ? (1 << 28) : GBOOST_MAX); + z = 0; + } + else if(sumEOrigMapped == 0) { + /* 1/(any non-zero denominator) * EPS_0 is appx. 0 */ + gBoost = 0; + z = 0; + } + else { + /* numerator (sumEOrigMapped) and denominator (r) have same Q format (before << z) */ + z = CLZ(r) - 1; /* z = [0, 27] */ + r = InvRNormalized(r << z); + gBoost = MULSHIFT32(sumEOrigMapped, r); + } + + /* gBoost = Q(28 - z) */ + if(gBoost > (GBOOST_MAX >> z)) { + gBoost = GBOOST_MAX; + z = 0; + } + gBoost <<= z; /* gBoost = Q28, minimum 1 GB */ + + /* convert gain, noise, sinusoids to fixed Q format, clipping if necessary + * (rare, usually only happens at very low bitrates, introduces slight + * distortion into final HF mapping, but should be inaudible) + */ + for(m = mStart; m < mEnd; m++) { + /* let gLimBoost = Q24, since in practice the max values are usually 16 to 20 + * unless limiterGains == 3 (limiter off) and eCurr ~= 0 (i.e. huge gain, but only + * because the envelope has 0 power anyway) + */ + q = MULSHIFT32(m_PSInfoSBR->gLimBuf[m], gBoost) << 2; /* Q(gLimFbits) * Q(28) --> Q(gLimFbits[m]-2) */ + r = SqrtFix(q, m_PSInfoSBR->gLimFbits[m] - 2, &z); + z -= FBITS_GLIM_BOOST; + if(z >= 0) { + m_PSInfoSBR->gLimBoost[m] = r >> MIN(z, (int32_t)31); + } + else { + z = MIN((int32_t)30, -z); + r = CLIP_2N_SHIFT30(r, z); + m_PSInfoSBR->gLimBoost[m] = r; + } + + q = MULSHIFT32(m_PSInfoSBR->qmLimBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */ + r = SqrtFix(q, fbitsDQ - 2, &z); + z -= FBITS_QLIM_BOOST; /* << by 14, since integer sqrt of x < 2^16, and we want to leave 1 GB */ + if(z >= 0) { + m_PSInfoSBR->qmLimBoost[m] = r >> MIN((int32_t)31, z); + } + else { + z = MIN((int32_t)30, -z); + r = CLIP_2N_SHIFT30(r, z); + m_PSInfoSBR->qmLimBoost[m] = r; + } + + q = MULSHIFT32(m_PSInfoSBR->smBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */ + r = SqrtFix(q, fbitsDQ - 2, &z); + z -= FBITS_OUT_QMFA; /* justify for adding to signal (xBuf) later */ + if(z >= 0) { + m_PSInfoSBR->smBoost[m] = r >> MIN((int32_t)31, z); + } + else { + z = MIN((int32_t)30, -z); + r = CLIP_2N_SHIFT30(r, z); + m_PSInfoSBR->smBoost[m] = r; + } + } +} +/*********************************************************************************************************************** + * Function: CalcGain + * + * Description: calculate and apply proper gain to HF components in one envelope + * (4.6.18.7.5) + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * index of current envelope + * + * Outputs: envelope gain, sinusoids and noise after scaling + * + * Return: none + **********************************************************************************************************************/ +void CalcGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch, int32_t env) { + + int32_t lim, fbitsDQ; + + /* initialize to -1 so that mapping limiter bands to env/noise bands works right on first pass */ + m_PSInfoSBR->envBand = -1; + m_PSInfoSBR->noiseFloorBand = -1; + m_PSInfoSBR->sBand = -1; + m_PSInfoSBR->highBand = -1; + + fbitsDQ = (FBITS_OUT_DQ_ENV - m_PSInfoSBR->envDataDequantScale[ch][env]); /* Q(29 - optional scalefactor) */ + for(lim = 0; lim < sbrFreq->nLimiter; lim++) { + /* the QMF bands are divided into lim regions (consecutive, non-overlapping) */ + CalcMaxGain(sbrHdr, sbrGrid, sbrFreq, ch, env, lim, fbitsDQ); + CalcComponentGains(sbrGrid, sbrFreq, sbrChan, ch, env, lim, fbitsDQ); + ApplyBoost(sbrFreq, lim, fbitsDQ); + } +} + +/* hSmooth table from 4.7.18.7.6, format = Q31 */ +static const int32_t hSmoothCoef[MAX_NUM_SMOOTH_COEFS] PROGMEM = { 0x2aaaaaab, 0x2697a512, 0x1becfa68, 0x0ebdb043, + 0x04130598, }; + +/*********************************************************************************************************************** + * Function: MapHF + * + * Description: map HF components to proper QMF bands, with optional gain smoothing + * filter (4.6.18.7.6) + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current envelope + * reset flag (can be non-zero for first envelope only) + * + * Outputs: complete reconstructed subband QMF samples for this envelope + * + * Return: none + * + * Notes: ensures that output has >= MIN_GBITS_IN_QMFS guard bits, + * so it's not necessary to check anything in the synth QMF + **********************************************************************************************************************/ +void MapHF(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t env, int32_t hfReset) { + + int32_t noiseTabIndex, sinIndex, gainNoiseIndex, hSL; + int32_t i, iStart, iEnd, m, idx, j, s, n, smre, smim; + int32_t gFilt, qFilt, xre, xim, gbMask, gbIdx; + int32_t *XBuf; + + noiseTabIndex = sbrChan->noiseTabIndex; + sinIndex = sbrChan->sinIndex; + gainNoiseIndex = sbrChan->gainNoiseIndex; /* oldest entries in filter delay buffer */ + + if(hfReset) noiseTabIndex = 2; /* starts at 1, double since complex */ + hSL = (sbrHdr->smoothMode ? 0 : 4); + + if(hfReset) { + for(i = 0; i < hSL; i++) { + for(m = 0; m < sbrFreq->numQMFBands; m++) { + sbrChan->gTemp[gainNoiseIndex][m] = m_PSInfoSBR->gLimBoost[m]; + sbrChan->qTemp[gainNoiseIndex][m] = m_PSInfoSBR->qmLimBoost[m]; + } + gainNoiseIndex++; + if(gainNoiseIndex == MAX_NUM_SMOOTH_COEFS) gainNoiseIndex = 0; + } ASSERT(env == 0); /* should only be reset when env == 0 */ + } + + iStart = sbrGrid->envTimeBorder[env]; + iEnd = sbrGrid->envTimeBorder[env + 1]; + for(i = iStart; i < iEnd; i++) { + /* save new values in temp buffers (delay) + * we only store MAX_NUM_SMOOTH_COEFS most recent values, + * so don't keep storing the same value over and over + */ + if(i - iStart < MAX_NUM_SMOOTH_COEFS) { + for(m = 0; m < sbrFreq->numQMFBands; m++) { + sbrChan->gTemp[gainNoiseIndex][m] = m_PSInfoSBR->gLimBoost[m]; + sbrChan->qTemp[gainNoiseIndex][m] = m_PSInfoSBR->qmLimBoost[m]; + } + } + + /* see 4.6.18.7.6 */ + XBuf = m_PSInfoSBR->XBuf[i + HF_ADJ][sbrFreq->kStart]; + gbMask = 0; + for(m = 0; m < sbrFreq->numQMFBands; m++) { + if(env == m_PSInfoSBR->la || env == sbrChan->laPrev) { + /* no smoothing filter for gain, and qFilt = 0 (only need to do once) */ + if(i == iStart) { + m_PSInfoSBR->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m]; + m_PSInfoSBR->qFiltLast[m] = 0; + } + } + else if(hSL == 0) { + /* no smoothing filter for gain, (only need to do once) */ + if(i == iStart) { + m_PSInfoSBR->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m]; + m_PSInfoSBR->qFiltLast[m] = sbrChan->qTemp[gainNoiseIndex][m]; + } + } + else { + /* apply smoothing filter to gain and noise (after MAX_NUM_SMOOTH_COEFS, it's always the same) */ + if(i - iStart < MAX_NUM_SMOOTH_COEFS) { + gFilt = 0; + qFilt = 0; + idx = gainNoiseIndex; + for(j = 0; j < MAX_NUM_SMOOTH_COEFS; j++) { + /* sum(abs(hSmoothCoef[j])) for all j < 1.0 */ + gFilt += MULSHIFT32(sbrChan->gTemp[idx][m], hSmoothCoef[j]); + qFilt += MULSHIFT32(sbrChan->qTemp[idx][m], hSmoothCoef[j]); + idx--; + if(idx < 0) idx += MAX_NUM_SMOOTH_COEFS; + } + m_PSInfoSBR->gFiltLast[m] = gFilt << 1; /* restore to Q(FBITS_GLIM_BOOST) (gain of filter < 1.0, so no overflow) */ + m_PSInfoSBR->qFiltLast[m] = qFilt << 1; /* restore to Q(FBITS_QLIM_BOOST) */ + } + } + + if(m_PSInfoSBR->smBoost[m] != 0) { + /* add scaled signal and sinusoid, don't add noise (qFilt = 0) */ + smre = m_PSInfoSBR->smBoost[m]; + smim = smre; + + /* sinIndex: [0] xre += sm [1] xim += sm*s [2] xre -= sm [3] xim -= sm*s */ + s = (sinIndex >> 1); /* if 2 or 3, flip sign to subtract sm */ + s <<= 31; + smre ^= (s >> 31); + smre -= (s >> 31); + s ^= ((m + sbrFreq->kStart) << 31); + smim ^= (s >> 31); + smim -= (s >> 31); + + /* if sinIndex == 0 or 2, smim = 0; if sinIndex == 1 or 3, smre = 0 */ + s = sinIndex << 31; + smim &= (s >> 31); + s ^= 0x80000000; + smre &= (s >> 31); + + noiseTabIndex += 2; /* noise filtered by 0, but still need to bump index */ + } + else { + /* add scaled signal and scaled noise */ + qFilt = m_PSInfoSBR->qFiltLast[m]; + n = noiseTab[noiseTabIndex++]; + smre = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA); + + n = noiseTab[noiseTabIndex++]; + smim = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA); + } + noiseTabIndex &= 1023; /* 512 complex numbers */ + + gFilt = m_PSInfoSBR->gFiltLast[m]; + xre = MULSHIFT32(gFilt, XBuf[0]); + xim = MULSHIFT32(gFilt, XBuf[1]); + xre = CLIP_2N_SHIFT30(xre, 32 - FBITS_GLIM_BOOST); + xim = CLIP_2N_SHIFT30(xim, 32 - FBITS_GLIM_BOOST); + + xre += smre; + *XBuf++ = xre; + xim += smim; + *XBuf++ = xim; + + gbMask |= FASTABS(xre); + gbMask |= FASTABS(xim); + } + /* update circular buffer index */ + gainNoiseIndex++; + if(gainNoiseIndex == MAX_NUM_SMOOTH_COEFS) gainNoiseIndex = 0; + + sinIndex++; + sinIndex &= 3; + + /* ensure MIN_GBITS_IN_QMFS guard bits in output + * almost never occurs in practice, but checking here makes synth QMF logic very simple + */ + if(gbMask >> (31 - MIN_GBITS_IN_QMFS)) { + XBuf = m_PSInfoSBR->XBuf[i + HF_ADJ][sbrFreq->kStart]; + for(m = 0; m < sbrFreq->numQMFBands; m++) { + xre = XBuf[0]; + xim = XBuf[1]; + xre = CLIP_2N(xre, (31 - MIN_GBITS_IN_QMFS)); + xim = CLIP_2N(xim, (31 - MIN_GBITS_IN_QMFS)); + *XBuf++ = xre; + *XBuf++ = xim; + } + gbMask = CLIP_2N(gbMask, (31 - MIN_GBITS_IN_QMFS)); + } + gbIdx = ((i + HF_ADJ) >> 5) & 0x01; + sbrChan->gbMask[gbIdx] |= gbMask; + } + sbrChan->noiseTabIndex = noiseTabIndex; + sbrChan->sinIndex = sinIndex; + sbrChan->gainNoiseIndex = gainNoiseIndex; +} +/*********************************************************************************************************************** + * Function: AdjustHighFreq + * + * Description: adjust high frequencies and add noise and sinusoids (4.6.18.7) + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * + * Outputs: complete reconstructed subband QMF samples for this channel + * + * Return: none + **********************************************************************************************************************/ +void AdjustHighFreq(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch) { + + int32_t i, env, hfReset; + uint8_t frameClass, pointer; + + frameClass = sbrGrid->frameClass; + pointer = sbrGrid->pointer; + + /* derive la from table 4.159 */ + if ((frameClass == SBR_GRID_FIXVAR || frameClass == SBR_GRID_VARVAR) && pointer > 0) + m_PSInfoSBR->la = sbrGrid->numEnv + 1 - pointer; + else if (frameClass == SBR_GRID_VARFIX && pointer > 1) + m_PSInfoSBR->la = pointer - 1; + else + m_PSInfoSBR->la = -1; + + /* for each envelope, estimate gain and adjust SBR QMF bands */ + hfReset = sbrChan->reset; + for (env = 0; env < sbrGrid->numEnv; env++) { + EstimateEnvelope(sbrHdr, sbrGrid, sbrFreq, env); + CalcGain(sbrHdr, sbrGrid, sbrFreq, sbrChan, ch, env); + MapHF(sbrHdr, sbrGrid, sbrFreq, sbrChan, env, hfReset); + hfReset = 0; /* only set for first envelope after header reset */ + } + + /* set saved sine flags to 0 for QMF bands outside of current frequency range */ + for (i = 0; i < sbrFreq->freqLimiter[0] + sbrFreq->kStart; i++) + sbrChan->addHarmonic[0][i] = 0; + for (i = sbrFreq->freqLimiter[sbrFreq->nLimiter] + sbrFreq->kStart; i < 64; i++) + sbrChan->addHarmonic[0][i] = 0; + sbrChan->addHarmonicFlag[0] = sbrChan->addHarmonicFlag[1]; + + /* save la for next frame */ + if (m_PSInfoSBR->la == sbrGrid->numEnv) + sbrChan->laPrev = 0; + else + sbrChan->laPrev = -1; +} +/*********************************************************************************************************************** + * Function: CalcCovariance1 + * + * Description: calculate covariance matrix for p01, p12, p11, p22 (4.6.18.6.2) + * + * Inputs: buffer of low-freq samples, starting at time index 0, + * freq index = patch subband + * + * Outputs: complex covariance elements p01re, p01im, p12re, p12im, p11re, p22re + * (p11im = p22im = 0) + * format = integer (Q0) * 2^N, with scalefactor N >= 0 + * + * Return: scalefactor N + * + * Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits) + **********************************************************************************************************************/ +int32_t CalcCovariance1(int32_t *XBuf, int32_t *p01reN, int32_t *p01imN, int32_t *p12reN, int32_t *p12imN, int32_t *p11reN, int32_t *p22reN) { + + int32_t accBuf[2*6]; + int32_t n, z, s, loShift, hiShift, gbMask; + U64 p01re, p01im, p12re, p12im, p11re, p22re; + + CVKernel1(XBuf, accBuf); + p01re.r.lo32 = accBuf[0]; p01re.r.hi32 = accBuf[1]; + p01im.r.lo32 = accBuf[2]; p01im.r.hi32 = accBuf[3]; + p11re.r.lo32 = accBuf[4]; p11re.r.hi32 = accBuf[5]; + p12re.r.lo32 = accBuf[6]; p12re.r.hi32 = accBuf[7]; + p12im.r.lo32 = accBuf[8]; p12im.r.hi32 = accBuf[9]; + p22re.r.lo32 = accBuf[10]; p22re.r.hi32 = accBuf[11]; + + /* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits + * want to scale them down to integers (32-bit signed, Q0) + * with scale factor of 2^n, n >= 0 + * leave 2 GB's for calculating determinant, so take top 30 non-zero bits + */ + gbMask = ((p01re.r.hi32) ^ (p01re.r.hi32 >> 31)) | ((p01im.r.hi32) ^ (p01im.r.hi32 >> 31)); + gbMask |= ((p12re.r.hi32) ^ (p12re.r.hi32 >> 31)) | ((p12im.r.hi32) ^ (p12im.r.hi32 >> 31)); + gbMask |= ((p11re.r.hi32) ^ (p11re.r.hi32 >> 31)) | ((p22re.r.hi32) ^ (p22re.r.hi32 >> 31)); + if (gbMask == 0) { + s = p01re.r.hi32 >> 31; gbMask = (p01re.r.lo32 ^ s) - s; + s = p01im.r.hi32 >> 31; gbMask |= (p01im.r.lo32 ^ s) - s; + s = p12re.r.hi32 >> 31; gbMask |= (p12re.r.lo32 ^ s) - s; + s = p12im.r.hi32 >> 31; gbMask |= (p12im.r.lo32 ^ s) - s; + s = p11re.r.hi32 >> 31; gbMask |= (p11re.r.lo32 ^ s) - s; + s = p22re.r.hi32 >> 31; gbMask |= (p22re.r.lo32 ^ s) - s; + z = 32 + CLZ(gbMask); + } else { + gbMask = FASTABS(p01re.r.hi32) | FASTABS(p01im.r.hi32); + gbMask |= FASTABS(p12re.r.hi32) | FASTABS(p12im.r.hi32); + gbMask |= FASTABS(p11re.r.hi32) | FASTABS(p22re.r.hi32); + z = CLZ(gbMask); + } + + n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */ + if (n <= 30) { + loShift = (30 - n); + *p01reN = p01re.r.lo32 << loShift; *p01imN = p01im.r.lo32 << loShift; + *p12reN = p12re.r.lo32 << loShift; *p12imN = p12im.r.lo32 << loShift; + *p11reN = p11re.r.lo32 << loShift; *p22reN = p22re.r.lo32 << loShift; + return -(loShift + 2*FBITS_OUT_QMFA); + } else if (n < 32 + 30) { + loShift = (n - 30); + hiShift = 32 - loShift; + *p01reN = (p01re.r.hi32 << hiShift) | (p01re.r.lo32 >> loShift); + *p01imN = (p01im.r.hi32 << hiShift) | (p01im.r.lo32 >> loShift); + *p12reN = (p12re.r.hi32 << hiShift) | (p12re.r.lo32 >> loShift); + *p12imN = (p12im.r.hi32 << hiShift) | (p12im.r.lo32 >> loShift); + *p11reN = (p11re.r.hi32 << hiShift) | (p11re.r.lo32 >> loShift); + *p22reN = (p22re.r.hi32 << hiShift) | (p22re.r.lo32 >> loShift); + return (loShift - 2*FBITS_OUT_QMFA); + } else { + hiShift = n - (32 + 30); + *p01reN = p01re.r.hi32 >> hiShift; *p01imN = p01im.r.hi32 >> hiShift; + *p12reN = p12re.r.hi32 >> hiShift; *p12imN = p12im.r.hi32 >> hiShift; + *p11reN = p11re.r.hi32 >> hiShift; *p22reN = p22re.r.hi32 >> hiShift; + return (32 - 2*FBITS_OUT_QMFA - hiShift); + } + + return 0; +} +/*********************************************************************************************************************** + * Function: CalcCovariance2 + * + * Description: calculate covariance matrix for p02 (4.6.18.6.2) + * + * Inputs: buffer of low-freq samples, starting at time index = 0, + * freq index = patch subband + * + * Outputs: complex covariance element p02re, p02im + * format = integer (Q0) * 2^N, with scalefactor N >= 0 + * + * Return: scalefactor N + * + * Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits) + **********************************************************************************************************************/ +int32_t CalcCovariance2(int32_t *XBuf, int32_t *p02reN, int32_t *p02imN) { + + U64 p02re, p02im; + int32_t n, z, s, loShift, hiShift, gbMask; + int32_t accBuf[2*2]; + + CVKernel2(XBuf, accBuf); + p02re.r.lo32 = accBuf[0]; + p02re.r.hi32 = accBuf[1]; + p02im.r.lo32 = accBuf[2]; + p02im.r.hi32 = accBuf[3]; + + /* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits + * want to scale them down to integers (32-bit signed, Q0) + * with scale factor of 2^n, n >= 0 + * leave 1 GB for calculating determinant, so take top 30 non-zero bits + */ + gbMask = ((p02re.r.hi32) ^ (p02re.r.hi32 >> 31)) | ((p02im.r.hi32) ^ (p02im.r.hi32 >> 31)); + if (gbMask == 0) { + s = p02re.r.hi32 >> 31; gbMask = (p02re.r.lo32 ^ s) - s; + s = p02im.r.hi32 >> 31; gbMask |= (p02im.r.lo32 ^ s) - s; + z = 32 + CLZ(gbMask); + } else { + gbMask = FASTABS(p02re.r.hi32) | FASTABS(p02im.r.hi32); + z = CLZ(gbMask); + } + n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */ + + if (n <= 30) { + loShift = (30 - n); + *p02reN = p02re.r.lo32 << loShift; + *p02imN = p02im.r.lo32 << loShift; + return -(loShift + 2*FBITS_OUT_QMFA); + } else if (n < 32 + 30) { + loShift = (n - 30); + hiShift = 32 - loShift; + *p02reN = (p02re.r.hi32 << hiShift) | (p02re.r.lo32 >> loShift); + *p02imN = (p02im.r.hi32 << hiShift) | (p02im.r.lo32 >> loShift); + return (loShift - 2*FBITS_OUT_QMFA); + } else { + hiShift = n - (32 + 30); + *p02reN = p02re.r.hi32 >> hiShift; + *p02imN = p02im.r.hi32 >> hiShift; + return (32 - 2*FBITS_OUT_QMFA - hiShift); + } + + return 0; +} +/*********************************************************************************************************************** + * Function: CalcLPCoefs + * + * Description: calculate linear prediction coefficients for one subband (4.6.18.6.2) + * + * Inputs: buffer of low-freq samples, starting at time index = 0, + * freq index = patch subband + * number of guard bits in input sample buffer + * + * Outputs: complex LP coefficients a0re, a0im, a1re, a1im, format = Q29 + * + * Return: none + * + * Notes: output coefficients (a0re, a0im, a1re, a1im) clipped to range (-4, 4) + * if the comples coefficients have magnitude >= 4.0, they are all + * set to 0 (see spec) + **********************************************************************************************************************/ +void CalcLPCoefs(int32_t *XBuf, int32_t *a0re, int32_t *a0im, int32_t *a1re, int32_t *a1im, int32_t gb) { + + int32_t zFlag, n1, n2, nd, d, dInv, tre, tim; + int32_t p01re, p01im, p02re, p02im, p12re, p12im, p11re, p22re; + + /* pre-scale to avoid overflow - probably never happens in practice (see QMFA) + * max bit growth per accumulator = 38*2 = 76 mul-adds (X * X) + * using 64-bit MADD, so if X has n guard bits, X*X has 2n+1 guard bits + * gain 1 extra sign bit per multiply, so ensure ceil(log2(76/2) / 2) = 3 guard bits on inputs + */ + if (gb < 3) { + nd = 3 - gb; + for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) { + XBuf[0] >>= nd; XBuf[1] >>= nd; + XBuf += (2*64); + } + XBuf -= (2*64*(NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2)); + } + + /* calculate covariance elements */ + n1 = CalcCovariance1(XBuf, &p01re, &p01im, &p12re, &p12im, &p11re, &p22re); + n2 = CalcCovariance2(XBuf, &p02re, &p02im); + + /* normalize everything to larger power of 2 scalefactor, call it n1 */ + if (n1 < n2) { + nd = MIN(n2 - n1, (int32_t)31); + p01re >>= nd; p01im >>= nd; + p12re >>= nd; p12im >>= nd; + p11re >>= nd; p22re >>= nd; + n1 = n2; + } else if (n1 > n2) { + nd = MIN(n1 - n2, (int32_t)31); + p02re >>= nd; p02im >>= nd; + } + + /* calculate determinant of covariance matrix (at least 1 GB in pXX) */ + d = MULSHIFT32(p12re, p12re) + MULSHIFT32(p12im, p12im); + d = MULSHIFT32(d, RELAX_COEF) << 1; + d = MULSHIFT32(p11re, p22re) - d; + ASSERT(d >= 0); /* should never be < 0 */ + + zFlag = 0; + *a0re = *a0im = 0; + *a1re = *a1im = 0; + if (d > 0) { + /* input = Q31 d = Q(-2*n1 - 32 + nd) = Q31 * 2^(31 + 2*n1 + 32 - nd) + * inverse = Q29 dInv = Q29 * 2^(-31 - 2*n1 - 32 + nd) = Q(29 + 31 + 2*n1 + 32 - nd) + * + * numerator has same Q format as d, since it's sum of normalized squares + * so num * inverse = Q(-2*n1 - 32) * Q(29 + 31 + 2*n1 + 32 - nd) + * = Q(29 + 31 - nd), drop low 32 in MULSHIFT32 + * = Q(29 + 31 - 32 - nd) = Q(28 - nd) + */ + nd = CLZ(d) - 1; + d <<= nd; + dInv = InvRNormalized(d); + + /* 1 GB in pXX */ + tre = MULSHIFT32(p01re, p12re) - MULSHIFT32(p01im, p12im) - MULSHIFT32(p02re, p11re); + tre = MULSHIFT32(tre, dInv); + tim = MULSHIFT32(p01re, p12im) + MULSHIFT32(p01im, p12re) - MULSHIFT32(p02im, p11re); + tim = MULSHIFT32(tim, dInv); + + /* if d is extremely small, just set coefs to 0 (would have poor precision anyway) */ + if (nd > 28 || (FASTABS(tre) >> (28 - nd)) >= 4 || (FASTABS(tim) >> (28 - nd)) >= 4) { + zFlag = 1; + } else { + *a1re = tre << (FBITS_LPCOEFS - 28 + nd); /* i.e. convert Q(28 - nd) to Q(29) */ + *a1im = tim << (FBITS_LPCOEFS - 28 + nd); + } + } + + if (p11re) { + /* input = Q31 p11re = Q(-n1 + nd) = Q31 * 2^(31 + n1 - nd) + * inverse = Q29 dInv = Q29 * 2^(-31 - n1 + nd) = Q(29 + 31 + n1 - nd) + * + * numerator is Q(-n1 - 3) + * so num * inverse = Q(-n1 - 3) * Q(29 + 31 + n1 - nd) + * = Q(29 + 31 - 3 - nd), drop low 32 in MULSHIFT32 + * = Q(29 + 31 - 3 - 32 - nd) = Q(25 - nd) + */ + nd = CLZ(p11re) - 1; /* assume positive */ + p11re <<= nd; + dInv = InvRNormalized(p11re); + + /* a1re, a1im = Q29, so scaled by (n1 + 3) */ + tre = (p01re >> 3) + MULSHIFT32(p12re, *a1re) + MULSHIFT32(p12im, *a1im); + tre = -MULSHIFT32(tre, dInv); + tim = (p01im >> 3) - MULSHIFT32(p12im, *a1re) + MULSHIFT32(p12re, *a1im); + tim = -MULSHIFT32(tim, dInv); + + if (nd > 25 || (FASTABS(tre) >> (25 - nd)) >= 4 || (FASTABS(tim) >> (25 - nd)) >= 4) { + zFlag = 1; + } else { + *a0re = tre << (FBITS_LPCOEFS - 25 + nd); /* i.e. convert Q(25 - nd) to Q(29) */ + *a0im = tim << (FBITS_LPCOEFS - 25 + nd); + } + } + + /* see 4.6.18.6.2 - if magnitude of a0 or a1 >= 4 then a0 = a1 = 0 + * i.e. a0re < 4, a0im < 4, a1re < 4, a1im < 4 + * Q29*Q29 = Q26 + */ + if (zFlag || MULSHIFT32(*a0re, *a0re) + MULSHIFT32(*a0im, *a0im) >= MAG_16 || MULSHIFT32(*a1re, *a1re) + MULSHIFT32(*a1im, *a1im) >= MAG_16) { + *a0re = *a0im = 0; + *a1re = *a1im = 0; + } + + /* no need to clip - we never changed the XBuf data, just used it to calculate a0 and a1 */ + if (gb < 3) { + nd = 3 - gb; + for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) { + XBuf[0] <<= nd; XBuf[1] <<= nd; + XBuf += (2*64); + } + } +} +/*********************************************************************************************************************** + * Function: GenerateHighFreq + * + * Description: generate high frequencies with SBR (4.6.18.6) + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * + * Outputs: new high frequency samples starting at frequency kStart + * + * Return: none + **********************************************************************************************************************/ +void GenerateHighFreq(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch) { + + int32_t band, newBW, c, t, gb, gbMask, gbIdx; + int32_t currPatch, p, x, k, g, i, iStart, iEnd, bw, bwsq; + int32_t a0re, a0im, a1re, a1im; + int32_t x1re, x1im, x2re, x2im; + int32_t ACCre, ACCim; + int32_t *XBufLo, *XBufHi; + (void) ch; + + /* calculate array of chirp factors */ + for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) { + c = sbrChan->chirpFact[band]; /* previous (bwArray') */ + newBW = newBWTab[sbrChan->invfMode[0][band]][sbrChan->invfMode[1][band]]; + + /* weighted average of new and old (can't overflow - total gain = 1.0) */ + if (newBW < c) + t = MULSHIFT32(newBW, 0x60000000) + MULSHIFT32(0x20000000, c); /* new is smaller: 0.75*new + 0.25*old */ + else + t = MULSHIFT32(newBW, 0x74000000) + MULSHIFT32(0x0c000000, c); /* new is larger: 0.90625*new + 0.09375*old */ + t <<= 1; + + if (t < 0x02000000) /* below 0.015625, clip to 0 */ + t = 0; + if (t > 0x7f800000) /* clip to 0.99609375 */ + t = 0x7f800000; + + /* save curr as prev for next time */ + sbrChan->chirpFact[band] = t; + sbrChan->invfMode[0][band] = sbrChan->invfMode[1][band]; + } + + iStart = sbrGrid->envTimeBorder[0] + HF_ADJ; + iEnd = sbrGrid->envTimeBorder[sbrGrid->numEnv] + HF_ADJ; + + /* generate new high freqs from low freqs, patches, and chirp factors */ + k = sbrFreq->kStart; + g = 0; + bw = sbrChan->chirpFact[g]; + bwsq = MULSHIFT32(bw, bw) << 1; + + gbMask = (sbrChan->gbMask[0] | sbrChan->gbMask[1]); /* older 32 | newer 8 */ + gb = CLZ(gbMask) - 1; + + for (currPatch = 0; currPatch < sbrFreq->numPatches; currPatch++) { + for (x = 0; x < sbrFreq->patchNumSubbands[currPatch]; x++) { + /* map k to corresponding noise floor band */ + if (k >= sbrFreq->freqNoise[g+1]) { + g++; + bw = sbrChan->chirpFact[g]; /* Q31 */ + bwsq = MULSHIFT32(bw, bw) << 1; /* Q31 */ + } + + p = sbrFreq->patchStartSubband[currPatch] + x; /* low QMF band */ + XBufHi = m_PSInfoSBR->XBuf[iStart][k]; + if (bw) { + CalcLPCoefs(m_PSInfoSBR->XBuf[0][p], &a0re, &a0im, &a1re, &a1im, gb); + + a0re = MULSHIFT32(bw, a0re); /* Q31 * Q29 = Q28 */ + a0im = MULSHIFT32(bw, a0im); + a1re = MULSHIFT32(bwsq, a1re); + a1im = MULSHIFT32(bwsq, a1im); + + XBufLo = m_PSInfoSBR->XBuf[iStart-2][p]; + + x2re = XBufLo[0]; /* RE{XBuf[n-2]} */ + x2im = XBufLo[1]; /* IM{XBuf[n-2]} */ + XBufLo += (64*2); + + x1re = XBufLo[0]; /* RE{XBuf[n-1]} */ + x1im = XBufLo[1]; /* IM{XBuf[n-1]} */ + XBufLo += (64*2); + + for (i = iStart; i < iEnd; i++) { + /* a0re/im, a1re/im are Q28 with at least 1 GB, + * so the summing for AACre/im is fine (1 GB in, plus 1 from MULSHIFT32) + */ + ACCre = MULSHIFT32(x2re, a1re) - MULSHIFT32(x2im, a1im); + ACCim = MULSHIFT32(x2re, a1im) + MULSHIFT32(x2im, a1re); + x2re = x1re; + x2im = x1im; + + ACCre += MULSHIFT32(x1re, a0re) - MULSHIFT32(x1im, a0im); + ACCim += MULSHIFT32(x1re, a0im) + MULSHIFT32(x1im, a0re); + x1re = XBufLo[0]; /* RE{XBuf[n]} */ + x1im = XBufLo[1]; /* IM{XBuf[n]} */ + XBufLo += (64*2); + + /* lost 4 fbits when scaling by a0re/im, a1re/im (Q28) */ + ACCre = CLIP_2N_SHIFT30(ACCre, 4); + ACCre += x1re; + ACCim = CLIP_2N_SHIFT30(ACCim, 4); + ACCim += x1im; + + XBufHi[0] = ACCre; + XBufHi[1] = ACCim; + XBufHi += (64*2); + + /* update guard bit masks */ + gbMask = FASTABS(ACCre); + gbMask |= FASTABS(ACCim); + gbIdx = (i >> 5) & 0x01; /* 0 if i < 32, 1 if i >= 32 */ + sbrChan->gbMask[gbIdx] |= gbMask; + } + } else { + XBufLo = (int32_t *)m_PSInfoSBR->XBuf[iStart][p]; + for (i = iStart; i < iEnd; i++) { + XBufHi[0] = XBufLo[0]; + XBufHi[1] = XBufLo[1]; + XBufLo += (64*2); + XBufHi += (64*2); + } + } + k++; /* high QMF band */ + } + } +} +/*********************************************************************************************************************** + * Function: DecodeHuffmanScalar + * + * Description: decode one Huffman symbol from bitstream + * + * Inputs: pointers to Huffman table and info struct + * left-aligned bit buffer with >= huffTabInfo->maxBits bits + * + * Outputs: decoded symbol in *val + * + * Return: number of bits in symbol + * + * Notes: assumes canonical Huffman codes: + * first CW always 0, we have "count" CW's of length "nBits" bits + * starting CW for codes of length nBits+1 = + * (startCW[nBits] + count[nBits]) << 1 + * if there are no codes at nBits, then we just keep << 1 each time + * (since count[nBits] = 0) + **********************************************************************************************************************/ +int32_t DecodeHuffmanScalar(const int16_t *huffTab, const HuffInfo_t *huffTabInfo, uint32_t bitBuf, + int32_t *val) { + + uint32_t count, start, shift, t; + const uint8_t *countPtr; + const int16_t *map; + + map = huffTab + huffTabInfo->offset; + countPtr = huffTabInfo->count; + + start = 0; + count = 0; + shift = 32; + do { + start += count; + start <<= 1; + map += count; + count = *countPtr++; + shift--; + t = (bitBuf >> shift) - start; + } while(t >= count); + + *val = (int32_t) map[t]; + return (countPtr - huffTabInfo->count); +} +/*********************************************************************************************************************** + * Function: DecodeOneSymbol + * + * Description: dequantize one Huffman symbol from bitstream, + * using table huffTabSBR[huffTabIndex] + * + * Inputs: index of Huffman table + * + * Outputs: bitstream advanced by number of bits in codeword + * + * Return: one decoded symbol + **********************************************************************************************************************/ +int32_t DecodeOneSymbol(int32_t huffTabIndex) { + + int32_t nBits, val; + uint32_t bitBuf; + const HuffInfo_t *hi; + + hi = &(huffTabSBRInfo[huffTabIndex]); + + bitBuf = GetBitsNoAdvance(hi->maxBits) << (32 - hi->maxBits); + nBits = DecodeHuffmanScalar(huffTabSBR, hi, bitBuf, &val); + AdvanceBitstream(nBits); + + return val; +} + +/* [1.0, sqrt(2)], format = Q29 (one guard bit for decoupling) */ +static const int32_t envDQTab[2] PROGMEM = {0x20000000, 0x2d413ccc}; + +/*********************************************************************************************************************** + * Function: DequantizeEnvelope + * + * Description: dequantize envelope scalefactors + * + * Inputs: number of scalefactors to process + * amplitude resolution flag for this frame (0 or 1) + * quantized envelope scalefactors + * + * Outputs: dequantized envelope scalefactors + * + * Return: extra int32_t bits in output (6 + expMax) + * in other words, output format = Q(FBITS_OUT_DQ_ENV - (6 + expMax)) + * + * Notes: dequantized scalefactors have at least 2 GB + **********************************************************************************************************************/ +int32_t DequantizeEnvelope(int32_t nBands, int32_t ampRes, int8_t *envQuant, int32_t *envDequant) { + + int32_t exp, expMax, i, scalei; + + if(nBands <= 0) return 0; + + /* scan for largest dequant value (do separately from envelope decoding to keep code cleaner) */ + expMax = 0; + for(i = 0; i < nBands; i++) { + if(envQuant[i] > expMax) expMax = envQuant[i]; + } + + /* dequantized envelope gains + * envDequant = 64*2^(envQuant / alpha) = 2^(6 + envQuant / alpha) + * if ampRes == 0, alpha = 2 and range of envQuant = [0, 127] + * if ampRes == 1, alpha = 1 and range of envQuant = [0, 63] + * also if coupling is on, envDequant is scaled by something in range [0, 2] + * so range of envDequant = [2^6, 2^69] (no coupling), [2^6, 2^70] (with coupling) + * + * typical range (from observation) of envQuant/alpha = [0, 27] --> largest envQuant ~= 2^33 + * output: Q(29 - (6 + expMax)) + * + * reference: 14496-3:2001(E)/4.6.18.3.5 and 14496-4:200X/FPDAM8/5.6.5.1.2.1.5 + */ + if(ampRes) { + do { + exp = *envQuant++; + scalei = MIN(expMax - exp, (int32_t)31); + *envDequant++ = envDQTab[0] >> scalei; + } while(--nBands); + + return (6 + expMax); + } + else { + expMax >>= 1; + do { + exp = *envQuant++; + scalei = MIN(expMax - (exp >> 1), (int32_t)31); + *envDequant++ = envDQTab[exp & 0x01] >> scalei; + } while(--nBands); + + return (6 + expMax); + } + +} +/*********************************************************************************************************************** + * Function: DequantizeNoise + * + * Description: dequantize noise scalefactors + * + * Inputs: number of scalefactors to process + * quantized noise scalefactors + * + * Outputs: dequantized noise scalefactors, format = Q(FBITS_OUT_DQ_NOISE) + * + * Return: none + * + * Notes: dequantized scalefactors have at least 2 GB + **********************************************************************************************************************/ +void DequantizeNoise(int32_t nBands, int8_t *noiseQuant, int32_t *noiseDequant) { + + int32_t exp, scalei; + + if(nBands <= 0) return; + + /* dequantize noise floor gains (4.6.18.3.5): + * noiseDequant = 2^(NOISE_FLOOR_OFFSET - noiseQuant) + * + * range of noiseQuant = [0, 30] (see 4.6.18.3.6), NOISE_FLOOR_OFFSET = 6 + * so range of noiseDequant = [2^-24, 2^6] + */ + do { + exp = *noiseQuant++; + scalei = NOISE_FLOOR_OFFSET - exp + FBITS_OUT_DQ_NOISE; /* 6 + 24 - exp, exp = [0,30] */ + + if(scalei < 0) + *noiseDequant++ = 0; + else if(scalei < 30) + *noiseDequant++ = 1 << scalei; + else + *noiseDequant++ = 0x3fffffff; /* leave 2 GB */ + + } while(--nBands); +} +/*********************************************************************************************************************** + * Function: DecodeSBREnvelope + * + * Description: decode delta Huffman coded envelope scalefactors from bitstream + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * + * Outputs: dequantized env scalefactors for left channel (before decoupling) + * dequantized env scalefactors for right channel (if coupling off) + * or raw decoded env scalefactors for right channel (if coupling on) + * + * Return: none + **********************************************************************************************************************/ +void DecodeSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch) { + + int32_t huffIndexTime, huffIndexFreq, env, envStartBits, band, nBands, sf, lastEnv; + int32_t freqRes, freqResPrev, dShift, i; + + if(m_PSInfoSBR->couplingFlag && ch) { + dShift = 1; + if(sbrGrid->ampResFrame) { + huffIndexTime = HuffTabSBR_tEnv30b; + huffIndexFreq = HuffTabSBR_fEnv30b; + envStartBits = 5; + } + else { + huffIndexTime = HuffTabSBR_tEnv15b; + huffIndexFreq = HuffTabSBR_fEnv15b; + envStartBits = 6; + } + } + else { + dShift = 0; + if(sbrGrid->ampResFrame) { + huffIndexTime = HuffTabSBR_tEnv30; + huffIndexFreq = HuffTabSBR_fEnv30; + envStartBits = 6; + } + else { + huffIndexTime = HuffTabSBR_tEnv15; + huffIndexFreq = HuffTabSBR_fEnv15; + envStartBits = 7; + } + } + + /* range of envDataQuant[] = [0, 127] (see comments in DequantizeEnvelope() for reference) */ + for(env = 0; env < sbrGrid->numEnv; env++) { + nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow); + freqRes = (sbrGrid->freqRes[env]); + freqResPrev = (env == 0 ? sbrGrid->freqResPrev : sbrGrid->freqRes[env - 1]); + lastEnv = (env == 0 ? sbrGrid->numEnvPrev - 1 : env - 1); + if(lastEnv < 0) lastEnv = 0; /* first frame */ + + ASSERT(nBands <= MAX_QMF_BANDS); + + if(sbrChan->deltaFlagEnv[env] == 0) { + /* delta coding in freq */ + sf = GetBits(envStartBits) << dShift; + sbrChan->envDataQuant[env][0] = sf; + for(band = 1; band < nBands; band++) { + sf = DecodeOneSymbol(huffIndexFreq) << dShift; + sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[env][band - 1]; + } + } + else if(freqRes == freqResPrev) { + /* delta coding in time - same freq resolution for both frames */ + for(band = 0; band < nBands; band++) { + sf = DecodeOneSymbol(huffIndexTime) << dShift; + sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[lastEnv][band]; + } + } + else if(freqRes == 0 && freqResPrev == 1) { + /* delta coding in time - low freq resolution for new frame, high freq resolution for old frame */ + for(band = 0; band < nBands; band++) { + sf = DecodeOneSymbol(huffIndexTime) << dShift; + sbrChan->envDataQuant[env][band] = sf; + for(i = 0; i < sbrFreq->nHigh; i++) { + if(sbrFreq->freqHigh[i] == sbrFreq->freqLow[band]) { + sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i]; + break; + } + } + } + } + else if(freqRes == 1 && freqResPrev == 0) { + /* delta coding in time - high freq resolution for new frame, low freq resolution for old frame */ + for(band = 0; band < nBands; band++) { + sf = DecodeOneSymbol(huffIndexTime) << dShift; + sbrChan->envDataQuant[env][band] = sf; + for(i = 0; i < sbrFreq->nLow; i++) { + if(sbrFreq->freqLow[i] <= sbrFreq->freqHigh[band] + && sbrFreq->freqHigh[band] < sbrFreq->freqLow[i + 1]) { + sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i]; + break; + } + } + } + } + + /* skip coupling channel */ + if(ch != 1 || m_PSInfoSBR->couplingFlag != 1) + m_PSInfoSBR->envDataDequantScale[ch][env] = DequantizeEnvelope(nBands, sbrGrid->ampResFrame, + sbrChan->envDataQuant[env], m_PSInfoSBR->envDataDequant[ch][env]); + } + sbrGrid->numEnvPrev = sbrGrid->numEnv; + sbrGrid->freqResPrev = sbrGrid->freqRes[sbrGrid->numEnv - 1]; +} +/*********************************************************************************************************************** + * Function: DecodeSBRNoise + * + * Description: decode delta Huffman coded noise scalefactors from bitstream + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel + * index of current channel (0 for SCE, 0 or 1 for CPE) + * + * Outputs: dequantized noise scalefactors for left channel (before decoupling) + * dequantized noise scalefactors for right channel (if coupling off) + * or raw decoded noise scalefactors for right channel (if coupling on) + * + * Return: none + **********************************************************************************************************************/ +void DecodeSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch) { + + int32_t huffIndexTime, huffIndexFreq, noiseFloor, band, dShift, sf, lastNoiseFloor; + + if(m_PSInfoSBR->couplingFlag && ch) { + dShift = 1; + huffIndexTime = HuffTabSBR_tNoise30b; + huffIndexFreq = HuffTabSBR_fNoise30b; + } + else { + dShift = 0; + huffIndexTime = HuffTabSBR_tNoise30; + huffIndexFreq = HuffTabSBR_fNoise30; + } + + for(noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) { + lastNoiseFloor = (noiseFloor == 0 ? sbrGrid->numNoiseFloorsPrev - 1 : noiseFloor - 1); + if(lastNoiseFloor < 0) lastNoiseFloor = 0; /* first frame */ + + ASSERT(sbrFreq->numNoiseFloorBands <= MAX_QMF_BANDS); + + if(sbrChan->deltaFlagNoise[noiseFloor] == 0) { + /* delta coding in freq */ + sbrChan->noiseDataQuant[noiseFloor][0] = GetBits(5) << dShift; + for(band = 1; band < sbrFreq->numNoiseFloorBands; band++) { + sf = DecodeOneSymbol(huffIndexFreq) << dShift; + sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[noiseFloor][band - 1]; + } + } + else { + /* delta coding in time */ + for(band = 0; band < sbrFreq->numNoiseFloorBands; band++) { + sf = DecodeOneSymbol(huffIndexTime) << dShift; + sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[lastNoiseFloor][band]; + } + } + + /* skip coupling channel */ + if(ch != 1 || m_PSInfoSBR->couplingFlag != 1) + DequantizeNoise(sbrFreq->numNoiseFloorBands, sbrChan->noiseDataQuant[noiseFloor], + m_PSInfoSBR->noiseDataDequant[ch][noiseFloor]); + } + sbrGrid->numNoiseFloorsPrev = sbrGrid->numNoiseFloors; +} + +/* dqTabCouple[i] = 2 / (1 + 2^(12 - i)), format = Q30 */ +static const int32_t dqTabCouple[25] PROGMEM = { + 0x0007ff80, 0x000ffe00, 0x001ff802, 0x003fe010, 0x007f8080, 0x00fe03f8, 0x01f81f82, 0x03e0f83e, + 0x07878788, 0x0e38e38e, 0x1999999a, 0x2aaaaaab, 0x40000000, 0x55555555, 0x66666666, 0x71c71c72, + 0x78787878, 0x7c1f07c2, 0x7e07e07e, 0x7f01fc08, 0x7f807f80, 0x7fc01ff0, 0x7fe007fe, 0x7ff00200, + 0x7ff80080, +}; + +/*********************************************************************************************************************** + * Function: UncoupleSBREnvelope + * + * Description: scale dequantized envelope scalefactors according to channel + * coupling rules + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for right channel including + * quantized envelope scalefactors + * + * Outputs: dequantized envelope data for left channel (after decoupling) + * dequantized envelope data for right channel (after decoupling) + * + * Return: none + **********************************************************************************************************************/ +void UncoupleSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR) { + + int32_t env, band, nBands, scalei, E_1; + + scalei = (sbrGrid->ampResFrame ? 0 : 1); + for(env = 0; env < sbrGrid->numEnv; env++) { + nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow); + m_PSInfoSBR->envDataDequantScale[1][env] = m_PSInfoSBR->envDataDequantScale[0][env]; + for(band = 0; band < nBands; band++) { + /* clip E_1 to [0, 24] (scalefactors approach 0 or 2) */ + E_1 = sbrChanR->envDataQuant[env][band] >> scalei; + if(E_1 < 0) E_1 = 0; + if(E_1 > 24) E_1 = 24; + + /* envDataDequant[0] has 1 GB, so << by 2 is okay */ + m_PSInfoSBR->envDataDequant[1][env][band] = MULSHIFT32(m_PSInfoSBR->envDataDequant[0][env][band], + dqTabCouple[24 - E_1]) << 2; + m_PSInfoSBR->envDataDequant[0][env][band] = MULSHIFT32(m_PSInfoSBR->envDataDequant[0][env][band], + dqTabCouple[E_1]) << 2; + } + } +} +/*********************************************************************************************************************** + * Function: UncoupleSBRNoise + * + * Description: scale dequantized noise floor scalefactors according to channel + * coupling rules + * + * Inputs: initialized SBRGrid struct for this channel + * initialized SBRFreq struct for this SCE/CPE block + * initialized SBRChan struct for this channel including + * quantized noise scalefactors + * + * Outputs: dequantized noise data for left channel (after decoupling) + * dequantized noise data for right channel (after decoupling) + * + * Return: none + **********************************************************************************************************************/ +void UncoupleSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR) { + + int32_t noiseFloor, band, Q_1; + + for (noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) { + for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) { + /* Q_1 should be in range [0, 24] according to 4.6.18.3.6, but check to make sure */ + Q_1 = sbrChanR->noiseDataQuant[noiseFloor][band]; + if (Q_1 < 0) Q_1 = 0; + if (Q_1 > 24) Q_1 = 24; + + /* noiseDataDequant[0] has 1 GB, so << by 2 is okay */ + m_PSInfoSBR->noiseDataDequant[1][noiseFloor][band] = + MULSHIFT32(m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band], dqTabCouple[24 - Q_1]) << 2; + m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band] = + MULSHIFT32(m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band], dqTabCouple[Q_1]) << 2; + } + } +} +/*********************************************************************************************************************** + * Function: DecWindowOverlapNoClip + * + * Description: apply synthesis window, do overlap-add without clipping, + * for winSequence LONG-LONG + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 32-bit PCM, non-interleaved + * + * Return: none + * + * Notes: use this function when the decoded PCM is going to the SBR decoder + **********************************************************************************************************************/ +void DecWindowOverlapNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev) { + + int32_t in, w0, w1, f0, f1; + int32_t *buf1, *over1, *out1; + const int32_t *wndPrev, *wndCurr; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + out1 = out0 + 1024 - 1; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + if (winTypeCurr == winTypePrev) { + /* cut window loads in half since current and overlap sections use same symmetric window */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } else { + /* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */ + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } +} +/*********************************************************************************************************************** + * Function: DecWindowOverlapLongStart + * + * Description: apply synthesis window, do overlap-add, without clipping + * for winSequence LONG-START + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 32-bit PCM, non-interleaved + * + * Return: none + * + * Notes: use this function when the decoded PCM is going to the SBR decoder + **********************************************************************************************************************/ +void DecWindowOverlapLongStartNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev) { + + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1, *out1; + const int32_t *wndPrev, *wndCurr; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + out1 = out0 + 1024 - 1; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + i = 448; /* 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + in = *buf1--; + + *over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */ + *over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */ + } while (--i); + + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + + /* do 64 more loops - 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; + w1 = *wndPrev++; + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */ + w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */ + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */ + *over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */ + } while (over0 < over1); +} +/*********************************************************************************************************************** + * Function: DecWindowOverlapLongStop + * + * Description: apply synthesis window, do overlap-add, without clipping + * for winSequence LONG-STOP + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 32-bit PCM, non-interleaved + * + * Return: none + * + * Notes: use this function when the decoded PCM is going to the SBR decoder + **********************************************************************************************************************/ +void DecWindowOverlapLongStopNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev) { + + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1, *out1; + const int32_t *wndPrev, *wndCurr; + + buf0 += (1024 >> 1); + buf1 = buf0 - 1; + out1 = out0 + 1024 - 1; + over1 = over0 + 1024 - 1; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); + + i = 448; /* 2 outputs, 2 overlaps per loop */ + do { + /* Wn = 0 for n = (0, 1, ... 447) */ + /* Wn = 1 for n = (576, 577, ... 1023) */ + in = *buf0++; + f1 = in >> 1; /* scale since skipping multiply by Q31 */ + + in = *over0; + *out0++ = in; + + in = *over1; + *out1-- = in + f1; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (--i); + + /* do 64 more loops - 2 outputs, 2 overlaps per loop */ + do { + w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ + w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); +} +/*********************************************************************************************************************** + * Function: DecWindowOverlapShort + * + * Description: apply synthesis window, do overlap-add, without clipping + * for winSequence EIGHT-SHORT (does all 8 short blocks) + * + * Inputs: input buffer (output of type-IV DCT) + * overlap buffer (saved from last time) + * window type (sin or KBD) for input buffer + * window type (sin or KBD) for overlap buffer + * + * Outputs: one channel, one frame of 32-bit PCM, non-interleaved + * + * Return: none + * + * Notes: use this function when the decoded PCM is going to the SBR decoder + **********************************************************************************************************************/ +void DecWindowOverlapShortNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev) { + + int32_t i, in, w0, w1, f0, f1; + int32_t *buf1, *over1, *out1; + const int32_t *wndPrev, *wndCurr; + + wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); + + /* pcm[0-447] = 0 + overlap[0-447] */ + i = 448; + do { + f0 = *over0++; + f1 = *over0++; + *out0++ = f0; + *out0++ = f1; + i -= 2; + } while (i); + + /* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */ + out1 = out0 + (128 - 1); + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + do { + w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ + w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *over0; + *out0++ = in - f0; + + in = *over1; + *out1-- = in + f1; + + w0 = *wndCurr++; + w1 = *wndCurr++; + in = *buf1--; + + /* save over0/over1 for next short block, in the slots just vacated */ + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + + /* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703] + * pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831] + * pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959] + */ + for (i = 0; i < 3; i++) { + out0 += 64; + out1 = out0 + 128 - 1; + over0 += 64; + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *(over0 - 128); /* from last short block */ + in += *(over0 + 0); /* from last full frame */ + *out0++ = in - f0; + + in = *(over1 - 128); /* from last short block */ + in += *(over1 + 0); /* from last full frame */ + *out1-- = in + f1; + + /* save over0/over1 for next short block, in the slots just vacated */ + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } + + /* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023] + * over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127] + */ + out0 += 64; + over0 -= 832; /* points at overlap[64] */ + over1 = over0 + 128 - 1; /* points at overlap[191] */ + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + in = *(over0 + 768); /* from last short block */ + in += *(over0 + 896); /* from last full frame */ + *out0++ = in - f0; + + in = *(over1 + 768); /* from last short block */ + *(over1 - 128) = in + f1; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */ + *over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */ + } while (over0 < over1); + + /* over0 now points at overlap[128] */ + + /* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127] + * over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127] + * over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127] + * over[448-576] = Wc[128-255] * block7[128-255] + */ + for (i = 0; i < 3; i++) { + over0 += 64; + over1 = over0 + 128 - 1; + buf0 += 64; + buf1 = buf0 - 1; + wndCurr -= 128; + do { + w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ + w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ + in = *buf0++; + + f0 = MULSHIFT32(w0, in); + f1 = MULSHIFT32(w1, in); + + /* from last short block */ + *(over0 - 128) -= f0; + *(over1 - 128)+= f1; + + in = *buf1--; + *over1-- = MULSHIFT32(w0, in); + *over0++ = MULSHIFT32(w1, in); + } while (over0 < over1); + } + + /* over[576-1024] = 0 */ + i = 448; + over0 += 64; + do { + *over0++ = 0; + *over0++ = 0; + *over0++ = 0; + *over0++ = 0; + i -= 4; + } while (i); +} +/*********************************************************************************************************************** + * Function: PreMultiply64 + * + * Description: pre-twiddle stage of 64-point DCT-IV + * + * Inputs: buffer of 64 samples + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: minimum 1 GB in, 2 GB out, gains 2 int32_t bits + * gbOut = gbIn + 1 + * output is limited to sqrt(2)/2 plus GB in full GB + * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add + **********************************************************************************************************************/ +void PreMultiply64(int32_t *zbuf1) { + + int32_t i, ar1, ai1, ar2, ai2, z1, z2; + int32_t t, cms2, cps2a, sin2a, cps2b, sin2b; + int32_t *zbuf2; + const int32_t *csptr; + + zbuf2 = zbuf1 + 64 - 1; + csptr = cos4sin4tab64; + + /* whole thing should fit in registers - verify that compiler does this */ + for (i = 64 >> 2; i != 0; i--) { + /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ + cps2a = *csptr++; + sin2a = *csptr++; + cps2b = *csptr++; + sin2b = *csptr++; + + ar1 = *(zbuf1 + 0); + ai2 = *(zbuf1 + 1); + ai1 = *(zbuf2 + 0); + ar2 = *(zbuf2 - 1); + + /* gain 2 ints bit from MULSHIFT32 by Q30 + * max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414 + * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from + * extra sign bits, and eat one in adding + */ + t = MULSHIFT32(sin2a, ar1 + ai1); + z2 = MULSHIFT32(cps2a, ai1) - t; + cms2 = cps2a - 2*sin2a; + z1 = MULSHIFT32(cms2, ar1) + t; + *zbuf1++ = z1; /* cos*ar1 + sin*ai1 */ + *zbuf1++ = z2; /* cos*ai1 - sin*ar1 */ + + t = MULSHIFT32(sin2b, ar2 + ai2); + z2 = MULSHIFT32(cps2b, ai2) - t; + cms2 = cps2b - 2*sin2b; + z1 = MULSHIFT32(cms2, ar2) + t; + *zbuf2-- = z2; /* cos*ai2 - sin*ar2 */ + *zbuf2-- = z1; /* cos*ar2 + sin*ai2 */ + } +} +/*********************************************************************************************************************** + * Function: PostMultiply64 + * + * Description: post-twiddle stage of 64-point type-IV DCT + * + * Inputs: buffer of 64 samples + * number of output samples to calculate + * + * Outputs: processed samples in same buffer + * + * Return: none + * + * Notes: minimum 1 GB in, 2 GB out, gains 2 int32_t bits + * gbOut = gbIn + 1 + * output is limited to sqrt(2)/2 plus GB in full GB + * nSampsOut is rounded up to next multiple of 4, since we calculate + * 4 samples per loop + **********************************************************************************************************************/ +void PostMultiply64(int32_t *fft1, int32_t nSampsOut) { + + int32_t i, ar1, ai1, ar2, ai2; + int32_t t, cms2, cps2, sin2; + int32_t *fft2; + const int32_t *csptr; + + csptr = cos1sin1tab64; + fft2 = fft1 + 64 - 1; + + /* load coeffs for first pass + * cps2 = (cos+sin)/2, sin2 = sin/2, cms2 = (cos-sin)/2 + */ + cps2 = *csptr++; + sin2 = *csptr++; + cms2 = cps2 - 2*sin2; + + for (i = (nSampsOut + 3) >> 2; i != 0; i--) { + ar1 = *(fft1 + 0); + ai1 = *(fft1 + 1); + ar2 = *(fft2 - 1); + ai2 = *(fft2 + 0); + + /* gain 2 int32_t bits (multiplying by Q30), max gain = sqrt(2) */ + t = MULSHIFT32(sin2, ar1 + ai1); + *fft2-- = t - MULSHIFT32(cps2, ai1); + *fft1++ = t + MULSHIFT32(cms2, ar1); + + cps2 = *csptr++; + sin2 = *csptr++; + + ai2 = -ai2; + t = MULSHIFT32(sin2, ar2 + ai2); + *fft2-- = t - MULSHIFT32(cps2, ai2); + cms2 = cps2 - 2*sin2; + *fft1++ = t + MULSHIFT32(cms2, ar2); + } +} +/*********************************************************************************************************************** + * Function: QMFAnalysisConv + * + * Description: convolution kernel for analysis QMF + * + * Inputs: pointer to coefficient table, reordered for sequential access + * delay buffer of size 32*10 = 320 real-valued PCM samples + * index for delay ring buffer (range = [0, 9]) + * + * Outputs: 64 consecutive 32-bit samples + * + * Return: none + * + * Notes: this is carefully written to be efficient on ARM + * use the assembly code version in sbrqmfak.s when building for ARM! + **********************************************************************************************************************/ +void QMFAnalysisConv(int32_t *cTab, int32_t *delay, int32_t dIdx, int32_t *uBuf) { + + int32_t k, dOff; + int32_t *cPtr0, *cPtr1; + U64 u64lo, u64hi; + + dOff = dIdx*32 + 31; + cPtr0 = cTab; + cPtr1 = cTab + 33*5 - 1; + + /* special first pass since we need to flip sign to create cTab[384], cTab[512] */ + u64lo.w64 = 0; + u64hi.w64 = 0; + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + + uBuf[0] = u64lo.r.hi32; + uBuf[32] = u64hi.r.hi32; + uBuf++; + dOff--; + + /* max gain for any sample in uBuf, after scaling by cTab, ~= 0.99 + * so we can just sum the uBuf values with no overflow problems + */ + for (k = 1; k <= 31; k++) { + u64lo.w64 = 0; + u64hi.w64 = 0; + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} + + uBuf[0] = u64lo.r.hi32; + uBuf[32] = u64hi.r.hi32; + uBuf++; + dOff--; + } +} +/*********************************************************************************************************************** + * Function: QMFAnalysis + * + * Description: 32-subband analysis QMF (4.6.18.4.1) + * + * Inputs: 32 consecutive samples of decoded 32-bit PCM, format = Q(fBitsIn) + * delay buffer of size 32*10 = 320 PCM samples + * number of fraction bits in input PCM + * index for delay ring buffer (range = [0, 9]) + * number of subbands to calculate (range = [0, 32]) + * + * Outputs: qmfaBands complex subband samples, format = Q(FBITS_OUT_QMFA) + * updated delay buffer + * updated delay index + * + * Return: guard bit mask + * + * Notes: output stored as RE{X0}, IM{X0}, RE{X1}, IM{X1}, ... RE{X31}, IM{X31} + * output stored in int32_t buffer of size 64*2 = 128 + * (zero-filled from XBuf[2*qmfaBands] to XBuf[127]) + **********************************************************************************************************************/ +int32_t QMFAnalysis(int32_t *inbuf, int32_t *delay, int32_t *XBuf, int32_t fBitsIn, int32_t *delayIdx, int32_t qmfaBands) { + + int32_t n, y, shift, gbMask; + int32_t *delayPtr, *uBuf, *tBuf; + + /* use XBuf[128] as temp buffer for reordering */ + uBuf = XBuf; /* first 64 samples */ + tBuf = XBuf + 64; /* second 64 samples */ + + /* overwrite oldest PCM with new PCM + * delay[n] has 1 GB after shifting (either << or >>) + */ + delayPtr = delay + (*delayIdx * 32); + if (fBitsIn > FBITS_IN_QMFA) { + shift = MIN(fBitsIn - FBITS_IN_QMFA, (int32_t)31); + for (n = 32; n != 0; n--) { + y = (*inbuf) >> shift; + inbuf++; + *delayPtr++ = y; + } + } else { + shift = MIN(FBITS_IN_QMFA - fBitsIn, (int32_t)30); + for (n = 32; n != 0; n--) { + y = *inbuf++; + y = CLIP_2N_SHIFT30(y, shift); + *delayPtr++ = y; + } + } + + QMFAnalysisConv((int32_t *)cTabA, delay, *delayIdx, uBuf); + + /* uBuf has at least 2 GB right now (1 from clipping to Q(FBITS_IN_QMFA), one from + * the scaling by cTab (MULSHIFT32(*delayPtr--, *cPtr++), with net gain of < 1.0) + */ + tBuf[2*0 + 0] = uBuf[0]; + tBuf[2*0 + 1] = uBuf[1]; + for (n = 1; n < 31; n++) { + tBuf[2*n + 0] = -uBuf[64-n]; + tBuf[2*n + 1] = uBuf[n+1]; + } + tBuf[2*31 + 1] = uBuf[32]; + tBuf[2*31 + 0] = -uBuf[33]; + + /* fast in-place DCT-IV - only need 2*qmfaBands output samples */ + PreMultiply64(tBuf); /* 2 GB in, 3 GB out */ + FFT32C(tBuf); /* 3 GB in, 1 GB out */ + PostMultiply64(tBuf, qmfaBands*2); /* 1 GB in, 2 GB out */ + + gbMask = 0; + for (n = 0; n < qmfaBands; n++) { + XBuf[2*n+0] = tBuf[ n + 0]; /* implicit scaling of 2 in our output Q format */ + gbMask |= FASTABS(XBuf[2*n+0]); + XBuf[2*n+1] = -tBuf[63 - n]; + gbMask |= FASTABS(XBuf[2*n+1]); + } + + /* fill top section with zeros for HF generation */ + for ( ; n < 64; n++) { + XBuf[2*n+0] = 0; + XBuf[2*n+1] = 0; + } + + *delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1); + + /* minimum of 2 GB in output */ + return gbMask; +} +/*********************************************************************************************************************** + * Function: QMFSynthesisConv + * + * Description: final convolution kernel for synthesis QMF + * + * Inputs: pointer to coefficient table, reordered for sequential access + * delay buffer of size 64*10 = 640 complex samples (1280 ints) + * index for delay ring buffer (range = [0, 9]) + * number of QMF subbands to process (range = [0, 64]) + * number of channels + * + * Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans + * + * Return: none + * + * Notes: this is carefully written to be efficient on ARM + * use the assembly code version in sbrqmfsk.s when building for ARM! + **********************************************************************************************************************/ +void QMFSynthesisConv(int32_t *cPtr, int32_t *delay, int32_t dIdx, int16_t *outbuf, int32_t nChans) { + + int32_t k, dOff0, dOff1; + U64 sum64; + + dOff0 = (dIdx)*128; + dOff1 = dOff0 - 1; + if (dOff1 < 0) + dOff1 += 1280; + + /* scaling note: total gain of coefs (cPtr[0]-cPtr[9] for any k) is < 2.0, so 1 GB in delay values is adequate */ + for (k = 0; k <= 63; k++) { + sum64.w64 = 0; + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} + sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} + + dOff0++; + dOff1--; + *outbuf = CLIPTOSHORT((sum64.r.hi32 + RND_VAL) >> FBITS_OUT_QMFS); + outbuf += nChans; + } +} +/*********************************************************************************************************************** + * Function: QMFSynthesis + * + * Description: 64-subband synthesis QMF (4.6.18.4.2) + * + * Inputs: 64 consecutive complex subband QMF samples, format = Q(FBITS_IN_QMFS) + * delay buffer of size 64*10 = 640 complex samples (1280 ints) + * index for delay ring buffer (range = [0, 9]) + * number of QMF subbands to process (range = [0, 64]) + * number of channels + * + * Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans + * updated delay buffer + * updated delay index + * + * Return: none + * + * Notes: assumes MIN_GBITS_IN_QMFS guard bits in input, either from + * QMFAnalysis (if upsampling only) or from MapHF (if SBR on) + **********************************************************************************************************************/ +void QMFSynthesis(int32_t *inbuf, int32_t *delay, int32_t *delayIdx, int32_t qmfsBands, int16_t *outbuf, int32_t nChans) { + + int32_t n, a0, a1, b0, b1, dOff0, dOff1, dIdx; + int32_t *tBufLo, *tBufHi; + + dIdx = *delayIdx; + tBufLo = delay + dIdx*128 + 0; + tBufHi = delay + dIdx*128 + 127; + + /* reorder inputs to DCT-IV, only use first qmfsBands (complex) samples + */ + for (n = 0; n < qmfsBands >> 1; n++) { + a0 = *inbuf++; + b0 = *inbuf++; + a1 = *inbuf++; + b1 = *inbuf++; + *tBufLo++ = a0; + *tBufLo++ = a1; + *tBufHi-- = b0; + *tBufHi-- = b1; + } + if (qmfsBands & 0x01) { + a0 = *inbuf++; + b0 = *inbuf++; + *tBufLo++ = a0; + *tBufHi-- = b0; + *tBufLo++ = 0; + *tBufHi-- = 0; + n++; + } + for ( ; n < 32; n++) { + *tBufLo++ = 0; + *tBufHi-- = 0; + *tBufLo++ = 0; + *tBufHi-- = 0; + } + + tBufLo = delay + dIdx*128 + 0; + tBufHi = delay + dIdx*128 + 64; + + /* 2 GB in, 3 GB out */ + PreMultiply64(tBufLo); + PreMultiply64(tBufHi); + + /* 3 GB in, 1 GB out */ + FFT32C(tBufLo); + FFT32C(tBufHi); + + /* 1 GB in, 2 GB out */ + PostMultiply64(tBufLo, 64); + PostMultiply64(tBufHi, 64); + + /* could fuse with PostMultiply64 to avoid separate pass */ + dOff0 = dIdx*128; + dOff1 = dIdx*128 + 64; + for (n = 32; n != 0; n--) { + a0 = (*tBufLo++); + a1 = (*tBufLo++); + b0 = (*tBufHi++); + b1 = -(*tBufHi++); + + delay[dOff0++] = (b0 - a0); + delay[dOff0++] = (b1 - a1); + delay[dOff1++] = (b0 + a0); + delay[dOff1++] = (b1 + a1); + } + + QMFSynthesisConv((int32_t *)cTabS, delay, dIdx, outbuf, nChans); + + *delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1); +} +/*********************************************************************************************************************** + * Function: UnpackSBRHeader + * + * Description: unpack SBR header (table 4.56) + * + * Inputs: BitStreamInfo struct pointing to start of SBR header + * + * Outputs: initialized SBRHeader struct for this SCE/CPE block + * + * Return: non-zero if frame reset is triggered, zero otherwise + **********************************************************************************************************************/ +int32_t UnpackSBRHeader(SBRHeader *sbrHdr) { + + SBRHeader sbrHdrPrev; + + /* save previous values so we know whether to reset decoder */ + sbrHdrPrev.startFreq = sbrHdr->startFreq; + sbrHdrPrev.stopFreq = sbrHdr->stopFreq; + sbrHdrPrev.freqScale = sbrHdr->freqScale; + sbrHdrPrev.alterScale = sbrHdr->alterScale; + sbrHdrPrev.crossOverBand = sbrHdr->crossOverBand; + sbrHdrPrev.noiseBands = sbrHdr->noiseBands; + + sbrHdr->ampRes = GetBits(1); + sbrHdr->startFreq = GetBits(4); + sbrHdr->stopFreq = GetBits(4); + sbrHdr->crossOverBand = GetBits(3); + sbrHdr->resBitsHdr = GetBits(2); + sbrHdr->hdrExtra1 = GetBits(1); + sbrHdr->hdrExtra2 = GetBits(1); + + if (sbrHdr->hdrExtra1) { + sbrHdr->freqScale = GetBits(2); + sbrHdr->alterScale = GetBits(1); + sbrHdr->noiseBands = GetBits(2); + } else { + /* defaults */ + sbrHdr->freqScale = 2; + sbrHdr->alterScale = 1; + sbrHdr->noiseBands = 2; + } + + if (sbrHdr->hdrExtra2) { + sbrHdr->limiterBands = GetBits(2); + sbrHdr->limiterGains = GetBits(2); + sbrHdr->interpFreq = GetBits(1); + sbrHdr->smoothMode = GetBits(1); + } else { + /* defaults */ + sbrHdr->limiterBands = 2; + sbrHdr->limiterGains = 2; + sbrHdr->interpFreq = 1; + sbrHdr->smoothMode = 1; + } + sbrHdr->count++; + + /* if any of these have changed from previous frame, reset the SBR module */ + if (sbrHdr->startFreq != sbrHdrPrev.startFreq || sbrHdr->stopFreq != sbrHdrPrev.stopFreq || + sbrHdr->freqScale != sbrHdrPrev.freqScale || sbrHdr->alterScale != sbrHdrPrev.alterScale || + sbrHdr->crossOverBand != sbrHdrPrev.crossOverBand || sbrHdr->noiseBands != sbrHdrPrev.noiseBands + ) + return -1; + else + return 0; +} + +/* cLog2[i] = ceil(log2(i)) (disregard i == 0) */ +static const uint8_t cLog2[9] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; +/*********************************************************************************************************************** + * Function: UnpackSBRGrid + * + * Description: unpack SBR grid (table 4.62) + * + * Inputs: BitStreamInfo struct pointing to start of SBR grid + * initialized SBRHeader struct for this SCE/CPE block + * + * Outputs: initialized SBRGrid struct for this channel + * + * Return: none + **********************************************************************************************************************/ +void UnpackSBRGrid(SBRHeader *sbrHdr, SBRGrid *sbrGrid) { + + int32_t numEnvRaw, env, rel, pBits, border, middleBorder = 0; + uint8_t relBordLead[MAX_NUM_ENV], relBordTrail[MAX_NUM_ENV]; + uint8_t relBorder0[3], relBorder1[3], relBorder[3]; + uint8_t numRelBorder0, numRelBorder1, numRelBorder, numRelLead = 0, numRelTrail; + uint8_t absBordLead = 0, absBordTrail = 0, absBorder; + + sbrGrid->ampResFrame = sbrHdr->ampRes; + sbrGrid->frameClass = GetBits(2); + switch(sbrGrid->frameClass){ + + case SBR_GRID_FIXFIX: + numEnvRaw = GetBits(2); + sbrGrid->numEnv = (1 << numEnvRaw); + if(sbrGrid->numEnv == 1) sbrGrid->ampResFrame = 0; + + ASSERT(sbrGrid->numEnv == 1 || sbrGrid->numEnv == 2 || sbrGrid->numEnv == 4); + + sbrGrid->freqRes[0] = GetBits(1); + for(env = 1; env < sbrGrid->numEnv; env++) + sbrGrid->freqRes[env] = sbrGrid->freqRes[0]; + + absBordLead = 0; + absBordTrail = NUM_TIME_SLOTS; + numRelLead = sbrGrid->numEnv - 1; + numRelTrail = 0; + + /* numEnv = 1, 2, or 4 */ + if(sbrGrid->numEnv == 1) + border = NUM_TIME_SLOTS / 1; + else if(sbrGrid->numEnv == 2) + border = NUM_TIME_SLOTS / 2; + else + border = NUM_TIME_SLOTS / 4; + + for(rel = 0; rel < numRelLead; rel++) + relBordLead[rel] = border; + + middleBorder = (sbrGrid->numEnv >> 1); + + break; + + case SBR_GRID_FIXVAR: + absBorder = GetBits(2) + NUM_TIME_SLOTS; + numRelBorder = GetBits(2); + sbrGrid->numEnv = numRelBorder + 1; + for(rel = 0; rel < numRelBorder; rel++) + relBorder[rel] = 2 * GetBits(2) + 2; + + pBits = cLog2[sbrGrid->numEnv + 1]; + sbrGrid->pointer = GetBits(pBits); + + for(env = sbrGrid->numEnv - 1; env >= 0; env--) + sbrGrid->freqRes[env] = GetBits(1); + + absBordLead = 0; + absBordTrail = absBorder; + numRelLead = 0; + numRelTrail = numRelBorder; + + for(rel = 0; rel < numRelTrail; rel++) + relBordTrail[rel] = relBorder[rel]; + + if(sbrGrid->pointer > 1) + middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer; + else + middleBorder = sbrGrid->numEnv - 1; + + break; + + case SBR_GRID_VARFIX: + absBorder = GetBits(2); + numRelBorder = GetBits(2); + sbrGrid->numEnv = numRelBorder + 1; + for(rel = 0; rel < numRelBorder; rel++) + relBorder[rel] = 2 * GetBits(2) + 2; + + pBits = cLog2[sbrGrid->numEnv + 1]; + sbrGrid->pointer = GetBits(pBits); + + for(env = 0; env < sbrGrid->numEnv; env++) + sbrGrid->freqRes[env] = GetBits(1); + + absBordLead = absBorder; + absBordTrail = NUM_TIME_SLOTS; + numRelLead = numRelBorder; + numRelTrail = 0; + + for(rel = 0; rel < numRelLead; rel++) + relBordLead[rel] = relBorder[rel]; + + if(sbrGrid->pointer == 0) + middleBorder = 1; + else if(sbrGrid->pointer == 1) + middleBorder = sbrGrid->numEnv - 1; + else + middleBorder = sbrGrid->pointer - 1; + + break; + + case SBR_GRID_VARVAR: + absBordLead = GetBits(2); /* absBorder0 */ + absBordTrail = GetBits(2) + NUM_TIME_SLOTS; /* absBorder1 */ + numRelBorder0 = GetBits(2); + numRelBorder1 = GetBits(2); + + sbrGrid->numEnv = numRelBorder0 + numRelBorder1 + 1; + ASSERT(sbrGrid->numEnv <= 5); + + for(rel = 0; rel < numRelBorder0; rel++) + relBorder0[rel] = 2 * GetBits(2) + 2; + + for(rel = 0; rel < numRelBorder1; rel++) + relBorder1[rel] = 2 * GetBits(2) + 2; + + pBits = cLog2[numRelBorder0 + numRelBorder1 + 2]; + sbrGrid->pointer = GetBits(pBits); + + for(env = 0; env < sbrGrid->numEnv; env++) + sbrGrid->freqRes[env] = GetBits(1); + + numRelLead = numRelBorder0; + numRelTrail = numRelBorder1; + + for(rel = 0; rel < numRelLead; rel++) + relBordLead[rel] = relBorder0[rel]; + + for(rel = 0; rel < numRelTrail; rel++) + relBordTrail[rel] = relBorder1[rel]; + + if(sbrGrid->pointer > 1) + middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer; + else + middleBorder = sbrGrid->numEnv - 1; + + break; + } + + /* build time border vector */ + sbrGrid->envTimeBorder[0] = absBordLead * SAMPLES_PER_SLOT; + + rel = 0; + border = absBordLead; + for(env = 1; env <= numRelLead; env++) { + border += relBordLead[rel++]; + sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT; + } + + rel = 0; + border = absBordTrail; + for(env = sbrGrid->numEnv - 1; env > numRelLead; env--) { + border -= relBordTrail[rel++]; + sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT; + } + + sbrGrid->envTimeBorder[sbrGrid->numEnv] = absBordTrail * SAMPLES_PER_SLOT; + + if(sbrGrid->numEnv > 1) { + sbrGrid->numNoiseFloors = 2; + sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0]; + sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[middleBorder]; + sbrGrid->noiseTimeBorder[2] = sbrGrid->envTimeBorder[sbrGrid->numEnv]; + } + else { + sbrGrid->numNoiseFloors = 1; + sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0]; + sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[1]; + } +} +/*********************************************************************************************************************** + * Function: UnpackDeltaTimeFreq + * + * Description: unpack time/freq flags for delta coding of SBR envelopes (table 4.63) + * + * Inputs: BitStreamInfo struct pointing to start of dt/df flags + * number of envelopes + * number of noise floors + * + * Outputs: delta flags for envelope and noise floors + * + * Return: none + **********************************************************************************************************************/ +void UnpackDeltaTimeFreq(int32_t numEnv, uint8_t *deltaFlagEnv, int32_t numNoiseFloors, uint8_t *deltaFlagNoise) { + + int32_t env, noiseFloor; + + for (env = 0; env < numEnv; env++) + deltaFlagEnv[env] = GetBits(1); + + for (noiseFloor = 0; noiseFloor < numNoiseFloors; noiseFloor++) + deltaFlagNoise[noiseFloor] = GetBits(1); +} +/*********************************************************************************************************************** + * Function: UnpackInverseFilterMode + * + * Description: unpack invf flags for chirp factor calculation (table 4.64) + * + * Inputs: BitStreamInfo struct pointing to start of invf flags + * number of noise floor bands + * + * Outputs: invf flags for noise floor bands + * + * Return: none + **********************************************************************************************************************/ +void UnpackInverseFilterMode(int32_t numNoiseFloorBands, uint8_t *mode) { + + int32_t n; + + for (n = 0; n < numNoiseFloorBands; n++) + mode[n] = GetBits(2); +} +/*********************************************************************************************************************** + * Function: UnpackSinusoids + * + * Description: unpack sinusoid (harmonic) flags for each SBR subband (table 4.67) + * + * Inputs: BitStreamInfo struct pointing to start of sinusoid flags + * number of high resolution SBR subbands (nHigh) + * + * Outputs: sinusoid flags for each SBR subband, zero-filled above nHigh + * + * Return: none + **********************************************************************************************************************/ +void UnpackSinusoids(int32_t nHigh, int32_t addHarmonicFlag, uint8_t *addHarmonic) { + + int32_t n; + + n = 0; + if(addHarmonicFlag) { + for(; n < nHigh; n++) + addHarmonic[n] = GetBits(1); + } + + /* zero out unused bands */ + for(; n < MAX_QMF_BANDS; n++) + addHarmonic[n] = 0; +} +/*********************************************************************************************************************** + * Function: CopyCouplingGrid + * + * Description: copy grid parameters from left to right for channel coupling + * + * Inputs: initialized SBRGrid struct for left channel + * + * Outputs: initialized SBRGrid struct for right channel + * + * Return: none + **********************************************************************************************************************/ +void CopyCouplingGrid(SBRGrid *sbrGridLeft, SBRGrid *sbrGridRight) { + + int32_t env, noiseFloor; + + sbrGridRight->frameClass = sbrGridLeft->frameClass; + sbrGridRight->ampResFrame = sbrGridLeft->ampResFrame; + sbrGridRight->pointer = sbrGridLeft->pointer; + + sbrGridRight->numEnv = sbrGridLeft->numEnv; + for(env = 0; env < sbrGridLeft->numEnv; env++) { + sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env]; + sbrGridRight->freqRes[env] = sbrGridLeft->freqRes[env]; + } + sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env]; /* borders are [0, numEnv] inclusive */ + + sbrGridRight->numNoiseFloors = sbrGridLeft->numNoiseFloors; + for(noiseFloor = 0; noiseFloor <= sbrGridLeft->numNoiseFloors; noiseFloor++) + sbrGridRight->noiseTimeBorder[noiseFloor] = sbrGridLeft->noiseTimeBorder[noiseFloor]; + + /* numEnvPrev, numNoiseFloorsPrev, freqResPrev are updated in DecodeSBREnvelope() and DecodeSBRNoise() */ +} +/*********************************************************************************************************************** + * Function: CopyCouplingInverseFilterMode + * + * Description: copy invf flags from left to right for channel coupling + * + * Inputs: invf flags for left channel + * number of noise floor bands + * + * Outputs: invf flags for right channel + * + * Return: none + **********************************************************************************************************************/ +void CopyCouplingInverseFilterMode(int32_t numNoiseFloorBands, uint8_t *modeLeft, uint8_t *modeRight) { + + int32_t band; + + for(band = 0; band < numNoiseFloorBands; band++) + modeRight[band] = modeLeft[band]; +} +/*********************************************************************************************************************** + * Function: UnpackSBRSingleChannel + * + * Description: unpack sideband info (grid, delta flags, invf flags, envelope and + * noise floor configuration, sinusoids) for a single channel + * + * Inputs: BitStreamInfo struct pointing to start of sideband info + * initialized PSInfoSBR struct (after parsing SBR header and building + * frequency tables) + * base output channel (range = [0, nChans-1]) + * + * Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan) + * + * Return: none + **********************************************************************************************************************/ +void UnpackSBRSingleChannel(int32_t chBase) { + + int32_t bitsLeft; + SBRHeader *sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); + SBRGrid *sbrGridL = &(m_PSInfoSBR->sbrGrid[chBase + 0]); + SBRFreq *sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); + SBRChan *sbrChanL = &(m_PSInfoSBR->sbrChan[chBase + 0]); + + m_PSInfoSBR->dataExtra = GetBits(1); + if(m_PSInfoSBR->dataExtra) m_PSInfoSBR->resBitsData = GetBits(4); + + UnpackSBRGrid(sbrHdr, sbrGridL); + UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise); + UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); + + DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); + DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); + + sbrChanL->addHarmonicFlag[1] = GetBits(1); + UnpackSinusoids(sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]); + + m_PSInfoSBR->extendedDataPresent = GetBits(1); + if(m_PSInfoSBR->extendedDataPresent) { + m_PSInfoSBR->extendedDataSize = GetBits(4); + if(m_PSInfoSBR->extendedDataSize == 15) m_PSInfoSBR->extendedDataSize += GetBits(8); + + bitsLeft = 8 * m_PSInfoSBR->extendedDataSize; + + /* get ID, unpack extension info, do whatever is necessary with it... */ + while(bitsLeft > 0) { + GetBits(8); + bitsLeft -= 8; + } + } +} +/*********************************************************************************************************************** + * Function: UnpackSBRChannelPair + * + * Description: unpack sideband info (grid, delta flags, invf flags, envelope and + * noise floor configuration, sinusoids) for a channel pair + * + * Inputs: base output channel (range = [0, nChans-1]) + * + * Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan for both channels) + * + * Return: none + **********************************************************************************************************************/ +void UnpackSBRChannelPair(int32_t chBase) { + + int32_t bitsLeft; + SBRHeader *sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); + SBRGrid *sbrGridL = &(m_PSInfoSBR->sbrGrid[chBase + 0]), *sbrGridR = &(m_PSInfoSBR->sbrGrid[chBase + 1]); + SBRFreq *sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); + SBRChan *sbrChanL = &(m_PSInfoSBR->sbrChan[chBase + 0]), *sbrChanR = &(m_PSInfoSBR->sbrChan[chBase + 1]); + + m_PSInfoSBR->dataExtra = GetBits(1); + if(m_PSInfoSBR->dataExtra) { + m_PSInfoSBR->resBitsData = GetBits(4); + m_PSInfoSBR->resBitsData = GetBits(4); + } + + m_PSInfoSBR->couplingFlag = GetBits(1); + if(m_PSInfoSBR->couplingFlag) { + UnpackSBRGrid(sbrHdr, sbrGridL); + CopyCouplingGrid(sbrGridL, sbrGridR); + + UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, + sbrChanL->deltaFlagNoise); + UnpackDeltaTimeFreq(sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, + sbrChanR->deltaFlagNoise); + + UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); + CopyCouplingInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1], sbrChanR->invfMode[1]); + + DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); + DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); + DecodeSBREnvelope(sbrGridR, sbrFreq, sbrChanR, 1); + DecodeSBRNoise(sbrGridR, sbrFreq, sbrChanR, 1); + + /* pass RIGHT sbrChan struct */ + UncoupleSBREnvelope(sbrGridL, sbrFreq, sbrChanR); + UncoupleSBRNoise(sbrGridL, sbrFreq, sbrChanR); + + } + else { + UnpackSBRGrid(sbrHdr, sbrGridL); + UnpackSBRGrid(sbrHdr, sbrGridR); + UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, + sbrChanL->deltaFlagNoise); + UnpackDeltaTimeFreq(sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, + sbrChanR->deltaFlagNoise); + UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); + UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanR->invfMode[1]); + + DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); + DecodeSBREnvelope(sbrGridR, sbrFreq, sbrChanR, 1); + DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); + DecodeSBRNoise(sbrGridR, sbrFreq, sbrChanR, 1); + } + + sbrChanL->addHarmonicFlag[1] = GetBits(1); + UnpackSinusoids(sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]); + + sbrChanR->addHarmonicFlag[1] = GetBits(1); + UnpackSinusoids(sbrFreq->nHigh, sbrChanR->addHarmonicFlag[1], sbrChanR->addHarmonic[1]); + + m_PSInfoSBR->extendedDataPresent = GetBits(1); + if(m_PSInfoSBR->extendedDataPresent) { + m_PSInfoSBR->extendedDataSize = GetBits(4); + if(m_PSInfoSBR->extendedDataSize == 15) m_PSInfoSBR->extendedDataSize += GetBits(8); + + bitsLeft = 8 * m_PSInfoSBR->extendedDataSize; + + /* get ID, unpack extension info, do whatever is necessary with it... */ + while(bitsLeft > 0) { + GetBits(8); + bitsLeft -= 8; + } + } +} +/*********************************************************************************************************************** + * Function: AACGetErrorMessage + * + * Description: Gives back a description of the error, which is specified by the error code. + * + * Inputs: errCode as positive integer, which is the negated error code + * + * Return: error message as string + **********************************************************************************************************************/ + +const char* AACGetErrorMessage(uint8_t errorCode){ + const char* e = NULL; + int r = 0 - errorCode; + switch(r) { + case ERR_AAC_NONE: e = "NONE"; break; + case ERR_AAC_INDATA_UNDERFLOW: e = "INDATA_UNDERFLOW"; break; + case ERR_AAC_NULL_POINTER: e = "NULL_POINTER"; break; + case ERR_AAC_INVALID_ADTS_HEADER: e = "INVALID_ADTS_HEADER"; break; + case ERR_AAC_INVALID_ADIF_HEADER: e = "INVALID_ADIF_HEADER"; break; + case ERR_AAC_INVALID_FRAME: e = "INVALID_FRAME"; break; + case ERR_AAC_MPEG4_UNSUPPORTED: e = "MPEG4_UNSUPPORTED"; break; + case ERR_AAC_CHANNEL_MAP: e = "CHANNEL_MAP"; break; + case ERR_AAC_SYNTAX_ELEMENT: e = "SYNTAX_ELEMENT"; break; + case ERR_AAC_DEQUANT: e = "DEQUANT"; break; + case ERR_AAC_STEREO_PROCESS: e = "STEREO_PROCESS"; break; + case ERR_AAC_PNS: e = "PNS"; break; + case ERR_AAC_SHORT_BLOCK_DEINT: e = "SHORT_BLOCK_DEINT"; break; + case ERR_AAC_TNS: e = "TNS"; break; + case ERR_AAC_IMDCT: e = "IMDCT"; break; + case ERR_AAC_SBR_INIT: e = "SBR_INIT"; break; + case ERR_AAC_SBR_BITSTREAM: e = "SBR_BITSTREAM"; break; + case ERR_AAC_SBR_DATA: e = "SBR_DATA"; break; + case ERR_AAC_SBR_PCM_FORMAT: e = "SBR_PCM_FORMAT"; break; + case ERR_AAC_SBR_NCHANS_TOO_HIGH: e = "SBR_NCHANS_TOO_HIGH"; break; + case ERR_AAC_SBR_SINGLERATE_UNSUPPORTED: e = "BR_SINGLERATE_UNSUPPORTED"; break; + case ERR_AAC_NCHANS_TOO_HIGH: e = "NCHANS_TOO_HIGH"; break; + case ERR_AAC_RAWBLOCK_PARAMS: e = "RAWBLOCK_PARAMS"; break; + default: e = "ERR_UNKNOWN"; + } + return e; +} \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.h_ b/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.h_ new file mode 100644 index 0000000..b7e1e1a --- /dev/null +++ b/libraries/ESP32-audioI2S/additional_info/old/Helix AAC Decoder/aac_decoder.h_ @@ -0,0 +1,589 @@ +// based on helix aac decoder +#pragma once +//#pragma GCC optimize ("O3") +//#pragma GCC diagnostic ignored "-Wnarrowing" + +#include "Arduino.h" + +#define AAC_ENABLE_MPEG4 + +#if (defined CONFIG_IDF_TARGET_ESP32S3 && defined BOARD_HAS_PSRAM) + #define AAC_ENABLE_SBR // needs additional 60KB DRAM, +#endif + +#define ASSERT(x) /* do nothing */ + +#ifndef MAX +#define MAX(a,b) std::max(a,b) +#endif + +#ifndef MIN +#define MIN(a,b) std::min(a,b) +#endif + + +/* AAC file format */ +enum { + AAC_FF_Unknown = 0, /* should be 0 on init */ + AAC_FF_ADTS = 1, + AAC_FF_ADIF = 2, + AAC_FF_RAW = 3 +}; + +/* syntactic element type */ +enum { + AAC_ID_INVALID = -1, + AAC_ID_SCE = 0, + AAC_ID_CPE = 1, + AAC_ID_CCE = 2, + AAC_ID_LFE = 3, + AAC_ID_DSE = 4, + AAC_ID_PCE = 5, + AAC_ID_FIL = 6, + AAC_ID_END = 7 +}; + +enum { + ERR_AAC_NONE = 0, + ERR_AAC_INDATA_UNDERFLOW = -1, + ERR_AAC_NULL_POINTER = -2, + ERR_AAC_INVALID_ADTS_HEADER = -3, + ERR_AAC_INVALID_ADIF_HEADER = -4, + ERR_AAC_INVALID_FRAME = -5, + ERR_AAC_MPEG4_UNSUPPORTED = -6, + ERR_AAC_CHANNEL_MAP = -7, + ERR_AAC_SYNTAX_ELEMENT = -8, + ERR_AAC_DEQUANT = -9, + ERR_AAC_STEREO_PROCESS = -10, + ERR_AAC_PNS = -11, + ERR_AAC_SHORT_BLOCK_DEINT = -12, + ERR_AAC_TNS = -13, + ERR_AAC_IMDCT = -14, + ERR_AAC_NCHANS_TOO_HIGH = -15, + ERR_AAC_SBR_INIT = -16, + ERR_AAC_SBR_BITSTREAM = -17, + ERR_AAC_SBR_DATA = -18, + ERR_AAC_SBR_PCM_FORMAT = -19, + ERR_AAC_SBR_NCHANS_TOO_HIGH = -20, + ERR_AAC_SBR_SINGLERATE_UNSUPPORTED = -21, + ERR_AAC_RAWBLOCK_PARAMS = -22, + ERR_AAC_UNKNOWN = -9999 +}; + +enum { + SBR_GRID_FIXFIX = 0, + SBR_GRID_FIXVAR = 1, + SBR_GRID_VARFIX = 2, + SBR_GRID_VARVAR = 3 +}; + +enum { + HuffTabSBR_tEnv15 = 0, + HuffTabSBR_fEnv15 = 1, + HuffTabSBR_tEnv15b = 2, + HuffTabSBR_fEnv15b = 3, + HuffTabSBR_tEnv30 = 4, + HuffTabSBR_fEnv30 = 5, + HuffTabSBR_tEnv30b = 6, + HuffTabSBR_fEnv30b = 7, + HuffTabSBR_tNoise30 = 8, + HuffTabSBR_fNoise30 = 5, + HuffTabSBR_tNoise30b = 9, + HuffTabSBR_fNoise30b = 7 +}; + +typedef struct _AACDecInfo_t { + /* raw decoded data, before rounding to 16-bit PCM (for postprocessing such as SBR) */ + void *rawSampleBuf[2]; + int32_t rawSampleBytes; + int32_t rawSampleFBits; + /* fill data (can be used for processing SBR or other extensions) */ + uint8_t *fillBuf; + int32_t fillCount; + int32_t fillExtType; + int32_t prevBlockID; /* block information */ + int32_t currBlockID; + int32_t currInstTag; + int32_t sbDeinterleaveReqd[2]; // [MAX_NCHANS_ELEM] + int32_t adtsBlocksLeft; + int32_t bitRate; /* user-accessible info */ + int32_t nChans; + int32_t sampRate; + float compressionRatio; + int32_t id; /* 0: MPEG-4, 1: MPEG2 */ + int32_t profile; /* 0: Main profile, 1: LowComplexity (LC), 2: ScalableSamplingRate (SSR), 3: reserved */ + int32_t format; + int32_t sbrEnabled; + int32_t tnsUsed; + int32_t pnsUsed; + int32_t frameCount; +} AACDecInfo_t; + + +typedef struct _aac_BitStreamInfo_t { + uint8_t *bytePtr; + uint32_t iCache; + int32_t cachedBits; + int32_t nBytes; +} aac_BitStreamInfo_t; + +typedef union _U64 { + int64_t w64; + struct { + uint32_t lo32; + int32_t hi32; + } r; +} U64; + +typedef struct _AACFrameInfo_t { + int32_t bitRate; + int32_t nChans; + int32_t sampRateCore; + int32_t sampRateOut; + int32_t bitsPerSample; + int32_t outputSamps; + int32_t profile; + int32_t tnsUsed; + int32_t pnsUsed; +} AACFrameInfo_t; + +typedef struct _HuffInfo_t { + int32_t maxBits; /* number of bits in longest codeword */ + uint8_t count[20]; /* count[MAX_HUFF_BITS] = number of codes with length i+1 bits */ + int32_t offset; /* offset into symbol table */ +} HuffInfo_t; + +typedef struct _PulseInfo_t { + uint8_t pulseDataPresent; + uint8_t numPulse; + uint8_t startSFB; + uint8_t offset[4]; // [MAX_PULSES] + uint8_t amp[4]; // [MAX_PULSES] +} PulseInfo_t; + +typedef struct _TNSInfo_t { + uint8_t tnsDataPresent; + uint8_t numFilt[8]; // [MAX_TNS_FILTERS] max 1 filter each for 8 short windows, or 3 filters for 1 long window + uint8_t coefRes[8]; // [MAX_TNS_FILTERS] + uint8_t length[8]; // [MAX_TNS_FILTERS] + uint8_t order[8]; // [MAX_TNS_FILTERS] + uint8_t dir[8]; // [MAX_TNS_FILTERS] + int8_t coef[60]; // [MAX_TNS_COEFS] max 3 filters * 20 coefs for 1 long window, + // or 1 filter * 7 coefs for each of 8 short windows +} TNSInfo_t; + +typedef struct _GainControlInfo_t { + uint8_t gainControlDataPresent; + uint8_t maxBand; + uint8_t adjNum[3][8]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN] + uint8_t alevCode[3][8][7]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST] + uint8_t alocCode[3][8][7]; // [MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST] +} GainControlInfo_t; + +typedef struct _ICSInfo_t { + uint8_t icsResBit; + uint8_t winSequence; + uint8_t winShape; + uint8_t maxSFB; + uint8_t sfGroup; + uint8_t predictorDataPresent; + uint8_t predictorReset; + uint8_t predictorResetGroupNum; + uint8_t predictionUsed[41]; // [MAX_PRED_SFB] + uint8_t numWinGroup; + uint8_t winGroupLen[8]; // [MAX_WIN_GROUPS] +} ICSInfo_t; + +typedef struct _ADTSHeader_t { + /* fixed */ + uint8_t id; /* MPEG bit - should be 1 */ + uint8_t layer; /* MPEG layer - should be 0 */ + uint8_t protectBit; /* 0 = CRC word follows, 1 = no CRC word */ + uint8_t profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */ + uint8_t sampRateIdx; /* sample rate index range = [0, 11] */ + uint8_t privateBit; /* ignore */ + uint8_t channelConfig; /* 0 = implicit, >0 = use default table */ + uint8_t origCopy; /* 0 = copy, 1 = original */ + uint8_t home; /* ignore */ + /* variable */ + uint8_t copyBit; /* 1 bit of the 72-bit copyright ID (transmitted as 1 bit per frame) */ + uint8_t copyStart; /* 1 = this bit starts the 72-bit ID, 0 = it does not */ + int32_t frameLength; /* length of frame */ + int32_t bufferFull; /* number of 32-bit words left in enc buffer, 0x7FF = VBR */ + uint8_t numRawDataBlocks; /* number of raw data blocks in frame */ + /* CRC */ + int32_t crcCheckWord; /* 16-bit CRC check word (present if protectBit == 0) */ +} ADTSHeader_t; + +typedef struct _ADIFHeader_t { + uint8_t copyBit; /* 0 = no copyright ID, 1 = 72-bit copyright ID follows immediately */ + uint8_t origCopy; /* 0 = copy, 1 = original */ + uint8_t home; /* ignore */ + uint8_t bsType; /* bitstream type: 0 = CBR, 1 = VBR */ + int32_t bitRate; /* bitRate: CBR = bits/sec, VBR = peak bits/frame, 0 = unknown */ + uint8_t numPCE; /* number of program config elements (max = 16) */ + int32_t bufferFull; /* bits left in bit reservoir */ + uint8_t copyID[9]; /* [ADIF_COPYID_SIZE] optional 72-bit copyright ID */ +} ADIFHeader_t; + +/* sizeof(ProgConfigElement_t) = 82 bytes (if KEEP_PCE_COMMENTS not defined) */ +typedef struct _ProgConfigElement_t { + uint8_t elemInstTag; /* element instance tag */ + uint8_t profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */ + uint8_t sampRateIdx; /* sample rate index range = [0, 11] */ + uint8_t numFCE; /* number of front channel elements (max = 15) */ + uint8_t numSCE; /* number of side channel elements (max = 15) */ + uint8_t numBCE; /* number of back channel elements (max = 15) */ + uint8_t numLCE; /* number of LFE channel elements (max = 3) */ + uint8_t numADE; /* number of associated data elements (max = 7) */ + uint8_t numCCE; /* number of valid channel coupling elements (max = 15) */ + uint8_t monoMixdown; /* mono mixdown: bit 4 = present flag, bits 3-0 = element number */ + uint8_t stereoMixdown; /* stereo mixdown: bit 4 = present flag, bits 3-0 = element number */ + uint8_t matrixMixdown; /* bit 4 = present flag, bit 3 = unused,bits 2-1 = index, bit 0 = pseudo-surround enable */ + uint8_t fce[15]; /* [MAX_NUM_FCE] front element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */ + uint8_t sce[15]; /* [MAX_NUM_SCE] side element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */ + uint8_t bce[15]; /* [MAX_NUM_BCE] back element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */ + uint8_t lce[3]; /* [MAX_NUM_LCE] instance tag for LFE elements */ + uint8_t ade[7]; /* [MAX_NUM_ADE] instance tag for ADE elements */ + uint8_t cce[15]; /* [MAX_NUM_BCE] channel coupling elements: bit 4 = switching flag, bits 3-0 = inst tag */ +} ProgConfigElement_t; + +typedef struct _SBRHeader { + int32_t count; + + uint8_t ampRes; + uint8_t startFreq; + uint8_t stopFreq; + uint8_t crossOverBand; + uint8_t resBitsHdr; + uint8_t hdrExtra1; + uint8_t hdrExtra2; + + uint8_t freqScale; + uint8_t alterScale; + uint8_t noiseBands; + + uint8_t limiterBands; + uint8_t limiterGains; + uint8_t interpFreq; + uint8_t smoothMode; +} SBRHeader; + +/* need one SBRGrid per channel, updated every frame */ +typedef struct _SBRGrid { + uint8_t frameClass; + uint8_t ampResFrame; + uint8_t pointer; + + uint8_t numEnv; /* L_E */ + uint8_t envTimeBorder[5 + 1]; // [MAX_NUM_ENV+1] /* t_E */ + uint8_t freqRes[5]; // [MAX_NUM_ENV]/* r */ + uint8_t numNoiseFloors; /* L_Q */ + uint8_t noiseTimeBorder[2 + 1]; // [MAX_NUM_NOISE_FLOORS+1] /* t_Q */ + + uint8_t numEnvPrev; + uint8_t numNoiseFloorsPrev; + uint8_t freqResPrev; +} SBRGrid; + +/* need one SBRFreq per element (SCE/CPE/LFE), updated only on header reset */ +typedef struct _SBRFreq { + int32_t kStart; /* k_x */ + int32_t nMaster; + int32_t nHigh; + int32_t nLow; + int32_t nLimiter; /* N_l */ + int32_t numQMFBands; /* M */ + int32_t numNoiseFloorBands; /* Nq */ + int32_t kStartPrev; + int32_t numQMFBandsPrev; + uint8_t freqMaster[48 + 1]; // [MAX_QMF_BANDS + 1] /* not necessary to save this after derived tables are generated */ + uint8_t freqHigh[48 + 1]; // [MAX_QMF_BANDS + 1] + uint8_t freqLow[48 / 2 + 1]; // [MAX_QMF_BANDS / 2 + 1] /* nLow = nHigh - (nHigh >> 1) */ + uint8_t freqNoise[5 + 1]; // [MAX_NUM_NOISE_FLOOR_BANDS+1] + uint8_t freqLimiter[48 / 2 + 5];// [MAX_QMF_BANDS / 2 + MAX_NUM_PATCHES] /* max (intermediate) size = nLow + numPatches - 1 */ + + uint8_t numPatches; + uint8_t patchNumSubbands[5 + 1]; // [MAX_NUM_PATCHES + 1] + uint8_t patchStartSubband[5 + 1]; // [MAX_NUM_PATCHES + 1] +} SBRFreq; + +typedef struct _SBRChan { + int32_t reset; + uint8_t deltaFlagEnv[5]; // [MAX_NUM_ENV] + uint8_t deltaFlagNoise[2]; // [MAX_NUM_NOISE_FLOORS] + int8_t envDataQuant[5][48]; // [MAX_NUM_ENV][MAX_QMF_BANDS] /* range = [0, 127] */ + int8_t noiseDataQuant[2][5]; // [MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS] + + uint8_t invfMode[2][5]; // [2][MAX_NUM_NOISE_FLOOR_BANDS] /* invfMode[0/1][band] = prev/curr */ + int32_t chirpFact[5]; // [MAX_NUM_NOISE_FLOOR_BANDS] /* bwArray */ + uint8_t addHarmonicFlag[2]; /* addHarmonicFlag[0/1] = prev/curr */ + uint8_t addHarmonic[2][64]; /* addHarmonic[0/1][band] = prev/curr */ + + int32_t gbMask[2]; /* gbMask[0/1] = XBuf[0-31]/XBuf[32-39] */ + int8_t laPrev; + + int32_t noiseTabIndex; + int32_t sinIndex; + int32_t gainNoiseIndex; + int32_t gTemp[5][48]; // [MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS] + int32_t qTemp[5][48]; // [MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS] + +} SBRChan; + + +/* state info struct for baseline (MPEG-4 LC) decoding */ +typedef struct _PSInfoBase_t { + int32_t dataCount; + uint8_t dataBuf[510]; // [DATA_BUF_SIZE] + int32_t fillCount; + uint8_t fillBuf[269]; //[FILL_BUF_SIZE] + /* state information which is the same throughout whole frame */ + int32_t nChans; + int32_t useImpChanMap; + int32_t sampRateIdx; + /* state information which can be overwritten by subsequent elements within frame */ + ICSInfo_t icsInfo[2]; // [MAX_NCHANS_ELEM] + int32_t commonWin; + int16_t scaleFactors[2][15*8]; // [MAX_NCHANS_ELEM][MAX_SF_BANDS] + uint8_t sfbCodeBook[2][15*8]; // [MAX_NCHANS_ELEM][MAX_SF_BANDS] + int32_t msMaskPresent; + uint8_t msMaskBits[(15 * 8 + 7) >> 3]; // [MAX_MS_MASK_BYTES] + int32_t pnsUsed[2]; // [MAX_NCHANS_ELEM] + int32_t pnsLastVal; + int32_t intensityUsed[2]; // [MAX_NCHANS_ELEM] +// PulseInfo_t pulseInfo[2]; // [MAX_NCHANS_ELEM] + TNSInfo_t tnsInfo[2]; // [MAX_NCHANS_ELEM] + int32_t tnsLPCBuf[20]; // [MAX_TNS_ORDER] + int32_t tnsWorkBuf[20]; //[MAX_TNS_ORDER] + GainControlInfo_t gainControlInfo[2]; // [MAX_NCHANS_ELEM] + int32_t gbCurrent[2]; // [MAX_NCHANS_ELEM] + int32_t coef[2][1024]; // [MAX_NCHANS_ELEM][AAC_MAX_NSAMPS] +#ifdef AAC_ENABLE_SBR + int32_t sbrWorkBuf[2][1024]; // [MAX_NCHANS_ELEM][AAC_MAX_NSAMPS]; +#endif + /* state information which must be saved for each element and used in next frame */ + int32_t overlap[2][1024]; // [AAC_MAX_NCHANS][AAC_MAX_NSAMPS] + int32_t prevWinShape[2]; // [AAC_MAX_NCHANS] +} PSInfoBase_t; + +typedef struct _PSInfoSBR { + /* save for entire file */ + int32_t frameCount; + int32_t sampRateIdx; + + /* state info that must be saved for each channel */ + SBRHeader sbrHdr[2]; + SBRGrid sbrGrid[2]; + SBRFreq sbrFreq[2]; + SBRChan sbrChan[2]; + + /* temp variables, no need to save between blocks */ + uint8_t dataExtra; + uint8_t resBitsData; + uint8_t extendedDataPresent; + int32_t extendedDataSize; + + int8_t envDataDequantScale[2][5]; // [MAX_NCHANS_ELEM][MAX_NUM_ENV + int32_t envDataDequant[2][5][48]; // [MAX_NCHANS_ELEM][MAX_NUM_ENV][MAX_QMF_BANDS + int32_t noiseDataDequant[2][2][5]; // [MAX_NCHANS_ELEM][MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS] + + int32_t eCurr[48]; // [MAX_QMF_BANDS] + uint8_t eCurrExp[48]; // [MAX_QMF_BANDS] + uint8_t eCurrExpMax; + int8_t la; + + int32_t crcCheckWord; + int32_t couplingFlag; + int32_t envBand; + int32_t eOMGainMax; + int32_t gainMax; + int32_t gainMaxFBits; + int32_t noiseFloorBand; + int32_t qp1Inv; + int32_t qqp1Inv; + int32_t sMapped; + int32_t sBand; + int32_t highBand; + + int32_t sumEOrigMapped; + int32_t sumECurrGLim; + int32_t sumSM; + int32_t sumQM; + int32_t gLimBoost[48]; + int32_t qmLimBoost[48]; + int32_t smBoost[48]; + + int32_t smBuf[48]; + int32_t qmLimBuf[48]; + int32_t gLimBuf[48]; + int32_t gLimFbits[48]; + + int32_t gFiltLast[48]; + int32_t qFiltLast[48]; + + /* large buffers */ + int32_t delayIdxQMFA[2]; // [AAC_MAX_NCHANS] + int32_t delayQMFA[2][10 * 32]; // [AAC_MAX_NCHANS][DELAY_SAMPS_QMFA] + int32_t delayIdxQMFS[2]; // [AAC_MAX_NCHANS] + int32_t delayQMFS[2][10 * 128]; // [AAC_MAX_NCHANS][DELAY_SAMPS_QMFS] + int32_t XBufDelay[2][8][64][2]; // [AAC_MAX_NCHANS][HF_GEN][64][2] + int32_t XBuf[32+8][64][2]; +} PSInfoSBR_t; + +bool AACDecoder_AllocateBuffers(void); +int32_t AACFlushCodec(); +void AACDecoder_FreeBuffers(void); +bool AACDecoder_IsInit(void); +int32_t AACFindSyncWord(uint8_t *buf, int32_t nBytes); +int32_t AACSetRawBlockParams(int32_t nChans, int32_t sampRateCore, int32_t profile, int32_t copyLast = 0); +int32_t AACDecode(uint8_t *inbuf, int32_t *bytesLeft, int16_t *outbuf); +int32_t AACGetSampRate(); +int32_t AACGetChannels(); +int32_t AACGetID(); // 0-MPEG4, 1-MPEG2 +uint8_t AACGetProfile(); // 0-Main, 1-LC, 2-SSR, 3-reserved +uint8_t AACGetFormat(); // 0-unknown 1-ADTS 2-ADIF, 3-RAW +int32_t AACGetBitsPerSample(); +int32_t AACGetBitrate(); +int32_t AACGetOutputSamps(); +int32_t AACGetBitrate(); +void DecodeLPCCoefs(int32_t order, int32_t res, int8_t *filtCoef, int32_t *a, int32_t *b); +int32_t FilterRegion(int32_t size, int32_t dir, int32_t order, int32_t *audioCoef, int32_t *a, int32_t *hist); +int32_t TNSFilter(int32_t ch); +int32_t DecodeSingleChannelElement(); +int32_t DecodeChannelPairElement(); +int32_t DecodeLFEChannelElement(); +int32_t DecodeDataStreamElement(); +int32_t DecodeProgramConfigElement(uint8_t idx); +int32_t DecodeFillElement(); +int32_t DecodeNextElement(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail); +void PreMultiply(int32_t tabidx, int32_t *zbuf1); +void PostMultiply(int32_t tabidx, int32_t *fft1); +void PreMultiplyRescale(int32_t tabidx, int32_t *zbuf1, int32_t es); +void PostMultiplyRescale(int32_t tabidx, int32_t *fft1, int32_t es); +void DCT4(int32_t tabidx, int32_t *coef, int32_t gb); +void BitReverse(int32_t *inout, int32_t tabidx); +void R4FirstPass(int32_t *x, int32_t bg); +void R8FirstPass(int32_t *x, int32_t bg); +void R4Core(int32_t *x, int32_t bg, int32_t gp, int32_t *wtab); +void R4FFT(int32_t tabidx, int32_t *x); +void UnpackZeros(int32_t nVals, int32_t *coef); +void UnpackQuads(int32_t cb, int32_t nVals, int32_t *coef); +void UnpackPairsNoEsc(int32_t cb, int32_t nVals, int32_t *coef); +void UnpackPairsEsc(int32_t cb, int32_t nVals, int32_t *coef); +void DecodeSpectrumLong(int32_t ch); +void DecodeSpectrumShort(int32_t ch); +void DecWindowOverlap(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapLongStart(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapLongStop(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapShort(int32_t *buf0, int32_t *over0, int16_t *pcm0, int32_t nChans, int32_t winTypeCurr, int32_t winTypePrev); +int32_t IMDCT(int32_t ch, int32_t chOut, int16_t *outbuf); +void DecodeICSInfo(ICSInfo_t *icsInfo, int32_t sampRateIdx); +void DecodeSectionData(int32_t winSequence, int32_t numWinGrp, int32_t maxSFB, uint8_t *sfbCodeBook); +int32_t DecodeOneScaleFactor(); +void DecodeScaleFactors(int32_t numWinGrp, int32_t maxSFB, int32_t globalGain, uint8_t *sfbCodeBook, int16_t *scaleFactors); +void DecodePulseInfo(uint8_t ch); +void DecodeTNSInfo(int32_t winSequence, TNSInfo_t *ti, int8_t *tnsCoef); +void DecodeGainControlInfo(int32_t winSequence, GainControlInfo_t *gi); +void DecodeICS(int32_t ch); +int32_t DecodeNoiselessData(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail, int32_t ch); +int32_t UnpackADTSHeader(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail); +int32_t GetADTSChannelMapping(uint8_t *buf, int32_t bitOffset, int32_t bitsAvail); +int32_t GetNumChannelsADIF(int32_t nPCE); +int32_t GetSampleRateIdxADIF(int32_t nPCE); +int32_t UnpackADIFHeader(uint8_t **buf, int32_t *bitOffset, int32_t *bitsAvail); +int32_t SetRawBlockParams(int32_t copyLast, int32_t nChans, int32_t sampRate, int32_t profile); +int32_t PrepareRawBlock(); +int32_t DequantBlock(int32_t *inbuf, int32_t nSamps, int32_t scale); +int32_t AACDequantize(int32_t ch); +int32_t DeinterleaveShortBlocks(int32_t ch); +uint32_t Get32BitVal(uint32_t *last); +int32_t InvRootR(int32_t r); +int32_t ScaleNoiseVector(int32_t *coef, int32_t nVals, int32_t sf); +void GenerateNoiseVector(int32_t *coef, int32_t *last, int32_t nVals); +void CopyNoiseVector(int32_t *coefL, int32_t *coefR, int32_t nVals); +int32_t PNS(int32_t ch); +int32_t GetSampRateIdx(int32_t sampRate); +void StereoProcessGroup(int32_t *coefL, int32_t *coefR, const uint16_t *sfbTab, int32_t msMaskPres, uint8_t *msMaskPtr, + int32_t msMaskOffset, int32_t maxSFB, uint8_t *cbRight, int16_t *sfRight, int32_t *gbCurrent); +int32_t StereoProcess(); +int32_t RatioPowInv(int32_t a, int32_t b, int32_t c); +int32_t SqrtFix(int32_t q, int32_t fBitsIn, int32_t *fBitsOut); +int32_t InvRNormalized(int32_t r); +void BitReverse32(int32_t *inout); +void R8FirstPass32(int32_t *r0); +void R4Core32(int32_t *r0); +void FFT32C(int32_t *x); +void CVKernel1(int32_t *XBuf, int32_t *accBuf); +void CVKernel2(int32_t *XBuf, int32_t *accBuf); +void SetBitstreamPointer(int32_t nBytes, uint8_t *buf); +inline void RefillBitstreamCache(); +uint32_t GetBits(int32_t nBits); +uint32_t GetBitsNoAdvance(int32_t nBits); +void AdvanceBitstream(int32_t nBits); +int32_t CalcBitsUsed(uint8_t *startBuf, int32_t startOffset); +void ByteAlignBitstream(); +// SBR +void InitSBRState(); +int32_t DecodeSBRBitstream(int32_t chBase); +int32_t DecodeSBRData(int32_t chBase, int16_t *outbuf); +int32_t FlushCodecSBR(); +void BubbleSort(uint8_t *v, int32_t nItems); +uint8_t VMin(uint8_t *v, int32_t nItems); +uint8_t VMax(uint8_t *v, int32_t nItems); +int32_t CalcFreqMasterScaleZero(uint8_t *freqMaster, int32_t alterScale, int32_t k0, int32_t k2); +int32_t CalcFreqMaster(uint8_t *freqMaster, int32_t freqScale, int32_t alterScale, int32_t k0, int32_t k2); +int32_t CalcFreqHigh(uint8_t *freqHigh, uint8_t *freqMaster, int32_t nMaster, int32_t crossOverBand); +int32_t CalcFreqLow(uint8_t *freqLow, uint8_t *freqHigh, int32_t nHigh); +int32_t CalcFreqNoise(uint8_t *freqNoise, uint8_t *freqLow, int32_t nLow, int32_t kStart, int32_t k2, int32_t noiseBands); +int32_t BuildPatches(uint8_t *patchNumSubbands, uint8_t *patchStartSubband, uint8_t *freqMaster, int32_t nMaster, int32_t k0, + int32_t kStart, int32_t numQMFBands, int32_t sampRateIdx); +int32_t FindFreq(uint8_t *freq, int32_t nFreq, uint8_t val); +void RemoveFreq(uint8_t *freq, int32_t nFreq, int32_t removeIdx); +int32_t CalcFreqLimiter(uint8_t *freqLimiter, uint8_t *patchNumSubbands, uint8_t *freqLow, int32_t nLow, int32_t kStart, + int32_t limiterBands, int32_t numPatches); +int32_t CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int32_t sampRateIdx); +void EstimateEnvelope(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int32_t env); +int32_t GetSMapped(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t env, int32_t band, int32_t la); +void CalcMaxGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int32_t ch, int32_t env, int32_t lim, int32_t fbitsDQ); +void CalcNoiseDivFactors(int32_t q, int32_t *qp1Inv, int32_t *qqp1Inv); +void CalcComponentGains(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch, int32_t env, int32_t lim, int32_t fbitsDQ); +void ApplyBoost(SBRFreq *sbrFreq, int32_t lim, int32_t fbitsDQ); +void CalcGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch, int32_t env); +void MapHF(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t env, int32_t hfReset); +void AdjustHighFreq(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch); +int32_t CalcCovariance1(int32_t *XBuf, int32_t *p01reN, int32_t *p01imN, int32_t *p12reN, int32_t *p12imN, int32_t *p11reN, int32_t *p22reN); +int32_t CalcCovariance2(int32_t *XBuf, int32_t *p02reN, int32_t *p02imN); +void CalcLPCoefs(int32_t *XBuf, int32_t *a0re, int32_t *a0im, int32_t *a1re, int32_t *a1im, int32_t gb); +void GenerateHighFreq(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch); +int32_t DecodeHuffmanScalar(const int16_t *huffTab, const HuffInfo_t *huffTabInfo, uint32_t bitBuf, int32_t *val); +int32_t DecodeOneSymbol(int32_t huffTabIndex); +int32_t DequantizeEnvelope(int32_t nBands, int32_t ampRes, int8_t *envQuant, int32_t *envDequant); +void DequantizeNoise(int32_t nBands, int8_t *noiseQuant, int32_t *noiseDequant); +void DecodeSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch); +void DecodeSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int32_t ch); +void UncoupleSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR); +void UncoupleSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR); +void DecWindowOverlapNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapLongStartNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapLongStopNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev); +void DecWindowOverlapShortNoClip(int32_t *buf0, int32_t *over0, int32_t *out0, int32_t winTypeCurr, int32_t winTypePrev); +void PreMultiply64(int32_t *zbuf1); +void PostMultiply64(int32_t *fft1, int32_t nSampsOut); +void QMFAnalysisConv(int32_t *cTab, int32_t *delay, int32_t dIdx, int32_t *uBuf); +int32_t QMFAnalysis(int32_t *inbuf, int32_t *delay, int32_t *XBuf, int32_t fBitsIn, int32_t *delayIdx, int32_t qmfaBands); +void QMFSynthesisConv(int32_t *cPtr, int32_t *delay, int32_t dIdx, int16_t *outbuf, int32_t nChans); +void QMFSynthesis(int32_t *inbuf, int32_t *delay, int32_t *delayIdx, int32_t qmfsBands, int16_t *outbuf, int32_t nChans); +int32_t UnpackSBRHeader(SBRHeader *sbrHdr); +void UnpackSBRGrid(SBRHeader *sbrHdr, SBRGrid *sbrGrid); +void UnpackDeltaTimeFreq(int32_t numEnv, uint8_t *deltaFlagEnv, int32_t numNoiseFloors, uint8_t *deltaFlagNoise); +void UnpackInverseFilterMode(int32_t numNoiseFloorBands, uint8_t *mode); +void UnpackSinusoids(int32_t nHigh, int32_t addHarmonicFlag, uint8_t *addHarmonic); +void CopyCouplingGrid(SBRGrid *sbrGridLeft, SBRGrid *sbrGridRight); +void CopyCouplingInverseFilterMode(int32_t numNoiseFloorBands, uint8_t *modeLeft, uint8_t *modeRight); +void UnpackSBRSingleChannel(int32_t chBase); +void UnpackSBRChannelPair(int32_t chBase); + +inline uint8_t AACGetSBR(){return 0;} +inline uint8_t AACGetParametricStereo(){return 0;} +const char* AACGetErrorMessage(uint8_t errorCode); diff --git a/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.cpp_ b/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.cpp_ new file mode 100644 index 0000000..2f0331e --- /dev/null +++ b/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.cpp_ @@ -0,0 +1,4275 @@ +/* + * mp3_decoder.cpp + * libhelix_HMP3DECODER + * + * Created on: 26.10.2018 + * Updated on: 09.07.2025 + */ +#include "mp3_decoder.h" +/* clip to range [-2^n, 2^n - 1] */ +#if 0 //Fast on ARM: +#define CLIP_2N(y, n) { \ + int32_t sign = (y) >> 31; \ + if (sign != (y) >> (n)) { \ + (y) = sign ^ ((1 << (n)) - 1); \ + } \ +} +#else //on xtensa this is faster, due to asm min/max instructions: +#define CLIP_2N(y, n) { \ + int32_t x = 1 << n; \ + if (y < -x) y = -x; \ + x--; \ + if (y > x) y = x; \ +} +#endif + +const uint8_t m_SYNCWORDH =0xff; +const uint8_t m_SYNCWORDL =0xe0; +const uint8_t m_DQ_FRACBITS_OUT =25; // number of fraction bits in output of dequant +const uint8_t m_CSHIFT =12; // coefficients have 12 leading sign bits for early-terminating mulitplies +const uint8_t m_SIBYTES_MPEG1_MONO =17; +const uint8_t m_SIBYTES_MPEG1_STEREO =32; +const uint8_t m_SIBYTES_MPEG2_MONO =9; +const uint8_t m_SIBYTES_MPEG2_STEREO =17; +const uint8_t m_IMDCT_SCALE =2; // additional scaling (by sqrt(2)) for fast IMDCT36 +const uint8_t m_NGRANS_MPEG1 =2; +const uint8_t m_NGRANS_MPEG2 =1; +const uint32_t m_SQRTHALF =0x5a82799a; // sqrt(0.5) in Q31 format + + +MP3FrameInfo_t *m_MP3FrameInfo; +SFBandTable_t m_SFBandTable; +StereoMode_t m_sMode; /* mono/stereo mode */ +MPEGVersion_t m_MPEGVersion; /* version ID */ +FrameHeader_t *m_FrameHeader; +SideInfoSub_t m_SideInfoSub[m_MAX_NGRAN][m_MAX_NCHAN]; +SideInfo_t *m_SideInfo; +CriticalBandInfo_t m_CriticalBandInfo[m_MAX_NCHAN]; /* filled in dequantizer, used in joint stereo reconstruction */ +DequantInfo_t *m_DequantInfo; +HuffmanInfo_t *m_HuffmanInfo; +IMDCTInfo_t *m_IMDCTInfo; +ScaleFactorInfoSub_t m_ScaleFactorInfoSub[m_MAX_NGRAN][m_MAX_NCHAN]; +ScaleFactorJS_t *m_ScaleFactorJS; +SubbandInfo_t *m_SubbandInfo; +MP3DecInfo_t *m_MP3DecInfo; + +const uint16_t huffTable[4242] PROGMEM = { + /* huffTable01[9] */ + 0xf003, 0x3112, 0x3101, 0x2011, 0x2011, 0x1000, 0x1000, 0x1000, 0x1000, + /* huffTable02[65] */ + 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, 0x5021, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + /* huffTable03[65] */ + 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, 0x5021, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2101, 0x2101, 0x2101, + 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, + 0x2101, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + /* huffTable05[257] */ + 0xf008, 0x8332, 0x8322, 0x7232, 0x7232, 0x6132, 0x6132, 0x6132, 0x6132, 0x7312, 0x7312, 0x7301, + 0x7301, 0x7031, 0x7031, 0x7222, 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, + 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + /* huffTable06[129] */ + 0xf007, 0x7332, 0x7301, 0x6322, 0x6322, 0x6232, 0x6232, 0x6031, 0x6031, 0x5312, 0x5312, 0x5312, + 0x5312, 0x5132, 0x5132, 0x5132, 0x5132, 0x5222, 0x5222, 0x5222, 0x5222, 0x5201, 0x5201, 0x5201, + 0x5201, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, + 0x4021, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + /* huffTable07[110] */ + 0xf006, 0x0041, 0x0052, 0x005b, 0x0060, 0x0063, 0x0068, 0x006b, 0x6212, 0x5122, 0x5122, 0x6201, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf004, 0x4552, 0x4542, 0x4452, 0x4352, 0x3532, 0x3532, + 0x3442, 0x3442, 0x3522, 0x3522, 0x3252, 0x3252, 0x2512, 0x2512, 0x2512, 0x2512, 0xf003, 0x2152, + 0x2152, 0x3501, 0x3432, 0x2051, 0x2051, 0x3342, 0x3332, 0xf002, 0x2422, 0x2242, 0x1412, 0x1412, + 0xf001, 0x1142, 0x1041, 0xf002, 0x2401, 0x2322, 0x2232, 0x2301, 0xf001, 0x1312, 0x1132, 0xf001, + 0x1031, 0x1222, + /* huffTable08[280] */ + 0xf008, 0x0101, 0x010a, 0x010f, 0x8512, 0x8152, 0x0112, 0x0115, 0x8422, 0x8242, 0x8412, 0x7142, + 0x7142, 0x8401, 0x8041, 0x8322, 0x8232, 0x8312, 0x8132, 0x8301, 0x8031, 0x6222, 0x6222, 0x6222, + 0x6222, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0xf003, 0x3552, 0x3452, 0x2542, 0x2542, 0x1352, 0x1352, + 0x1352, 0x1352, 0xf002, 0x2532, 0x2442, 0x1522, 0x1522, 0xf001, 0x1252, 0x1501, 0xf001, 0x1432, + 0x1342, 0xf001, 0x1051, 0x1332, + /* huffTable09[93] */ + 0xf006, 0x0041, 0x004a, 0x004f, 0x0052, 0x0057, 0x005a, 0x6412, 0x6142, 0x6322, 0x6232, 0x5312, + 0x5312, 0x5132, 0x5132, 0x6301, 0x6031, 0x5222, 0x5222, 0x5201, 0x5201, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4021, 0x4021, 0x4021, 0x4021, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0xf003, 0x3552, 0x3542, 0x2532, 0x2532, 0x2352, 0x2352, + 0x3452, 0x3501, 0xf002, 0x2442, 0x2522, 0x2252, 0x2512, 0xf001, 0x1152, 0x1432, 0xf002, 0x1342, + 0x1342, 0x2051, 0x2401, 0xf001, 0x1422, 0x1242, 0xf001, 0x1332, 0x1041, + /* huffTable10[320] */ + 0xf008, 0x0101, 0x010a, 0x010f, 0x0118, 0x011b, 0x0120, 0x0125, 0x8712, 0x8172, 0x012a, 0x012d, + 0x0132, 0x8612, 0x8162, 0x8061, 0x0137, 0x013a, 0x013d, 0x8412, 0x8142, 0x8041, 0x8322, 0x8232, + 0x8301, 0x7312, 0x7312, 0x7132, 0x7132, 0x7031, 0x7031, 0x7222, 0x7222, 0x6212, 0x6212, 0x6212, + 0x6212, 0x6122, 0x6122, 0x6122, 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf003, 0x3772, 0x3762, 0x3672, 0x3752, 0x3572, 0x3662, + 0x2742, 0x2742, 0xf002, 0x2472, 0x2652, 0x2562, 0x2732, 0xf003, 0x2372, 0x2372, 0x2642, 0x2642, + 0x3552, 0x3452, 0x2362, 0x2362, 0xf001, 0x1722, 0x1272, 0xf002, 0x2462, 0x2701, 0x1071, 0x1071, + 0xf002, 0x1262, 0x1262, 0x2542, 0x2532, 0xf002, 0x1601, 0x1601, 0x2352, 0x2442, 0xf001, 0x1632, + 0x1622, 0xf002, 0x2522, 0x2252, 0x1512, 0x1512, 0xf002, 0x1152, 0x1152, 0x2432, 0x2342, 0xf001, + 0x1501, 0x1051, 0xf001, 0x1422, 0x1242, 0xf001, 0x1332, 0x1401, + /* huffTable11[296] */ + 0xf008, 0x0101, 0x0106, 0x010f, 0x0114, 0x0117, 0x8722, 0x8272, 0x011c, 0x7172, 0x7172, 0x8712, + 0x8071, 0x8632, 0x8362, 0x8061, 0x011f, 0x0122, 0x8512, 0x7262, 0x7262, 0x8622, 0x8601, 0x7612, + 0x7612, 0x7162, 0x7162, 0x8152, 0x8432, 0x8051, 0x0125, 0x8422, 0x8242, 0x8412, 0x8142, 0x8401, + 0x8041, 0x7322, 0x7322, 0x7232, 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, + 0x6132, 0x7301, 0x7301, 0x7031, 0x7031, 0x6222, 0x6222, 0x6222, 0x6222, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x5201, 0x5201, 0x5201, + 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, + 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0xf002, 0x2772, 0x2762, 0x2672, 0x2572, 0xf003, 0x2662, + 0x2662, 0x2742, 0x2742, 0x2472, 0x2472, 0x3752, 0x3552, 0xf002, 0x2652, 0x2562, 0x1732, 0x1732, + 0xf001, 0x1372, 0x1642, 0xf002, 0x2542, 0x2452, 0x2532, 0x2352, 0xf001, 0x1462, 0x1701, 0xf001, + 0x1442, 0x1522, 0xf001, 0x1252, 0x1501, 0xf001, 0x1342, 0x1332, + /* huffTable12[185] */ + 0xf007, 0x0081, 0x008a, 0x008f, 0x0092, 0x0097, 0x009a, 0x009d, 0x00a2, 0x00a5, 0x00a8, 0x7622, + 0x7262, 0x7162, 0x00ad, 0x00b0, 0x00b3, 0x7512, 0x7152, 0x7432, 0x7342, 0x00b6, 0x7422, 0x7242, + 0x7412, 0x6332, 0x6332, 0x6142, 0x6142, 0x6322, 0x6322, 0x6232, 0x6232, 0x7041, 0x7301, 0x6031, + 0x6031, 0x5312, 0x5312, 0x5312, 0x5312, 0x5132, 0x5132, 0x5132, 0x5132, 0x5222, 0x5222, 0x5222, + 0x5222, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, + 0x5021, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0xf003, 0x3772, 0x3762, + 0x2672, 0x2672, 0x2752, 0x2752, 0x2572, 0x2572, 0xf002, 0x2662, 0x2742, 0x2472, 0x2562, 0xf001, + 0x1652, 0x1732, 0xf002, 0x2372, 0x2552, 0x1722, 0x1722, 0xf001, 0x1272, 0x1642, 0xf001, 0x1462, + 0x1712, 0xf002, 0x1172, 0x1172, 0x2701, 0x2071, 0xf001, 0x1632, 0x1362, 0xf001, 0x1542, 0x1452, + 0xf002, 0x1442, 0x1442, 0x2601, 0x2501, 0xf001, 0x1612, 0x1061, 0xf001, 0x1532, 0x1352, 0xf001, + 0x1522, 0x1252, 0xf001, 0x1051, 0x1401, + /* huffTable13[497] */ + 0xf006, 0x0041, 0x0082, 0x00c3, 0x00e4, 0x0105, 0x0116, 0x011f, 0x0130, 0x0139, 0x013e, 0x0143, + 0x0146, 0x6212, 0x6122, 0x6201, 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, + 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf006, 0x0108, 0x0111, 0x011a, 0x0123, 0x012c, 0x0131, + 0x0136, 0x013f, 0x0144, 0x0147, 0x014c, 0x0151, 0x0156, 0x015b, 0x6f12, 0x61f2, 0x60f1, 0x0160, + 0x0163, 0x0166, 0x62e2, 0x0169, 0x6e12, 0x61e2, 0x016c, 0x016f, 0x0172, 0x0175, 0x0178, 0x017b, + 0x66c2, 0x6d32, 0x017e, 0x6d22, 0x62d2, 0x6d12, 0x67b2, 0x0181, 0x0184, 0x63c2, 0x0187, 0x6b42, + 0x51d2, 0x51d2, 0x6d01, 0x60d1, 0x6a82, 0x68a2, 0x6c42, 0x64c2, 0x6b62, 0x66b2, 0x5c32, 0x5c32, + 0x5c22, 0x5c22, 0x52c2, 0x52c2, 0x5b52, 0x5b52, 0x65b2, 0x6982, 0x5c12, 0x5c12, 0xf006, 0x51c2, + 0x51c2, 0x6892, 0x6c01, 0x50c1, 0x50c1, 0x64b2, 0x6a62, 0x66a2, 0x6972, 0x5b32, 0x5b32, 0x53b2, + 0x53b2, 0x6882, 0x6a52, 0x5b22, 0x5b22, 0x65a2, 0x6962, 0x54a2, 0x54a2, 0x6872, 0x6782, 0x5492, + 0x5492, 0x6772, 0x6672, 0x42b2, 0x42b2, 0x42b2, 0x42b2, 0x4b12, 0x4b12, 0x4b12, 0x4b12, 0x41b2, + 0x41b2, 0x41b2, 0x41b2, 0x5b01, 0x5b01, 0x50b1, 0x50b1, 0x5692, 0x5692, 0x5a42, 0x5a42, 0x5a32, + 0x5a32, 0x53a2, 0x53a2, 0x5952, 0x5952, 0x5592, 0x5592, 0x4a22, 0x4a22, 0x4a22, 0x4a22, 0x42a2, + 0x42a2, 0x42a2, 0x42a2, 0xf005, 0x4a12, 0x4a12, 0x41a2, 0x41a2, 0x5a01, 0x5862, 0x40a1, 0x40a1, + 0x5682, 0x5942, 0x4392, 0x4392, 0x5932, 0x5852, 0x5582, 0x5762, 0x4922, 0x4922, 0x4292, 0x4292, + 0x5752, 0x5572, 0x4832, 0x4832, 0x4382, 0x4382, 0x5662, 0x5742, 0x5472, 0x5652, 0x5562, 0x5372, + 0xf005, 0x3912, 0x3912, 0x3912, 0x3912, 0x3192, 0x3192, 0x3192, 0x3192, 0x4901, 0x4901, 0x4091, + 0x4091, 0x4842, 0x4842, 0x4482, 0x4482, 0x4272, 0x4272, 0x5642, 0x5462, 0x3822, 0x3822, 0x3822, + 0x3822, 0x3282, 0x3282, 0x3282, 0x3282, 0x3812, 0x3812, 0x3812, 0x3812, 0xf004, 0x4732, 0x4722, + 0x3712, 0x3712, 0x3172, 0x3172, 0x4552, 0x4701, 0x4071, 0x4632, 0x4362, 0x4542, 0x4452, 0x4622, + 0x4262, 0x4532, 0xf003, 0x2182, 0x2182, 0x3801, 0x3081, 0x3612, 0x3162, 0x3601, 0x3061, 0xf004, + 0x4352, 0x4442, 0x3522, 0x3522, 0x3252, 0x3252, 0x3501, 0x3501, 0x2512, 0x2512, 0x2512, 0x2512, + 0x2152, 0x2152, 0x2152, 0x2152, 0xf003, 0x3432, 0x3342, 0x3051, 0x3422, 0x3242, 0x3332, 0x2412, + 0x2412, 0xf002, 0x1142, 0x1142, 0x2401, 0x2041, 0xf002, 0x2322, 0x2232, 0x1312, 0x1312, 0xf001, + 0x1132, 0x1301, 0xf001, 0x1031, 0x1222, 0xf003, 0x0082, 0x008b, 0x008e, 0x0091, 0x0094, 0x0097, + 0x3ce2, 0x3dd2, 0xf003, 0x0093, 0x3eb2, 0x3be2, 0x3f92, 0x39f2, 0x3ae2, 0x3db2, 0x3bd2, 0xf003, + 0x3f82, 0x38f2, 0x3cc2, 0x008d, 0x3e82, 0x0090, 0x27f2, 0x27f2, 0xf003, 0x2ad2, 0x2ad2, 0x3da2, + 0x3cb2, 0x3bc2, 0x36f2, 0x2f62, 0x2f62, 0xf002, 0x28e2, 0x2f52, 0x2d92, 0x29d2, 0xf002, 0x25f2, + 0x27e2, 0x2ca2, 0x2bb2, 0xf003, 0x2f42, 0x2f42, 0x24f2, 0x24f2, 0x3ac2, 0x36e2, 0x23f2, 0x23f2, + 0xf002, 0x1f32, 0x1f32, 0x2d82, 0x28d2, 0xf001, 0x1f22, 0x12f2, 0xf002, 0x2e62, 0x2c92, 0x1f01, + 0x1f01, 0xf002, 0x29c2, 0x2e52, 0x1ba2, 0x1ba2, 0xf002, 0x2d72, 0x27d2, 0x1e42, 0x1e42, 0xf002, + 0x28c2, 0x26d2, 0x1e32, 0x1e32, 0xf002, 0x19b2, 0x19b2, 0x2b92, 0x2aa2, 0xf001, 0x1ab2, 0x15e2, + 0xf001, 0x14e2, 0x1c82, 0xf001, 0x1d62, 0x13e2, 0xf001, 0x1e22, 0x1e01, 0xf001, 0x10e1, 0x1d52, + 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, 0x1b82, 0x18b2, 0xf001, 0x14d2, 0x1a92, + 0xf001, 0x19a2, 0x1c62, 0xf001, 0x13d2, 0x1b72, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1992, 0x1a72, + 0xf001, 0x17a2, 0x1792, 0xf003, 0x0023, 0x3df2, 0x2de2, 0x2de2, 0x1ff2, 0x1ff2, 0x1ff2, 0x1ff2, + 0xf001, 0x1fe2, 0x1fd2, 0xf001, 0x1ee2, 0x1fc2, 0xf001, 0x1ed2, 0x1fb2, 0xf001, 0x1bf2, 0x1ec2, + 0xf002, 0x1cd2, 0x1cd2, 0x2fa2, 0x29e2, 0xf001, 0x1af2, 0x1dc2, 0xf001, 0x1ea2, 0x1e92, 0xf001, + 0x1f72, 0x1e72, 0xf001, 0x1ef2, 0x1cf2, + /* huffTable15[580] */ + 0xf008, 0x0101, 0x0122, 0x0143, 0x0154, 0x0165, 0x0176, 0x017f, 0x0188, 0x0199, 0x01a2, 0x01ab, + 0x01b4, 0x01bd, 0x01c2, 0x01cb, 0x01d4, 0x01d9, 0x01de, 0x01e3, 0x01e8, 0x01ed, 0x01f2, 0x01f7, + 0x01fc, 0x0201, 0x0204, 0x0207, 0x020a, 0x020f, 0x0212, 0x0215, 0x021a, 0x021d, 0x0220, 0x8192, + 0x0223, 0x0226, 0x0229, 0x022c, 0x022f, 0x8822, 0x8282, 0x8812, 0x8182, 0x0232, 0x0235, 0x0238, + 0x023b, 0x8722, 0x8272, 0x8462, 0x8712, 0x8552, 0x8172, 0x023e, 0x8632, 0x8362, 0x8542, 0x8452, + 0x8622, 0x8262, 0x8612, 0x0241, 0x8532, 0x7162, 0x7162, 0x8352, 0x8442, 0x7522, 0x7522, 0x7252, + 0x7252, 0x7512, 0x7512, 0x7152, 0x7152, 0x8501, 0x8051, 0x7432, 0x7432, 0x7342, 0x7342, 0x7422, + 0x7422, 0x7242, 0x7242, 0x7332, 0x7332, 0x6142, 0x6142, 0x6142, 0x6142, 0x7412, 0x7412, 0x7401, + 0x7401, 0x6322, 0x6322, 0x6322, 0x6322, 0x6232, 0x6232, 0x6232, 0x6232, 0x7041, 0x7041, 0x7301, + 0x7301, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6031, 0x6031, 0x6031, + 0x6031, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, + 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0xf005, 0x5ff2, 0x5fe2, 0x5ef2, 0x5fd2, 0x4ee2, 0x4ee2, + 0x5df2, 0x5fc2, 0x5cf2, 0x5ed2, 0x5de2, 0x5fb2, 0x4bf2, 0x4bf2, 0x5ec2, 0x5ce2, 0x4dd2, 0x4dd2, + 0x4fa2, 0x4fa2, 0x4af2, 0x4af2, 0x4eb2, 0x4eb2, 0x4be2, 0x4be2, 0x4dc2, 0x4dc2, 0x4cd2, 0x4cd2, + 0x4f92, 0x4f92, 0xf005, 0x49f2, 0x49f2, 0x4ae2, 0x4ae2, 0x4db2, 0x4db2, 0x4bd2, 0x4bd2, 0x4f82, + 0x4f82, 0x48f2, 0x48f2, 0x4cc2, 0x4cc2, 0x4e92, 0x4e92, 0x49e2, 0x49e2, 0x4f72, 0x4f72, 0x47f2, + 0x47f2, 0x4da2, 0x4da2, 0x4ad2, 0x4ad2, 0x4cb2, 0x4cb2, 0x4f62, 0x4f62, 0x5ea2, 0x5f01, 0xf004, + 0x3bc2, 0x3bc2, 0x36f2, 0x36f2, 0x4e82, 0x48e2, 0x4f52, 0x4d92, 0x35f2, 0x35f2, 0x3e72, 0x3e72, + 0x37e2, 0x37e2, 0x3ca2, 0x3ca2, 0xf004, 0x3ac2, 0x3ac2, 0x3bb2, 0x3bb2, 0x49d2, 0x4d82, 0x3f42, + 0x3f42, 0x34f2, 0x34f2, 0x3f32, 0x3f32, 0x33f2, 0x33f2, 0x38d2, 0x38d2, 0xf004, 0x36e2, 0x36e2, + 0x3f22, 0x3f22, 0x32f2, 0x32f2, 0x4e62, 0x40f1, 0x3f12, 0x3f12, 0x31f2, 0x31f2, 0x3c92, 0x3c92, + 0x39c2, 0x39c2, 0xf003, 0x3e52, 0x3ba2, 0x3ab2, 0x35e2, 0x3d72, 0x37d2, 0x3e42, 0x34e2, 0xf003, + 0x3c82, 0x38c2, 0x3e32, 0x3d62, 0x36d2, 0x33e2, 0x3b92, 0x39b2, 0xf004, 0x3e22, 0x3e22, 0x3aa2, + 0x3aa2, 0x32e2, 0x32e2, 0x3e12, 0x3e12, 0x31e2, 0x31e2, 0x4e01, 0x40e1, 0x3d52, 0x3d52, 0x35d2, + 0x35d2, 0xf003, 0x3c72, 0x37c2, 0x3d42, 0x3b82, 0x24d2, 0x24d2, 0x38b2, 0x3a92, 0xf003, 0x39a2, + 0x3c62, 0x36c2, 0x3d32, 0x23d2, 0x23d2, 0x22d2, 0x22d2, 0xf003, 0x3d22, 0x3d01, 0x2d12, 0x2d12, + 0x2b72, 0x2b72, 0x27b2, 0x27b2, 0xf003, 0x21d2, 0x21d2, 0x3c52, 0x30d1, 0x25c2, 0x25c2, 0x2a82, + 0x2a82, 0xf002, 0x28a2, 0x2c42, 0x24c2, 0x2b62, 0xf003, 0x26b2, 0x26b2, 0x3992, 0x3c01, 0x2c32, + 0x2c32, 0x23c2, 0x23c2, 0xf003, 0x2a72, 0x2a72, 0x27a2, 0x27a2, 0x26a2, 0x26a2, 0x30c1, 0x3b01, + 0xf002, 0x12c2, 0x12c2, 0x2c22, 0x2b52, 0xf002, 0x25b2, 0x2c12, 0x2982, 0x2892, 0xf002, 0x21c2, + 0x2b42, 0x24b2, 0x2a62, 0xf002, 0x2b32, 0x2972, 0x13b2, 0x13b2, 0xf002, 0x2792, 0x2882, 0x2b22, + 0x2a52, 0xf002, 0x12b2, 0x12b2, 0x25a2, 0x2b12, 0xf002, 0x11b2, 0x11b2, 0x20b1, 0x2962, 0xf002, + 0x2692, 0x2a42, 0x24a2, 0x2872, 0xf002, 0x2782, 0x2a32, 0x13a2, 0x13a2, 0xf001, 0x1952, 0x1592, + 0xf001, 0x1a22, 0x12a2, 0xf001, 0x1a12, 0x11a2, 0xf002, 0x2a01, 0x20a1, 0x1862, 0x1862, 0xf001, + 0x1682, 0x1942, 0xf001, 0x1492, 0x1932, 0xf002, 0x1392, 0x1392, 0x2772, 0x2901, 0xf001, 0x1852, + 0x1582, 0xf001, 0x1922, 0x1762, 0xf001, 0x1672, 0x1292, 0xf001, 0x1912, 0x1091, 0xf001, 0x1842, + 0x1482, 0xf001, 0x1752, 0x1572, 0xf001, 0x1832, 0x1382, 0xf001, 0x1662, 0x1742, 0xf001, 0x1472, + 0x1801, 0xf001, 0x1081, 0x1652, 0xf001, 0x1562, 0x1732, 0xf001, 0x1372, 0x1642, 0xf001, 0x1701, + 0x1071, 0xf001, 0x1601, 0x1061, + /* huffTable16[651] */ + 0xf008, 0x0101, 0x010a, 0x0113, 0x8ff2, 0x0118, 0x011d, 0x0120, 0x82f2, 0x0131, 0x8f12, 0x81f2, + 0x0134, 0x0145, 0x0156, 0x0167, 0x0178, 0x0189, 0x019a, 0x01a3, 0x01ac, 0x01b5, 0x01be, 0x01c7, + 0x01d0, 0x01d9, 0x01de, 0x01e3, 0x01e6, 0x01eb, 0x01f0, 0x8152, 0x01f3, 0x01f6, 0x01f9, 0x01fc, + 0x8412, 0x8142, 0x01ff, 0x8322, 0x8232, 0x7312, 0x7312, 0x7132, 0x7132, 0x8301, 0x8031, 0x7222, + 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, 0x6122, 0x6201, 0x6201, 0x6201, + 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf003, 0x3fe2, 0x3ef2, 0x3fd2, 0x3df2, 0x3fc2, 0x3cf2, + 0x3fb2, 0x3bf2, 0xf003, 0x2fa2, 0x2fa2, 0x3af2, 0x3f92, 0x39f2, 0x38f2, 0x2f82, 0x2f82, 0xf002, + 0x2f72, 0x27f2, 0x2f62, 0x26f2, 0xf002, 0x2f52, 0x25f2, 0x1f42, 0x1f42, 0xf001, 0x14f2, 0x13f2, + 0xf004, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x2f32, 0x2f32, 0x2f32, + 0x2f32, 0x00e2, 0x00f3, 0x00fc, 0x0105, 0xf001, 0x1f22, 0x1f01, 0xf004, 0x00fa, 0x00ff, 0x0104, + 0x0109, 0x010c, 0x0111, 0x0116, 0x0119, 0x011e, 0x0123, 0x0128, 0x43e2, 0x012d, 0x0130, 0x0133, + 0x0136, 0xf004, 0x0128, 0x012b, 0x012e, 0x4d01, 0x0131, 0x0134, 0x0137, 0x4c32, 0x013a, 0x4c12, + 0x40c1, 0x013d, 0x32e2, 0x32e2, 0x4e22, 0x4e12, 0xf004, 0x43d2, 0x4d22, 0x42d2, 0x41d2, 0x4b32, + 0x012f, 0x3d12, 0x3d12, 0x44c2, 0x4b62, 0x43c2, 0x47a2, 0x3c22, 0x3c22, 0x42c2, 0x45b2, 0xf004, + 0x41c2, 0x4c01, 0x4b42, 0x44b2, 0x4a62, 0x46a2, 0x33b2, 0x33b2, 0x4a52, 0x45a2, 0x3b22, 0x3b22, + 0x32b2, 0x32b2, 0x3b12, 0x3b12, 0xf004, 0x31b2, 0x31b2, 0x4b01, 0x40b1, 0x4962, 0x4692, 0x4a42, + 0x44a2, 0x4872, 0x4782, 0x33a2, 0x33a2, 0x4a32, 0x4952, 0x3a22, 0x3a22, 0xf004, 0x4592, 0x4862, + 0x31a2, 0x31a2, 0x4682, 0x4772, 0x3492, 0x3492, 0x4942, 0x4752, 0x3762, 0x3762, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0xf003, 0x2a12, 0x2a12, 0x3a01, 0x30a1, 0x3932, 0x3392, 0x3852, 0x3582, 0xf003, + 0x2922, 0x2922, 0x2292, 0x2292, 0x3672, 0x3901, 0x2912, 0x2912, 0xf003, 0x2192, 0x2192, 0x3091, + 0x3842, 0x3482, 0x3572, 0x3832, 0x3382, 0xf003, 0x3662, 0x3822, 0x2282, 0x2282, 0x3742, 0x3472, + 0x2812, 0x2812, 0xf003, 0x2182, 0x2182, 0x2081, 0x2081, 0x3801, 0x3652, 0x2732, 0x2732, 0xf003, + 0x2372, 0x2372, 0x3562, 0x3642, 0x2722, 0x2722, 0x2272, 0x2272, 0xf003, 0x3462, 0x3552, 0x2701, + 0x2701, 0x1712, 0x1712, 0x1712, 0x1712, 0xf002, 0x1172, 0x1172, 0x2071, 0x2632, 0xf002, 0x2362, + 0x2542, 0x2452, 0x2622, 0xf001, 0x1262, 0x1612, 0xf002, 0x1162, 0x1162, 0x2601, 0x2061, 0xf002, + 0x1352, 0x1352, 0x2532, 0x2442, 0xf001, 0x1522, 0x1252, 0xf001, 0x1512, 0x1501, 0xf001, 0x1432, + 0x1342, 0xf001, 0x1051, 0x1422, 0xf001, 0x1242, 0x1332, 0xf001, 0x1401, 0x1041, 0xf004, 0x4ec2, + 0x0086, 0x3ed2, 0x3ed2, 0x39e2, 0x39e2, 0x4ae2, 0x49d2, 0x2ee2, 0x2ee2, 0x2ee2, 0x2ee2, 0x3de2, + 0x3de2, 0x3be2, 0x3be2, 0xf003, 0x2eb2, 0x2eb2, 0x2dc2, 0x2dc2, 0x3cd2, 0x3bd2, 0x2ea2, 0x2ea2, + 0xf003, 0x2cc2, 0x2cc2, 0x3da2, 0x3ad2, 0x3e72, 0x3ca2, 0x2ac2, 0x2ac2, 0xf003, 0x39c2, 0x3d72, + 0x2e52, 0x2e52, 0x1db2, 0x1db2, 0x1db2, 0x1db2, 0xf002, 0x1e92, 0x1e92, 0x2cb2, 0x2bc2, 0xf002, + 0x2e82, 0x28e2, 0x2d92, 0x27e2, 0xf002, 0x2bb2, 0x2d82, 0x28d2, 0x2e62, 0xf001, 0x16e2, 0x1c92, + 0xf002, 0x2ba2, 0x2ab2, 0x25e2, 0x27d2, 0xf002, 0x1e42, 0x1e42, 0x24e2, 0x2c82, 0xf001, 0x18c2, + 0x1e32, 0xf002, 0x1d62, 0x1d62, 0x26d2, 0x2b92, 0xf002, 0x29b2, 0x2aa2, 0x11e2, 0x11e2, 0xf002, + 0x14d2, 0x14d2, 0x28b2, 0x29a2, 0xf002, 0x1b72, 0x1b72, 0x27b2, 0x20d1, 0xf001, 0x1e01, 0x10e1, + 0xf001, 0x1d52, 0x15d2, 0xf001, 0x1c72, 0x17c2, 0xf001, 0x1d42, 0x1b82, 0xf001, 0x1a92, 0x1c62, + 0xf001, 0x16c2, 0x1d32, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1a82, 0x18a2, 0xf001, 0x1992, 0x1c42, + 0xf001, 0x16b2, 0x1a72, 0xf001, 0x1b52, 0x1982, 0xf001, 0x1892, 0x1972, 0xf001, 0x1792, 0x1882, + 0xf001, 0x1ce2, 0x1dd2, + /* huffTable24[705] */ + 0xf009, 0x8fe2, 0x8fe2, 0x8ef2, 0x8ef2, 0x8fd2, 0x8fd2, 0x8df2, 0x8df2, 0x8fc2, 0x8fc2, 0x8cf2, + 0x8cf2, 0x8fb2, 0x8fb2, 0x8bf2, 0x8bf2, 0x7af2, 0x7af2, 0x7af2, 0x7af2, 0x8fa2, 0x8fa2, 0x8f92, + 0x8f92, 0x79f2, 0x79f2, 0x79f2, 0x79f2, 0x78f2, 0x78f2, 0x78f2, 0x78f2, 0x8f82, 0x8f82, 0x8f72, + 0x8f72, 0x77f2, 0x77f2, 0x77f2, 0x77f2, 0x7f62, 0x7f62, 0x7f62, 0x7f62, 0x76f2, 0x76f2, 0x76f2, + 0x76f2, 0x7f52, 0x7f52, 0x7f52, 0x7f52, 0x75f2, 0x75f2, 0x75f2, 0x75f2, 0x7f42, 0x7f42, 0x7f42, + 0x7f42, 0x74f2, 0x74f2, 0x74f2, 0x74f2, 0x7f32, 0x7f32, 0x7f32, 0x7f32, 0x73f2, 0x73f2, 0x73f2, + 0x73f2, 0x7f22, 0x7f22, 0x7f22, 0x7f22, 0x72f2, 0x72f2, 0x72f2, 0x72f2, 0x71f2, 0x71f2, 0x71f2, + 0x71f2, 0x8f12, 0x8f12, 0x80f1, 0x80f1, 0x9f01, 0x0201, 0x0206, 0x020b, 0x0210, 0x0215, 0x021a, + 0x021f, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x0224, 0x0229, 0x0232, + 0x0237, 0x023a, 0x023f, 0x0242, 0x0245, 0x024a, 0x024d, 0x0250, 0x0253, 0x0256, 0x0259, 0x025c, + 0x025f, 0x0262, 0x0265, 0x0268, 0x026b, 0x026e, 0x0271, 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, + 0x0283, 0x0288, 0x028b, 0x028e, 0x0291, 0x0294, 0x0297, 0x029a, 0x029f, 0x94b2, 0x02a4, 0x02a7, + 0x02aa, 0x93b2, 0x9882, 0x02af, 0x92b2, 0x02b2, 0x02b5, 0x9692, 0x94a2, 0x02b8, 0x9782, 0x9a32, + 0x93a2, 0x9952, 0x9592, 0x9a22, 0x92a2, 0x91a2, 0x9862, 0x9682, 0x9772, 0x9942, 0x9492, 0x9932, + 0x9392, 0x9852, 0x9582, 0x9922, 0x9762, 0x9672, 0x9292, 0x9912, 0x9192, 0x9842, 0x9482, 0x9752, + 0x9572, 0x9832, 0x9382, 0x9662, 0x9822, 0x9282, 0x9812, 0x9742, 0x9472, 0x9182, 0x02bb, 0x9652, + 0x9562, 0x9712, 0x02be, 0x8372, 0x8372, 0x9732, 0x9722, 0x8272, 0x8272, 0x8642, 0x8642, 0x8462, + 0x8462, 0x8552, 0x8552, 0x8172, 0x8172, 0x8632, 0x8632, 0x8362, 0x8362, 0x8542, 0x8542, 0x8452, + 0x8452, 0x8622, 0x8622, 0x8262, 0x8262, 0x8612, 0x8612, 0x8162, 0x8162, 0x9601, 0x9061, 0x8532, + 0x8532, 0x8352, 0x8352, 0x8442, 0x8442, 0x8522, 0x8522, 0x8252, 0x8252, 0x8512, 0x8512, 0x9501, + 0x9051, 0x7152, 0x7152, 0x7152, 0x7152, 0x8432, 0x8432, 0x8342, 0x8342, 0x7422, 0x7422, 0x7422, + 0x7422, 0x7242, 0x7242, 0x7242, 0x7242, 0x7332, 0x7332, 0x7332, 0x7332, 0x7412, 0x7412, 0x7412, + 0x7412, 0x7142, 0x7142, 0x7142, 0x7142, 0x8401, 0x8401, 0x8041, 0x8041, 0x7322, 0x7322, 0x7322, + 0x7322, 0x7232, 0x7232, 0x7232, 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, + 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x7301, 0x7301, 0x7301, + 0x7301, 0x7031, 0x7031, 0x7031, 0x7031, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, + 0x6222, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x6201, 0x6201, 0x6201, + 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0xf002, 0x2ee2, 0x2ed2, + 0x2de2, 0x2ec2, 0xf002, 0x2ce2, 0x2dd2, 0x2eb2, 0x2be2, 0xf002, 0x2dc2, 0x2cd2, 0x2ea2, 0x2ae2, + 0xf002, 0x2db2, 0x2bd2, 0x2cc2, 0x2e92, 0xf002, 0x29e2, 0x2da2, 0x2ad2, 0x2cb2, 0xf002, 0x2bc2, + 0x2e82, 0x28e2, 0x2d92, 0xf002, 0x29d2, 0x2e72, 0x27e2, 0x2ca2, 0xf002, 0x2ac2, 0x2bb2, 0x2d82, + 0x28d2, 0xf003, 0x3e01, 0x30e1, 0x2d01, 0x2d01, 0x16e2, 0x16e2, 0x16e2, 0x16e2, 0xf002, 0x2e62, + 0x2c92, 0x19c2, 0x19c2, 0xf001, 0x1e52, 0x1ab2, 0xf002, 0x15e2, 0x15e2, 0x2ba2, 0x2d72, 0xf001, + 0x17d2, 0x14e2, 0xf001, 0x1c82, 0x18c2, 0xf002, 0x2e42, 0x2e22, 0x1e32, 0x1e32, 0xf001, 0x1d62, + 0x16d2, 0xf001, 0x13e2, 0x1b92, 0xf001, 0x19b2, 0x1aa2, 0xf001, 0x12e2, 0x1e12, 0xf001, 0x11e2, + 0x1d52, 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, 0x1b82, 0x18b2, 0xf001, 0x14d2, + 0x1a92, 0xf001, 0x19a2, 0x1c62, 0xf001, 0x16c2, 0x1d32, 0xf001, 0x13d2, 0x1d22, 0xf001, 0x12d2, + 0x1d12, 0xf001, 0x1b72, 0x17b2, 0xf001, 0x11d2, 0x1c52, 0xf001, 0x15c2, 0x1a82, 0xf001, 0x18a2, + 0x1992, 0xf001, 0x1c42, 0x14c2, 0xf001, 0x1b62, 0x16b2, 0xf002, 0x20d1, 0x2c01, 0x1c32, 0x1c32, + 0xf001, 0x13c2, 0x1a72, 0xf001, 0x17a2, 0x1c22, 0xf001, 0x12c2, 0x1b52, 0xf001, 0x15b2, 0x1c12, + 0xf001, 0x1982, 0x1892, 0xf001, 0x11c2, 0x1b42, 0xf002, 0x20c1, 0x2b01, 0x1b32, 0x1b32, 0xf002, + 0x20b1, 0x2a01, 0x1a12, 0x1a12, 0xf001, 0x1a62, 0x16a2, 0xf001, 0x1972, 0x1792, 0xf002, 0x20a1, + 0x2901, 0x1091, 0x1091, 0xf001, 0x1b22, 0x1a52, 0xf001, 0x15a2, 0x1b12, 0xf001, 0x11b2, 0x1962, + 0xf001, 0x1a42, 0x1872, 0xf001, 0x1801, 0x1081, 0xf001, 0x1701, 0x1071, +}; +/* pow(2,-i/4) * pow(j,4/3) for i=0..3 j=0..15, Q25 format */ +const int32_t pow43_14[4][16] PROGMEM = { /* Q28 */ +{ 0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, 0x0cb2ff53, 0x111989d6, + 0x15ce31c8, 0x1ac7f203, 0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, + 0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c, }, + +{ 0x00000000, 0x0d744fcd, 0x21e71f26, 0x3a36abd9, 0x0aadc084, 0x0e610e6e, + 0x12560c1d, 0x168523cf, 0x1ae89f99, 0x1f7c03a4, 0x243bae49, 0x29249c67, + 0x2e34420f, 0x33686f85, 0x38bf3dff, 0x3e370182, }, + +{ 0x00000000, 0x0b504f33, 0x1c823e07, 0x30f39a55, 0x08facd62, 0x0c176319, + 0x0f6b3522, 0x12efe2ad, 0x16a09e66, 0x1a79a317, 0x1e77e301, 0x2298d5b4, + 0x26da56fc, 0x2b3a902a, 0x2fb7e7e7, 0x3450f650, }, + +{ 0x00000000, 0x09837f05, 0x17f910d7, 0x2929c7a9, 0x078d0dfa, 0x0a2ae661, + 0x0cf73154, 0x0fec91cb, 0x1306fe0a, 0x16434a6c, 0x199ee595, 0x1d17ae3d, + 0x20abd76a, 0x2459d551, 0x28204fbb, 0x2bfe1808, }, +}; + +/* pow(j,4/3) for j=16..63, Q23 format */ +const int32_t pow43[48] PROGMEM = { + 0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85, 0x1b24e8bb, 0x1cf7fcfa, + 0x1ed28af2, 0x20b4582a, 0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000, + 0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99, 0x32cbfd4a, 0x34eca001, + 0x3712ca62, 0x393e6088, 0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72, + 0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3, 0x4daaebfd, 0x5007b497, + 0x5268fc62, 0x54ceb29c, 0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129, + 0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b, 0x6b1fc80c, 0x6daeaa0d, + 0x70416360, 0x72d7e8b0, 0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09, +}; + +const uint32_t polyCoef[264] PROGMEM = { + /* shuffled vs. original from 0, 1, ... 15 to 0, 15, 2, 13, ... 14, 1 */ + 0x00000000, 0x00000074, 0x00000354, 0x0000072c, 0x00001fd4, 0x00005084, 0x000066b8, 0x000249c4, + 0x00049478, 0xfffdb63c, 0x000066b8, 0xffffaf7c, 0x00001fd4, 0xfffff8d4, 0x00000354, 0xffffff8c, + 0xfffffffc, 0x00000068, 0x00000368, 0x00000644, 0x00001f40, 0x00004ad0, 0x00005d1c, 0x00022ce0, + 0x000493c0, 0xfffd9960, 0x00006f78, 0xffffa9cc, 0x0000203c, 0xfffff7e4, 0x00000340, 0xffffff84, + 0xfffffffc, 0x00000060, 0x00000378, 0x0000056c, 0x00001e80, 0x00004524, 0x000052a0, 0x00020ffc, + 0x000491a0, 0xfffd7ca0, 0x00007760, 0xffffa424, 0x00002080, 0xfffff6ec, 0x00000328, 0xffffff74, + 0xfffffffc, 0x00000054, 0x00000384, 0x00000498, 0x00001d94, 0x00003f7c, 0x00004744, 0x0001f32c, + 0x00048e18, 0xfffd6008, 0x00007e70, 0xffff9e8c, 0x0000209c, 0xfffff5ec, 0x00000310, 0xffffff68, + 0xfffffffc, 0x0000004c, 0x0000038c, 0x000003d0, 0x00001c78, 0x000039e4, 0x00003b00, 0x0001d680, + 0x00048924, 0xfffd43ac, 0x000084b0, 0xffff990c, 0x00002094, 0xfffff4e4, 0x000002f8, 0xffffff5c, + 0xfffffffc, 0x00000044, 0x00000390, 0x00000314, 0x00001b2c, 0x0000345c, 0x00002ddc, 0x0001ba04, + 0x000482d0, 0xfffd279c, 0x00008a20, 0xffff93a4, 0x0000206c, 0xfffff3d4, 0x000002dc, 0xffffff4c, + 0xfffffffc, 0x00000040, 0x00000390, 0x00000264, 0x000019b0, 0x00002ef0, 0x00001fd4, 0x00019dc8, + 0x00047b1c, 0xfffd0be8, 0x00008ecc, 0xffff8e64, 0x00002024, 0xfffff2c0, 0x000002c0, 0xffffff3c, + 0xfffffff8, 0x00000038, 0x0000038c, 0x000001bc, 0x000017fc, 0x0000299c, 0x000010e8, 0x000181d8, + 0x0004720c, 0xfffcf09c, 0x000092b4, 0xffff894c, 0x00001fc0, 0xfffff1a4, 0x000002a4, 0xffffff2c, + 0xfffffff8, 0x00000034, 0x00000380, 0x00000120, 0x00001618, 0x00002468, 0x00000118, 0x00016644, + 0x000467a4, 0xfffcd5cc, 0x000095e0, 0xffff8468, 0x00001f44, 0xfffff084, 0x00000284, 0xffffff18, + 0xfffffff8, 0x0000002c, 0x00000374, 0x00000090, 0x00001400, 0x00001f58, 0xfffff068, 0x00014b14, + 0x00045bf0, 0xfffcbb88, 0x00009858, 0xffff7fbc, 0x00001ea8, 0xffffef60, 0x00000268, 0xffffff04, + 0xfffffff8, 0x00000028, 0x0000035c, 0x00000008, 0x000011ac, 0x00001a70, 0xffffded8, 0x00013058, + 0x00044ef8, 0xfffca1d8, 0x00009a1c, 0xffff7b54, 0x00001dfc, 0xffffee3c, 0x0000024c, 0xfffffef0, + 0xfffffff4, 0x00000024, 0x00000340, 0xffffff8c, 0x00000f28, 0x000015b0, 0xffffcc70, 0x0001161c, + 0x000440bc, 0xfffc88d8, 0x00009b3c, 0xffff7734, 0x00001d38, 0xffffed18, 0x0000022c, 0xfffffedc, + 0xfffffff4, 0x00000020, 0x00000320, 0xffffff1c, 0x00000c68, 0x0000111c, 0xffffb92c, 0x0000fc6c, + 0x00043150, 0xfffc708c, 0x00009bb8, 0xffff7368, 0x00001c64, 0xffffebf4, 0x00000210, 0xfffffec4, + 0xfffffff0, 0x0000001c, 0x000002f4, 0xfffffeb4, 0x00000974, 0x00000cb8, 0xffffa518, 0x0000e350, + 0x000420b4, 0xfffc5908, 0x00009b9c, 0xffff6ff4, 0x00001b7c, 0xffffead0, 0x000001f4, 0xfffffeac, + 0xfffffff0, 0x0000001c, 0x000002c4, 0xfffffe58, 0x00000648, 0x00000884, 0xffff9038, 0x0000cad0, + 0x00040ef8, 0xfffc425c, 0x00009af0, 0xffff6ce0, 0x00001a88, 0xffffe9b0, 0x000001d4, 0xfffffe94, + 0xffffffec, 0x00000018, 0x0000028c, 0xfffffe04, 0x000002e4, 0x00000480, 0xffff7a90, 0x0000b2fc, + 0x0003fc28, 0xfffc2c90, 0x000099b8, 0xffff6a3c, 0x00001988, 0xffffe898, 0x000001bc, 0xfffffe7c, + 0x000001a0, 0x0000187c, 0x000097fc, 0x0003e84c, 0xffff6424, 0xffffff4c, 0x00000248, 0xffffffec, +}; + +/* format = Q30, range = [0.0981, 1.9976] + * + * n = 16; + * k = 0; + * for(i=0; i<5; i++, n=n/2) { + * for(p=0; pbytePtr = buf; + bsi->iCache = 0; /* 4-byte uint32_t */ + bsi->cachedBits = 0; /* i.e. zero bits in cache */ + bsi->nBytes = nBytes; +} +//---------------------------------------------------------------------------------------------------------------------- +void RefillBitstreamCache(BitStreamInfo_t *bsi) { + int32_t nBytes = bsi->nBytes; + /* optimize for common case, independent of machine endian-ness */ + if (nBytes >= 4) { + bsi->iCache = (*bsi->bytePtr++) << 24; + bsi->iCache |= (*bsi->bytePtr++) << 16; + bsi->iCache |= (*bsi->bytePtr++) << 8; + bsi->iCache |= (*bsi->bytePtr++); + bsi->cachedBits = 32; + bsi->nBytes -= 4; + } else { + bsi->iCache = 0; + while (nBytes--) { + bsi->iCache |= (*bsi->bytePtr++); + bsi->iCache <<= 8; + } + bsi->iCache <<= ((3 - bsi->nBytes) * 8); + bsi->cachedBits = 8 * bsi->nBytes; + bsi->nBytes = 0; + } +} +//---------------------------------------------------------------------------------------------------------------------- +uint32_t GetBits(BitStreamInfo_t *bsi, int32_t nBits) { + uint32_t data, lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ + data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + bsi->iCache <<= nBits; /* left-justify cache */ + bsi->cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ + if (bsi->cachedBits < 0) {/* if we cross anint32_t boundary, refill the cache */ + lowBits = -bsi->cachedBits; + RefillBitstreamCache(bsi); + data |= bsi->iCache >> (32 - lowBits); /* get the low-order bits */ + bsi->cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ + bsi->iCache <<= lowBits; /* left-justify cache */ + } + return data; +} +//---------------------------------------------------------------------------------------------------------------------- +int32_t CalcBitsUsed(BitStreamInfo_t *bsi, uint8_t *startBuf, int32_t startOffset){ + int32_t bitsUsed; + bitsUsed = (bsi->bytePtr - startBuf) * 8; + bitsUsed -= bsi->cachedBits; + bitsUsed -= startOffset; + return bitsUsed; +} +//---------------------------------------------------------------------------------------------------------------------- +int32_t CheckPadBit(){ + return (m_FrameHeader->paddingBit ? 1 : 0); +} +//---------------------------------------------------------------------------------------------------------------------- +int32_t UnpackFrameHeader(uint8_t *buf){ + int32_t verIdx; + /* validate pointers and sync word */ + if ((buf[0] & m_SYNCWORDH) != m_SYNCWORDH || (buf[1] & m_SYNCWORDL) != m_SYNCWORDL){return -1;} + /* read header fields - use bitmasks instead of GetBits() for speed, since format never varies */ + verIdx = (buf[1] >> 3) & 0x03; + m_MPEGVersion = (MPEGVersion_t) (verIdx == 0 ? MPEG25 : ((verIdx & 0x01) ? MPEG1 : MPEG2)); + m_FrameHeader->layer = 4 - ((buf[1] >> 1) & 0x03); /* easy mapping of index to layer number, 4 = error */ + m_FrameHeader->crc = 1 - ((buf[1] >> 0) & 0x01); + m_FrameHeader->brIdx = (buf[2] >> 4) & 0x0f; + m_FrameHeader->srIdx = (buf[2] >> 2) & 0x03; + m_FrameHeader->paddingBit = (buf[2] >> 1) & 0x01; + m_FrameHeader->privateBit = (buf[2] >> 0) & 0x01; + m_sMode = (StereoMode_t) ((buf[3] >> 6) & 0x03); /* maps to correct enum (see definition) */ + m_FrameHeader->modeExt = (buf[3] >> 4) & 0x03; + m_FrameHeader->copyFlag = (buf[3] >> 3) & 0x01; + m_FrameHeader->origFlag = (buf[3] >> 2) & 0x01; + m_FrameHeader->emphasis = (buf[3] >> 0) & 0x03; + /* check parameters to avoid indexing tables with bad values */ + if (m_FrameHeader->srIdx == 3 || m_FrameHeader->layer == 4 || m_FrameHeader->brIdx == 15) {return -1;} + /* for readability (we reference sfBandTable many times in decoder) */ + m_SFBandTable = sfBandTable[m_MPEGVersion][m_FrameHeader->srIdx]; + if (m_sMode != Joint) /* just to be safe (dequant, stproc check fh->modeExt) */ + m_FrameHeader->modeExt = 0; + /* init user-accessible data */ + m_MP3DecInfo->nChans = (m_sMode == Mono ? 1 : 2); + m_MP3DecInfo->samprate = samplerateTab[m_MPEGVersion][m_FrameHeader->srIdx]; + m_MP3DecInfo->nGrans = (m_MPEGVersion == MPEG1 ? m_NGRANS_MPEG1 : m_NGRANS_MPEG2); + m_MP3DecInfo->nGranSamps = ((int32_t) samplesPerFrameTab[m_MPEGVersion][m_FrameHeader->layer - 1])/m_MP3DecInfo->nGrans; + m_MP3DecInfo->layer = m_FrameHeader->layer; + + /* get bitrate and nSlots from table, unless brIdx == 0 (free mode) in which case caller must figure it out himself + * question - do we want to overwrite mp3DecInfo->bitrate with 0 each time if it's free mode, and + * copy the pre-calculated actual free bitrate into it in mp3dec.c (according to the spec, + * this shouldn't be necessary, since it should be either all frames free or none free) + */ + if (m_FrameHeader->brIdx) { + m_MP3DecInfo->bitrate=((int32_t) bitrateTab[m_MPEGVersion][m_FrameHeader->layer - 1][m_FrameHeader->brIdx]) * 1000; + /* nSlots = total frame bytes (from table) - sideInfo bytes - header - CRC (if present) + pad (if present) */ + m_MP3DecInfo->nSlots= (int32_t) slotTab[m_MPEGVersion][m_FrameHeader->srIdx][m_FrameHeader->brIdx] + - (int32_t) sideBytesTab[m_MPEGVersion][(m_sMode == Mono ? 0 : 1)] - 4 + - (m_FrameHeader->crc ? 2 : 0) + (m_FrameHeader->paddingBit ? 1 : 0); + } + /* load crc word, if enabled, and return length of frame header (in bytes) */ + if (m_FrameHeader->crc) { + m_FrameHeader->CRCWord = ((int32_t) buf[4] << 8 | (int32_t) buf[5] << 0); + return 6; + } else { + m_FrameHeader->CRCWord = 0; + return 4; + } +} +//---------------------------------------------------------------------------------------------------------------------- +int32_t UnpackSideInfo( uint8_t *buf) { + int32_t gr, ch, bd, nBytes; + BitStreamInfo_t bitStreamInfo, *bsi; + + SideInfoSub_t *sis; + /* validate pointers and sync word */ + bsi = &bitStreamInfo; + if (m_MPEGVersion == MPEG1) { + /* MPEG 1 */ + nBytes=(m_sMode == Mono ? m_SIBYTES_MPEG1_MONO : m_SIBYTES_MPEG1_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + m_SideInfo->mainDataBegin = GetBits(bsi, 9); + m_SideInfo->privateBits= GetBits(bsi, (m_sMode == Mono ? 5 : 3)); + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) + for (bd = 0; bd < m_MAX_SCFBD; bd++) m_SideInfo->scfsi[ch][bd] = GetBits(bsi, 1); + } else { + /* MPEG 2, MPEG 2.5 */ + nBytes=(m_sMode == Mono ? m_SIBYTES_MPEG2_MONO : m_SIBYTES_MPEG2_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + m_SideInfo->mainDataBegin = GetBits(bsi, 8); + m_SideInfo->privateBits = GetBits(bsi, (m_sMode == Mono ? 1 : 2)); + } + for (gr = 0; gr < m_MP3DecInfo->nGrans; gr++) { + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + sis = &m_SideInfoSub[gr][ch]; /* side info subblock for this granule, channel */ + sis->part23Length = GetBits(bsi, 12); + sis->nBigvals = GetBits(bsi, 9); + sis->globalGain = GetBits(bsi, 8); + sis->sfCompress = GetBits(bsi, (m_MPEGVersion == MPEG1 ? 4 : 9)); + sis->winSwitchFlag = GetBits(bsi, 1); + if (sis->winSwitchFlag) { + /* this is a start, stop, short, or mixed block */ + sis->blockType = GetBits(bsi, 2); /* 0 = normal, 1 = start, 2 = short, 3 = stop */ + sis->mixedBlock = GetBits(bsi, 1); /* 0 = not mixed, 1 = mixed */ + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = 0; /* unused */ + sis->subBlockGain[0] = GetBits(bsi, 3); + sis->subBlockGain[1] = GetBits(bsi, 3); + sis->subBlockGain[2] = GetBits(bsi, 3); + if (sis->blockType == 0) { + /* this should not be allowed, according to spec */ + sis->nBigvals = 0; + sis->part23Length = 0; + sis->sfCompress = 0; + } else if (sis->blockType == 2 && sis->mixedBlock == 0) { + /* short block, not mixed */ + sis->region0Count = 8; + } else { + /* start, stop, or short-mixed */ + sis->region0Count = 7; + } + sis->region1Count = 20 - sis->region0Count; + } else { + /* this is a normal block */ + sis->blockType = 0; + sis->mixedBlock = 0; + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = GetBits(bsi, 5); + sis->region0Count = GetBits(bsi, 4); + sis->region1Count = GetBits(bsi, 3); + } + sis->preFlag = (m_MPEGVersion == MPEG1 ? GetBits(bsi, 1) : 0); + sis->sfactScale = GetBits(bsi, 1); + sis->count1TableSelect = GetBits(bsi, 1); + } + } + m_MP3DecInfo->mainDataBegin = m_SideInfo->mainDataBegin; /* needed by main decode loop */ + assert(nBytes == CalcBitsUsed(bsi, buf, 0) >> 3); + return nBytes; +} +/*********************************************************************************************************************** + * Function: UnpackSFMPEG1 + * + * Description: unpack MPEG 1 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * vector of scfsi flags from side info, length = 4 (MAX_SCFBD) + * index of current granule + * ScaleFactorInfoSub from granule 0 (for granule 1, if scfsi[i] is set, + * then we just replicate the scale factors from granule 0 in the + * i'th set of scalefactor bands) + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * + * Return: none + * + * Notes: set order of short blocks to s[band][window] instead of s[window][band] + * so that we index through consectutive memory locations when unpacking + * (make sure dequantizer follows same convention) + * Illegal Intensity Position = 7 (always) for MPEG1 scale factors + **********************************************************************************************************************/ +void UnpackSFMPEG1(BitStreamInfo_t *bsi, SideInfoSub_t *sis, + ScaleFactorInfoSub_t *sfis, int32_t *scfsi, int32_t gr, ScaleFactorInfoSub_t *sfisGr0){ + int32_t sfb; + int32_t slen0, slen1; + /* these can be 0, so make sure GetBits(bsi, 0) returns 0 (no >> 32 or anything) */ + slen0 = (int32_t)m_SFLenTab[sis->sfCompress][0]; + slen1 = (int32_t)m_SFLenTab[sis->sfCompress][1]; + if (sis->blockType == 2){ + /* short block, type 2 (implies winSwitchFlag == 1) */ + if (sis->mixedBlock){ + /* do long block portion */ + for(sfb = 0; sfb < 8; sfb++) + sfis->l[sfb]=(char)GetBits(bsi, slen0); + sfb=3; + } + else { + /* all short blocks */ + sfb=0; + } + for ( ; sfb < 6; sfb++){ + sfis->s[sfb][0] = (char)GetBits(bsi, slen0); + sfis->s[sfb][1] = (char)GetBits(bsi, slen0); + sfis->s[sfb][2] = (char)GetBits(bsi, slen0); + } + for ( ; sfb < 12; sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen1); + sfis->s[sfb][1] = (char)GetBits(bsi, slen1); + sfis->s[sfb][2] = (char)GetBits(bsi, slen1); + } + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } + else{ + /* long blocks, type 0, 1, or 3 */ + if(gr == 0) { + /* first granule */ + for (sfb = 0; sfb < 11; sfb++) + sfis->l[sfb] = (char)GetBits(bsi, slen0); + for (sfb = 11; sfb < 21; sfb++) + sfis->l[sfb] = (char)GetBits(bsi, slen1); + return; + } + else{ + /* second granule + * scfsi: 0 = different scalefactors for each granule, + * 1 = copy sf's from granule 0 into granule 1 + * for block type == 2, scfsi is always 0 + */ + sfb = 0; + if(scfsi[0]) for( ; sfb < 6 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb < 6 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if(scfsi[1]) for( ; sfb <11 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <11 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if(scfsi[2]) for( ; sfb <16 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <16 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + if(scfsi[3]) for( ; sfb <21 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <21 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + } + /* last sf band not transmitted */ + sfis->l[21] = 0; + sfis->l[22] = 0; + } +} +/*********************************************************************************************************************** + * Function: UnpackSFMPEG2 + * + * Description: unpack MPEG 2 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * index of current granule and channel + * ScaleFactorInfoSub from this granule + * modeExt field from frame header, to tell whether intensity stereo is on + * ScaleFactorJS struct for storing IIP info used in Dequant() + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * updated intensityScale and preFlag flags + * + * Return: none + * + * Notes: Illegal Intensity Position = (2^slen) - 1 for MPEG2 scale factors + **********************************************************************************************************************/ +void UnpackSFMPEG2(BitStreamInfo_t *bsi, SideInfoSub_t *sis, + ScaleFactorInfoSub_t *sfis, int32_t gr, int32_t ch, int32_t modeExt, ScaleFactorJS_t *sfjs){ + + int32_t i, sfb, sfcIdx, btIdx, nrIdx;// iipTest; + int32_t slen[4], nr[4]; + int32_t sfCompress, preFlag, intensityScale; + (void)gr; + sfCompress = sis->sfCompress; + preFlag = 0; + intensityScale = 0; + + /* stereo mode bits (1 = on): bit 1 = mid-side on/off, bit 0 = intensity on/off */ + if (! ((modeExt & 0x01) && (ch == 1)) ) { + /* in other words: if ((modeExt & 0x01) == 0 || ch == 0) */ + if (sfCompress < 400) { + /* max slen = floor[(399/16) / 5] = 4 */ + slen[0] = (sfCompress >> 4) / 5; + slen[1]= (sfCompress >> 4) % 5; + slen[2]= (sfCompress & 0x0f) >> 2; + slen[3]= (sfCompress & 0x03); + sfcIdx = 0; + } + else if(sfCompress < 500){ + /* max slen = floor[(99/4) / 5] = 4 */ + sfCompress -= 400; + slen[0] = (sfCompress >> 2) / 5; + slen[1]= (sfCompress >> 2) % 5; + slen[2]= (sfCompress & 0x03); + slen[3]= 0; + sfcIdx = 1; + } + else{ + /* max slen = floor[11/3] = 3 (sfCompress = 9 bits in MPEG2) */ + sfCompress -= 500; + slen[0] = sfCompress / 3; + slen[1] = sfCompress % 3; + slen[2] = slen[3] = 0; + if (sis->mixedBlock) { + /* adjust for long/short mix logic (see comment above in NRTab[] definition) */ + slen[2] = slen[1]; + slen[1] = slen[0]; + } + preFlag = 1; + sfcIdx = 2; + } + } + else{ + /* intensity stereo ch = 1 (right) */ + intensityScale = sfCompress & 0x01; + sfCompress >>= 1; + if (sfCompress < 180) { + /* max slen = floor[35/6] = 5 (from mod 36) */ + slen[0] = (sfCompress / 36); + slen[1] = (sfCompress % 36) / 6; + slen[2] = (sfCompress % 36) % 6; + slen[3] = 0; + sfcIdx = 3; + } + else if (sfCompress < 244){ + /* max slen = floor[63/16] = 3 */ + sfCompress -= 180; + slen[0] = (sfCompress & 0x3f) >> 4; + slen[1] = (sfCompress & 0x0f) >> 2; + slen[2] = (sfCompress & 0x03); + slen[3] = 0; + sfcIdx = 4; + } + else{ + /* max slen = floor[11/3] = 3 (max sfCompress >> 1 = 511/2 = 255) */ + sfCompress -= 244; + slen[0] = (sfCompress / 3); + slen[1] = (sfCompress % 3); + slen[2] = slen[3] = 0; + sfcIdx = 5; + } + } + /* set index based on block type: (0,1,3) --> 0, (2 non-mixed) --> 1, (2 mixed) ---> 2 */ + btIdx = 0; + if (sis->blockType == 2) + btIdx = (sis->mixedBlock ? 2 : 1); + for (i = 0; i < 4; i++) + nr[i] = (int32_t)NRTab[sfcIdx][btIdx][i]; + + /* save intensity stereo scale factor info */ + if( (modeExt & 0x01) && (ch == 1) ) { + for (i = 0; i < 4; i++) { + sfjs->slen[i] = slen[i]; + sfjs->nr[i] = nr[i]; + } + sfjs->intensityScale = intensityScale; + } + sis->preFlag = preFlag; + + /* short blocks */ + if(sis->blockType == 2) { + if(sis->mixedBlock) { + /* do long block portion */ + //iipTest = (1 << slen[0]) - 1; + for (sfb=0; sfb < 6; sfb++) { + sfis->l[sfb] = (char)GetBits(bsi, slen[0]); + } + sfb = 3; /* start sfb for short */ + nrIdx = 1; + } + else{ + /* all short blocks, so start nr, sfb at 0 */ + sfb = 0; + nrIdx = 0; + } + + /* remaining short blocks, sfb just keeps incrementing */ + for( ; nrIdx <= 3; nrIdx++) { + //iipTest = (1 << slen[nrIdx]) - 1; + for(i=0; i < nr[nrIdx]; i++, sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][1] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][2] = (char)GetBits(bsi, slen[nrIdx]); + } + } + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } + else{ + /* long blocks */ + sfb = 0; + for (nrIdx = 0; nrIdx <= 3; nrIdx++) { + //iipTest = (1 << slen[nrIdx]) - 1; + for(i=0; i < nr[nrIdx]; i++, sfb++) { + sfis->l[sfb] = (char)GetBits(bsi, slen[nrIdx]); + } + } + /* last sf band not transmitted */ + sfis->l[21] = sfis->l[22] = 0; + + } +} +/*********************************************************************************************************************** + * Function: UnpackScaleFactors + * + * Description: parse the fields of the MP3 scale factor data section + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader() and UnpackSideInfo() + * buffer pointing to the MP3 scale factor data + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits available in data buffer + * index of current granule and channel + * + * Outputs: updated platform-specific ScaleFactorInfo struct + * updated bitOffset + * + * Return: length (in bytes) of scale factor data, -1 if null input pointers + **********************************************************************************************************************/ +int32_t UnpackScaleFactors( uint8_t *buf, int32_t *bitOffset, int32_t bitsAvail, int32_t gr, int32_t ch){ + int32_t bitsUsed; + uint8_t *startBuf; + BitStreamInfo_t bitStreamInfo, *bsi; + + /* init GetBits reader */ + startBuf = buf; + bsi = &bitStreamInfo; + SetBitstreamPointer(bsi, (bitsAvail + *bitOffset + 7) / 8, buf); + if (*bitOffset) + GetBits(bsi, *bitOffset); + + if (m_MPEGVersion == MPEG1) + UnpackSFMPEG1(bsi, &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], + m_SideInfo->scfsi[ch], gr, &m_ScaleFactorInfoSub[0][ch]); + else + UnpackSFMPEG2(bsi, &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], + gr, ch, m_FrameHeader->modeExt, m_ScaleFactorJS); + + m_MP3DecInfo->part23Length[gr][ch] = m_SideInfoSub[gr][ch].part23Length; + + bitsUsed = CalcBitsUsed(bsi, buf, *bitOffset); + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + + return (buf - startBuf); +} +/***************************************************************************************************************************************************** + * M P 3 D E C + ****************************************************************************************************************************************************/ + +/***************************************************************************************************************************************************** + * Function: MP3FindSyncWord + * + * Description: locate the next byte-alinged sync word in the raw mp3 stream + * + * Inputs: buffer to search for sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to first sync word (bytes from start of buf) + * -1 if sync not found after searching nBytes + ****************************************************************************************************************************************************/ +int32_t MP3FindSyncWord(uint8_t *buf, int32_t nBytes) { + + // Auxiliary function for extracting bits, byte 'value', 'start_bit' is that bit from the left (0-7), 'num_bits' is the number of bits + // auto extract_bits = [&](uint8_t byte, uint8_t start_bit, uint8_t num_bits) { + // return (byte >> (8 - start_bit - num_bits)) & ((1 << num_bits) - 1); + // }; + const uint8_t SYNCWORDH = 0xff; + const uint8_t SYNCWORDL = 0xe0; + + typedef struct { + uint8_t mpeg_version; // 0=MPEG2.5, 1=reserved, 2=MPEG2, 3=MPEG1 + uint8_t layer; // 0=reserved, 1=Layer III, 2=Layer II, 3=Layer I + bool crc_protected; + uint8_t bitrate_idx; + uint8_t sample_rate_idx; + bool padding; + uint8_t channel_mode; + uint32_t frame_length; // In Bytes + uint16_t sample_rate_hz; // Die tatsächliche Abtastrate in Hz + uint16_t bitrate_kbps; // Die tatsächliche Bitrate in kbps + uint16_t samples_per_frame; + } Mp3FrameHeader; + + // SamplingFrequenz-Lookup tables(Beispiel für MPEG1, MPEG2, MPEG2.5) + const uint16_t sampling_rates[3][4] = { + {44100, 48000, 32000, 0}, // MPEG1 + {22050, 24000, 16000, 0}, // MPEG2 + {11025, 12000, 8000, 0} // MPEG2.5 + }; + + typedef enum { /* map to 0,1,2 to make table indexing easier */ + MPEG1 = 0, + MPEG2 = 1, + MPEG25 = 2 + } MPEGVersion_t; + + const uint16_t mpeg1_layer1_bitrates[16] = { + 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 + }; + + const uint16_t mpeg1_layer3_bitrates[16] = { // Bitraten-Lookup tables (example for MPEG1 Layer III) + 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 // Attention: These tables must be complete and correct! + }; + // Define bitrate tables for MPEG1 Layer II and MPEG2/2.5 Layer II + // These tables are examples and need to be complete based on the MPEG standard + const uint16_t mpeg1_layer2_bitrates[] = { + 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 + }; + const uint16_t mpeg2_layer2_bitrates[] = { + 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 + }; + const uint16_t mpeg2_layer3_bitrates[] = { + 0, // "Free format" oder ungültig + 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, + 0 // Ungültig + }; + + // Funktion zum Parsen des Headers und Überprüfen der Gültigkeit + auto parseMp3Header = [&](const uint8_t* header_data, Mp3FrameHeader* header_info) { + // Byte 0: Syncword H (bereits geprüft) + // Byte 1: Syncword L, MPEG Version, Layer + // Byte 2: Bitrate, Sampling Frequency, Padding, Private + // Byte 3: Channel Mode, Mode Extension, Copyright, Original, Emphasis + + // Syncword has already been checked, here we start with the other bits + header_info->mpeg_version = (header_data[1] >> 3) & 0b11; // Bits 12, 13 (A, B) + header_info->layer = (header_data[1] >> 1) & 0b11; // Bits 14, 15 (C, D) + header_info->crc_protected = !((header_data[1] >> 0) & 0b1); // Bit 16 (Schutzbit) + + header_info->bitrate_idx = (header_data[2] >> 4) & 0b1111; // Bits 17-20 + header_info->sample_rate_idx = (header_data[2] >> 2) & 0b11; // Bits 21-22 + header_info->padding = (header_data[2] >> 1) & 0b1; // Bit 23 + + header_info->channel_mode = (header_data[3] >> 6) & 0b11; // Bits 24-25 + + // Gültigkeitsprüfungen + if (header_info->mpeg_version == 1) { // Reserved + log_d("Reserved MPEG version\n"); + return false; + } + if (header_info->layer == 0) { // Reserved + log_d("Reserved Layer\n"); + return false; + } + // Modified part: Support for Layer II and Layer III + if (header_info->layer != 1 && header_info->layer != 2 && header_info->layer != 3 ) { // Allow Layer I (3) Layer II (2) and Layer III (1) + printf("\n"); for(int i = 0; i<10; i++) printf("0x%02x ", header_data[i]); printf("\n"); // Use header_data instead of buf + log_d("Not Layer I or II or III\n"); + return false; + } + + if (header_info->bitrate_idx == 0 || header_info->bitrate_idx == 15) { // Invalid bit rate + log_d("Invalid bitrate index\n"); + return false; + } + if (header_info->sample_rate_idx == 3) { // Invalid sampling frequency + log_d("Invalid sampling rate index\n"); + return false; + } + + // Determine the actual bit rate and sampling frequency + uint16_t bitrate_kbps = 0; + uint16_t sample_rate_hz = 0; + + // Mapping from MPEG version to sampling rate table + uint8_t sr_table_idx; + if (header_info->mpeg_version == 3) sr_table_idx = 0; // MPEG 1 (0b11) + else if (header_info->mpeg_version == 2) sr_table_idx = 1; // MPEG 2 (0b10) + else sr_table_idx = 2; // MPEG 2.5 (da mpeg_version == 0) - Although Google TTS is likely MPEG 2.0 + + sample_rate_hz = sampling_rates[sr_table_idx][header_info->sample_rate_idx]; + + // Bitraten-Mapping für verschiedene MPEG-Versionen und Layer + if (header_info->mpeg_version == 3) { // MPEG 1 + if (header_info->layer == 1) { // Layer III + bitrate_kbps = mpeg1_layer3_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 2) { // Layer II + bitrate_kbps = mpeg1_layer2_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 3) { // Layer I + bitrate_kbps = mpeg1_layer1_bitrates[header_info->bitrate_idx]; + } + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2 or MPEG 2.5 + if (header_info->layer == 1) { // Layer III + bitrate_kbps = mpeg2_layer3_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 2) { // Layer II + bitrate_kbps = mpeg2_layer2_bitrates[header_info->bitrate_idx]; + } + // If you also want to support MPEG 2/2.5 Layer I, you'd add another else if here + // e.g., else if (header_info->layer == 3) { bitrate_kbps = mpeg2_layer1_bitrates[header_info->bitrate_idx]; } + } + + if (bitrate_kbps == 0 || sample_rate_hz == 0) { + log_d("Could not determine valid bitrate or sample rate\n"); + return false; + } + + // Calculate frame length based on layer + // FrameSize = (1152 * BitRate / SampleRate) + Padding (for Layer III) + // FrameSize = (144 * BitRate / SampleRate) + Padding (for Layer I) + // FrameSize = (576 * BitRate / SampleRate) + Padding (for Layer II, MPEG 2.0/2.5) + // Note: For MPEG 1 Layer II, it's (1152 * BitRate / SampleRate) + Padding + // Need to be careful with the constant depending on MPEG version and layer + if (header_info->layer == 1) { // Layer III + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; // Assuming MPEG1 Layer III + if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG2/2.5 Layer III + header_info->frame_length = (72 * bitrate_kbps * 1000) / sample_rate_hz; // Correct constant for MPEG2/2.5 Layer III + } + } else if (header_info->layer == 2) { // Layer II + if (header_info->mpeg_version == 3) { // MPEG 1 Layer II + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2/2.5 Layer II + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; + } + } else if (header_info->layer == 3) { // Layer I + // For Layer I, the formula is (Bitrate * 12 / SampleRate) + Padding (in Bytes) + // Note: Bitrate is in kbps, so multiply by 1000 to get bps + if (header_info->mpeg_version == 3) { // MPEG 1 Layer I + header_info->frame_length = (bitrate_kbps * 1000 / 8 * 12) / sample_rate_hz; // Correct + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2/2.5 Layer I (if supported) + // You'd add the specific calculation for MPEG2/2.5 Layer I here + // For MPEG 2/2.5 Layer I, samples per frame is 576, so the constant is 6 + header_info->frame_length = (bitrate_kbps * 1000 / 8 * 6) / sample_rate_hz; // Hypothetical, verify constant + } + } + + if (header_info->padding) { + header_info->frame_length += 1; // Füge 1 Byte für Padding hinzu + } + + if (header_info->frame_length == 0) { + log_d("Calculated frame length is zero\n"); + return false; + } + header_info->sample_rate_hz = sample_rate_hz; + header_info->bitrate_kbps = bitrate_kbps; + + // Determine samples_per_frame based on the version and layer + if (header_info->mpeg_version == 3) { // MPEG-1 + if (header_info->layer == 1 || header_info->layer == 2) { // Layer III oder Layer II + header_info->samples_per_frame = 1152; + } else if (header_info->layer == 3) { // Layer I + header_info->samples_per_frame = 384; + } else { + header_info->samples_per_frame = 0; // Should be caught by previous checks + return false; + } + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG-2 oder MPEG-2.5 + if (header_info->layer == 1) { // Layer III + header_info->samples_per_frame = 576; + } else if (header_info->layer == 2) { // Layer II + header_info->samples_per_frame = 1152; + } else if (header_info->layer == 3) { // Layer I + header_info->samples_per_frame = 576; // Correct for MPEG-2/2.5 Layer I + } else { + header_info->samples_per_frame = 0; // Should be caught by previous checks + return false; + } + } else { // header_info->mpeg_version == 1 (Reserved) + header_info->samples_per_frame = 0; + return false; + } + return true; // Header ist gültig + }; + + const uint8_t mp3FHsize = 4; // frame header size + + // Lambda for the fast syncword search + auto findSync = [&](uint8_t* search_buf, uint16_t offset, uint16_t len) { + for (int32_t i = 0; i < len - 1; i++) { + // Prüfe auf die 11 oder 12 Sync-Bits + if ((search_buf[i + offset] == SYNCWORDH) && + ((search_buf[i + offset + 1] & SYNCWORDL) == SYNCWORDL)) { + return i; + } + } + return (int32_t)-1; + }; + + int32_t current_pos = 0; + + while (nBytes >= mp3FHsize) { // Make sure that there are enough bytes for a header + int32_t sync_offset = findSync(buf, current_pos, nBytes); + + if (sync_offset == -1) { + log_d("No syncword found in remaining buffer\n"); + return -1; // No more syncword found + } + + current_pos += sync_offset; + nBytes -= sync_offset; + + if (nBytes < mp3FHsize) { + log_d("Not enough bytes for a full header after syncword\n"); + return -1; // Not enough data for a full header + } + + Mp3FrameHeader header; + if (parseMp3Header(&buf[current_pos], &header)) { + // This is where the crucial step comes: Check the next frame + if (current_pos + header.frame_length + mp3FHsize <= current_pos + nBytes) { + // Check whether there is a syncword at the expected next frame start and a valid header is (optional but very robust) + Mp3FrameHeader next_header; + if (((buf[current_pos + header.frame_length] == SYNCWORDH) && ((buf[current_pos + header.frame_length + 1] & SYNCWORDL) == SYNCWORDL)) && + parseMp3Header(&buf[current_pos + header.frame_length], &next_header)) { + log_d("Found reliable MP3 frame at pos: %d, length: %lu\n", current_pos, header.frame_length); + + // s_samplerate = header.sample_rate_hz; // (angenommen in der Struktur vorhanden) + // s_bitRate = header.bitrate_kbps; // (angenommen in der Struktur vorhanden) + // s_mpeg_version = header.mpeg_version; + // s_layer = header.layer; + // s_channel_mode = header.channel_mode; + // s_samples_per_frame = header.samples_per_frame; + + // // Für s_channels (1 für Mono, 2 für Stereo) + // if (header.channel_mode == 0b11) { // 0b11 ist Mono + // s_channels = 1; + // } else { // Alle anderen Modi (Stereo, Joint Stereo, Dual Channel) sind 2 Kanäle + // s_channels = 2; + // } + return current_pos; + } else { + log_d("Header valid, but next frame does not validate. False positive. Moving on.\n"); + } + } else { + log_d("Header valid, but not enough data for next frame check. Possibly end of stream or false positive.\n"); + // If not enough data for the next frame, it could still be the right one. + // This is a compromise.If in doubt, continue to search or return the current one. + // For robustness: search. + } + } else { + log_d("Found syncword but header is invalid. Moving to next possible syncword.\n"); + } + + // If the current header was invalid or the next frame did not validate the current "SyncWord" and continue to search + current_pos += 1; // go a byte on and look for the Syncword again + nBytes -= 1; + } + + return -1; // no valid MP3 frame found +} +/***************************************************************************************************************************************************** + * Function: MP3FindFreeSync + * + * Description: figure out number of bytes between adjacent sync words in "free" mode + * + * Inputs: buffer to search for next sync word + * the 4-byte frame header starting at the current sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to next sync word, minus any pad byte (i.e. nSlots) + * -1 if sync not found after searching nBytes + * + * Notes: this checks that the first 22 bits of the next frame header are the + * same as the current frame header, but it's still not foolproof + * (could accidentally find a sequence in the bitstream which + * appears to match but is not actually the next frame header) + * this could be made more error-resilient by checking several frames + * in a row and verifying that nSlots is the same in each case + * since free mode requires CBR (see spec) we generally only call + * this function once (first frame) then store the result (nSlots) + * and just use it from then on + ****************************************************************************************************************************************************/ +int32_t MP3FindFreeSync(uint8_t *buf, uint8_t firstFH[4], int32_t nBytes){ + int32_t offset = 0; + uint8_t *bufPtr = buf; + + /* loop until we either: + * - run out of nBytes (FindMP3SyncWord() returns -1) + * - find the next valid frame header (sync word, version, layer, CRC flag, bitrate, and sample rate + * in next header must match current header) + */ + while (1) { + offset = MP3FindSyncWord(bufPtr, nBytes); + bufPtr += offset; + if (offset < 0) { + return -1; + } else if ((bufPtr[0] == firstFH[0]) && (bufPtr[1] == firstFH[1]) + && ((bufPtr[2] & 0xfc) == (firstFH[2] & 0xfc))) { + /* want to return number of bytes per frame, + * NOT counting the padding byte, so subtract one if padFlag == 1 */ + if ((firstFH[2] >> 1) & 0x01) + bufPtr--; + return bufPtr - buf; + } + bufPtr += 3; + nBytes -= (offset + 3); + }; + + return -1; +} +/*********************************************************************************************************************** + * Function: MP3GetLastFrameInfo + * + * Description: get info about last MP3 frame decoded (number of sampled decoded, + * sample rate, bitrate, etc.) + * + * Inputs: + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: none + * + * Notes: call this right after calling MP3Decode + **********************************************************************************************************************/ +void MP3GetLastFrameInfo() { + if (m_MP3DecInfo->layer != 3){ + m_MP3FrameInfo->bitrate=0; + m_MP3FrameInfo->nChans=0; + m_MP3FrameInfo->samprate=0; + m_MP3FrameInfo->bitsPerSample=0; + m_MP3FrameInfo->outputSamps=0; + m_MP3FrameInfo->layer=0; + m_MP3FrameInfo->version=0; + } + else{ + m_MP3FrameInfo->bitrate=m_MP3DecInfo->bitrate; + m_MP3FrameInfo->nChans=m_MP3DecInfo->nChans; + m_MP3FrameInfo->samprate=m_MP3DecInfo->samprate; + m_MP3FrameInfo->bitsPerSample=16; + m_MP3FrameInfo->outputSamps = (int32_t) samplesPerFrameTab[m_MPEGVersion][m_MP3DecInfo->layer-1]; + m_MP3FrameInfo->layer=m_MP3DecInfo->layer; + m_MP3FrameInfo->version=m_MPEGVersion; + } +} +int32_t MP3GetSampRate(){return m_MP3FrameInfo->samprate;} +int32_t MP3GetChannels(){return m_MP3FrameInfo->nChans;} +int32_t MP3GetBitsPerSample(){return m_MP3FrameInfo->bitsPerSample;} +int32_t MP3GetBitrate(){return m_MP3FrameInfo->bitrate;} +int32_t MP3GetOutputSamps(){return m_MP3FrameInfo->outputSamps;} + +const char* MP3GetLayer(){ + const char* layer_str = layer_table[m_MP3FrameInfo->layer]; // 0: Reserviert, 1: Layer III, 2: Layer II, 3: Layer I + return layer_str; +} + +const char* MP3GetMPEGVersion(){ + const char* mpeg_version_str = mpeg_version_table[m_MP3FrameInfo->version]; // 0: MPEG-2.5, 1: Reserviert, 2: MPEG-2 (ISO/IEC 13818-3), 3: MPEG-1 (ISO/IEC 11172-3) + return mpeg_version_str; +} +/*********************************************************************************************************************** + * Function: MP3GetNextFrameInfo + * + * Description: parse MP3 frame header + * + * Inputs: pointer to buffer containing valid MP3 frame header (located using + * MP3FindSyncWord(), above) + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + **********************************************************************************************************************/ +int32_t MP3GetNextFrameInfo(uint8_t *buf) { + + if (UnpackFrameHeader( buf) == -1 || m_MP3DecInfo->layer != 3){ + MP3_ERROR("MP3 invalid frameheader"); + return MP3_ERR; + } + MP3GetLastFrameInfo(); + + return MP3_NONE; +} +/*********************************************************************************************************************** + * Function: MP3ClearBadFrame + * + * Description: zero out pcm buffer if error decoding MP3 frame + * + * Inputs: mp3DecInfo struct with correct frame size parameters filled in + * pointer pcm output buffer + * + * Outputs: zeroed out pcm buffer + * + * Return: none + **********************************************************************************************************************/ +void MP3ClearBadFrame(int16_t *outbuf) { + int32_t i; + for (i = 0; i < m_MP3DecInfo->nGrans * m_MP3DecInfo->nGranSamps * m_MP3DecInfo->nChans; i++) + outbuf[i] = 0; +} +/*********************************************************************************************************************** + * Function: MP3Decode + * + * Description: decode one frame of MP3 data + * + * Inputs: number of valid bytes remaining in inbuf + * pointer to outbuf, big enough to hold one frame of decoded PCM samples + * flag indicating whether MP3 data is normal MPEG format (useSize = 0) + * or reformatted as "self-contained" frames (useSize = 1) + * + * Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo + * number of output samples = nGrans * nGranSamps * nChans + * updated inbuf pointer, updated bytesLeft + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + * + * Notes: switching useSize on and off between frames in the same stream + * is not supported (bit reservoir is not maintained if useSize on) + **********************************************************************************************************************/ +int32_t MP3Decode( uint8_t *inbuf, int32_t *bytesLeft, int16_t *outbuf){ + + // int pos = MP3FindSyncWord(inbuf, *bytesLeft); + // if(pos > 0){*bytesLeft -= pos; MP3_INFO("skip %i bytes", pos); return MP3_NONE; } + // if(pos < 0){MP3_INFO("skip %i max bytes", *bytesLeft); *bytesLeft = 0; return MP3_NONE; } + + int32_t offset, bitOffset, mainBits, gr, ch, fhBytes, siBytes, freeFrameBytes; + int32_t prevBitOffset, sfBlockBits, huffBlockBits; + uint8_t *mainPtr; + static uint8_t underflowCounter = 0; // http://macslons-irish-pub-radio.stream.laut.fm/macslons-irish-pub-radio + + /* unpack frame header */ + fhBytes = UnpackFrameHeader(inbuf); + if (fhBytes < 0){ + MP3_ERROR("MP3 invalid frameheader"); /* don't clear outbuf since we don't know size (failed to parse header) */ + return MP3_ERR; + } + inbuf += fhBytes; + /* unpack side info */ + siBytes = UnpackSideInfo( inbuf); + if (siBytes < 0) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3 invalid sideinfo"); + return MP3_ERR; + } + inbuf += siBytes; + *bytesLeft -= (fhBytes + siBytes); + + /* if free mode, need to calculate bitrate and nSlots manually, based on frame size */ + if (m_MP3DecInfo->bitrate == 0 || m_MP3DecInfo->freeBitrateFlag) { + if(!m_MP3DecInfo->freeBitrateFlag){ + /* first time through, need to scan for next sync word and figure out frame size */ + m_MP3DecInfo->freeBitrateFlag=1; + m_MP3DecInfo->freeBitrateSlots=MP3FindFreeSync(inbuf, inbuf - fhBytes - siBytes, *bytesLeft); + if(m_MP3DecInfo->freeBitrateSlots < 0){ + MP3ClearBadFrame(outbuf); + m_MP3DecInfo->freeBitrateFlag = 0; + MP3_ERROR("MP3, ca'nt find free bitrate slot"); + return MP3_ERR; + } + freeFrameBytes=m_MP3DecInfo->freeBitrateSlots + fhBytes + siBytes; + m_MP3DecInfo->bitrate=(freeFrameBytes * m_MP3DecInfo->samprate * 8) + / (m_MP3DecInfo->nGrans * m_MP3DecInfo->nGranSamps); + } + m_MP3DecInfo->nSlots = m_MP3DecInfo->freeBitrateSlots + CheckPadBit(); /* add pad byte, if required */ + } + + /* useSize != 0 means we're getting reformatted (RTP) packets (see RFC 3119) + * - calling function assembles "self-contained" MP3 frames by shifting any main_data + * from the bit reservoir (in previous frames) to AFTER the sync word and side info + * - calling function should set mainDataBegin to 0, and tell us exactly how large this + * frame is (in bytesLeft) + */ + // if (useSize) { + // m_MP3DecInfo->nSlots = *bytesLeft; + // if (m_MP3DecInfo->mainDataBegin != 0 || m_MP3DecInfo->nSlots <= 0) { + // /* error - non self-contained frame, or missing frame (size <= 0), could do loss concealment here */ + // MP3ClearBadFrame(outbuf); + // MP3_ERROR("MP3, invalid frameheader"); + // return MP3_ERR; + // } + + // /* can operate in-place on reformatted frames */ + // m_MP3DecInfo->mainDataBytes = m_MP3DecInfo->nSlots; + // mainPtr = inbuf; + // inbuf += m_MP3DecInfo->nSlots; + // *bytesLeft -= (m_MP3DecInfo->nSlots); + // } else { + /* out of data - assume last or truncated frame */ + if (m_MP3DecInfo->nSlots > *bytesLeft) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3, indata underflow"); + return MP3_ERR; + } + /* fill main data buffer with enough new data for this frame */ + if (m_MP3DecInfo->mainDataBytes >= m_MP3DecInfo->mainDataBegin) { + /* adequate "old" main data available (i.e. bit reservoir) */ + underflowCounter = 0; + memmove(m_MP3DecInfo->mainBuf, + m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBytes - m_MP3DecInfo->mainDataBegin, + m_MP3DecInfo->mainDataBegin); + memcpy (m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBegin, inbuf, + m_MP3DecInfo->nSlots); + + m_MP3DecInfo->mainDataBytes = m_MP3DecInfo->mainDataBegin + m_MP3DecInfo->nSlots; + inbuf += m_MP3DecInfo->nSlots; + *bytesLeft -= (m_MP3DecInfo->nSlots); + mainPtr = m_MP3DecInfo->mainBuf; + } else { + /* not enough data in bit reservoir from previous frames (perhaps starting in middle of file) */ + underflowCounter ++; + memcpy(m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBytes, inbuf, m_MP3DecInfo->nSlots); + m_MP3DecInfo->mainDataBytes += m_MP3DecInfo->nSlots; + inbuf += m_MP3DecInfo->nSlots; + *bytesLeft -= (m_MP3DecInfo->nSlots); + if(underflowCounter < 4){ + return MP3_NONE; + } + MP3ClearBadFrame( outbuf); + MP3_ERROR("MP3, maindata underflow"); + return MP3_ERR; + } +// } + bitOffset = 0; + mainBits = m_MP3DecInfo->mainDataBytes * 8; + + /* decode one complete frame */ + for (gr = 0; gr < m_MP3DecInfo->nGrans; gr++) { + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + /* unpack scale factors and compute size of scale factor block */ + prevBitOffset = bitOffset; + offset = UnpackScaleFactors( mainPtr, &bitOffset, + mainBits, gr, ch); + sfBlockBits = 8 * offset - prevBitOffset + bitOffset; + huffBlockBits = m_MP3DecInfo->part23Length[gr][ch] - sfBlockBits; + mainPtr += offset; + mainBits -= sfBlockBits; + + if (offset < 0 || mainBits < huffBlockBits) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3, invalid scalefact"); + return MP3_ERR; + } + /* decode Huffman code words */ + prevBitOffset = bitOffset; + offset = DecodeHuffman( mainPtr, &bitOffset, huffBlockBits, gr, ch); + if (offset < 0) { + MP3ClearBadFrame( outbuf); + MP3_ERROR("MP3, invalid Huffman code words"); + return MP3_ERR; + } + mainPtr += offset; + mainBits -= (8 * offset - prevBitOffset + bitOffset); + } + /* dequantize coefficients, decode stereo, reorder int16_t blocks */ + if (MP3Dequantize( gr) < 0) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3, invalid dequantize coefficients"); + return MP3_ERR; + } + + /* alias reduction, inverse MDCT, overlap-add, frequency inversion */ + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + if (IMDCT( gr, ch) < 0) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3, invalid inverse MDCT"); + return MP3_ERR; + } + } + /* subband transform - if stereo, interleaves pcm LRLRLR */ + if (Subband( + outbuf + gr * m_MP3DecInfo->nGranSamps * m_MP3DecInfo->nChans) + < 0) { + MP3ClearBadFrame(outbuf); + MP3_ERROR("MP3, invalid subband"); + return MP3_ERR; + } + } + MP3GetLastFrameInfo(); + return MP3_NONE; +} + +/*********************************************************************************************************************** + * Function: MP3Decoder_ClearBuffer + * + * Description: clear all the memory needed for the MP3 decoder + * + * Inputs: none + * + * Outputs: none + * + * Return: none + * + **********************************************************************************************************************/ +void MP3Decoder_ClearBuffer(void) { + + /* important to do this - DSP primitives assume a bunch of state variables are 0 on first use */ + memset( m_MP3DecInfo, 0, sizeof(MP3DecInfo_t)); //Clear MP3DecInfo + memset(&m_ScaleFactorInfoSub, 0, sizeof(ScaleFactorInfoSub_t)*(m_MAX_NGRAN *m_MAX_NCHAN)); //Clear ScaleFactorInfo + memset( m_SideInfo, 0, sizeof(SideInfo_t)); //Clear SideInfo + memset( m_FrameHeader, 0, sizeof(FrameHeader_t)); //Clear FrameHeader + memset( m_HuffmanInfo, 0, sizeof(HuffmanInfo_t)); //Clear HuffmanInfo + memset( m_DequantInfo, 0, sizeof(DequantInfo_t)); //Clear DequantInfo + memset( m_IMDCTInfo, 0, sizeof(IMDCTInfo_t)); //Clear IMDCTInfo + memset( m_SubbandInfo, 0, sizeof(SubbandInfo_t)); //Clear SubbandInfo + memset(&m_CriticalBandInfo, 0, sizeof(CriticalBandInfo_t)*m_MAX_NCHAN); //Clear CriticalBandInfo + memset( m_ScaleFactorJS, 0, sizeof(ScaleFactorJS_t)); //Clear ScaleFactorJS + memset(&m_SideInfoSub, 0, sizeof(SideInfoSub_t)*(m_MAX_NGRAN *m_MAX_NCHAN)); //Clear SideInfoSub + memset(&m_SFBandTable, 0, sizeof(SFBandTable_t)); //Clear SFBandTable + memset( m_MP3FrameInfo, 0, sizeof(MP3FrameInfo_t)); //Clear MP3FrameInfo + + return; + +} +/*********************************************************************************************************************** + * Function: MP3Decoder_AllocateBuffers + * + * Description: allocate all the memory needed for the MP3 decoder + * + * Inputs: none + * + * Outputs: none + * + * Return: pointer to MP3DecInfo structure (initialized with pointers to all + * the internal buffers needed for decoding) + * + * Notes: if one or more mallocs fail, function frees any buffers already + * allocated before returning + * + **********************************************************************************************************************/ + +#ifdef CONFIG_IDF_TARGET_ESP32S3 + // ESP32-S3: If there is PSRAM, prefer it + #define __malloc_heap_psram(size) \ + heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) +#else + // ESP32, PSRAM is too slow, prefer SRAM + #define __malloc_heap_psram(size) \ + heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM) +#endif + +bool MP3Decoder_AllocateBuffers(void) { + if(!m_MP3DecInfo) {m_MP3DecInfo = (MP3DecInfo_t*) __malloc_heap_psram(sizeof(MP3DecInfo_t) );} + if(!m_FrameHeader) {m_FrameHeader = (FrameHeader_t*) __malloc_heap_psram(sizeof(FrameHeader_t) );} + if(!m_SideInfo) {m_SideInfo = (SideInfo_t*) __malloc_heap_psram(sizeof(SideInfo_t) );} + if(!m_ScaleFactorJS) {m_ScaleFactorJS = (ScaleFactorJS_t*) __malloc_heap_psram(sizeof(ScaleFactorJS_t));} + if(!m_HuffmanInfo) {m_HuffmanInfo = (HuffmanInfo_t*) __malloc_heap_psram(sizeof(HuffmanInfo_t) );} + if(!m_DequantInfo) {m_DequantInfo = (DequantInfo_t*) __malloc_heap_psram(sizeof(DequantInfo_t) );} + if(!m_IMDCTInfo) {m_IMDCTInfo = (IMDCTInfo_t*) __malloc_heap_psram(sizeof(IMDCTInfo_t) );} + if(!m_SubbandInfo) {m_SubbandInfo = (SubbandInfo_t*) __malloc_heap_psram(sizeof(SubbandInfo_t) );} + if(!m_MP3FrameInfo) {m_MP3FrameInfo = (MP3FrameInfo_t*) __malloc_heap_psram(sizeof(MP3FrameInfo_t) );} + + if(!m_MP3DecInfo || !m_FrameHeader || !m_SideInfo || !m_ScaleFactorJS || !m_HuffmanInfo || + !m_DequantInfo || !m_IMDCTInfo || !m_SubbandInfo || !m_MP3FrameInfo) { + MP3Decoder_FreeBuffers(); + log_e("not enough memory to allocate mp3decoder buffers"); + return false; + } + MP3Decoder_ClearBuffer(); + return true; +} +/*********************************************************************************************************************** + * Function: MP3Decoder_IsInit + * + * Description: returns MP3 decoder initialization status + * + * Inputs: none + * + * Outputs: none + * + * Return: true if buffers allocated, otherwise false + + **********************************************************************************************************************/ +bool MP3Decoder_IsInit(void) { + if(!m_MP3DecInfo || !m_FrameHeader || !m_SideInfo || !m_ScaleFactorJS || !m_HuffmanInfo || + !m_DequantInfo || !m_IMDCTInfo || !m_SubbandInfo || !m_MP3FrameInfo) { + return false; + } + return true; +} +/*********************************************************************************************************************** + * Function: MP3Decoder_FreeBuffers + * + * Description: frees all the memory used by the MP3 decoder + * + * Inputs: pointer to initialized MP3DecInfo structure + * + * Outputs: none + * + * Return: none + * + * Notes: safe to call even if some buffers were not allocated + **********************************************************************************************************************/ +void MP3Decoder_FreeBuffers() +{ +// uint32_t i = ESP.getFreeHeap(); + + if(m_MP3DecInfo) {free(m_MP3DecInfo); m_MP3DecInfo=NULL;} + if(m_FrameHeader) {free(m_FrameHeader); m_FrameHeader=NULL;} + if(m_SideInfo) {free(m_SideInfo); m_SideInfo=NULL;} + if(m_ScaleFactorJS ) {free(m_ScaleFactorJS); m_ScaleFactorJS=NULL;} + if(m_HuffmanInfo) {free(m_HuffmanInfo); m_HuffmanInfo=NULL;} + if(m_DequantInfo) {free(m_DequantInfo); m_DequantInfo=NULL;} + if(m_IMDCTInfo) {free(m_IMDCTInfo); m_IMDCTInfo=NULL;} + if(m_SubbandInfo) {free(m_SubbandInfo); m_SubbandInfo=NULL;} + if(m_MP3FrameInfo) {free(m_MP3FrameInfo); m_MP3FrameInfo=NULL;} + +// log_i("MP3Decoder: %lu bytes memory was freed", ESP.getFreeHeap() - i); +} + +/*********************************************************************************************************************** + * H U F F M A N N + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: DecodeHuffmanPairs + * + * Description: decode 2-way vector Huffman codes in the "bigValues" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of pair-wise codes + * pointer to xy buffer to received decoded values + * number of codewords to decode + * index of Huffman table to use + * number of bits remaining in bitstream + * + * Outputs: pairs of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: number of bits used, or -1 if out of bits + * + * Notes: assumes that nVals is an even number + * si_huff.bit tests every Huffman codeword in every table (though not + * necessarily all linBits outputs for x,y > 15) + **********************************************************************************************************************/ +// no improvement with section=data + +int32_t DecodeHuffmanPairs(int32_t *xy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t *buf, int32_t bitOffset){ + int32_t i, x, y; + int32_t cachedBits, padBits, len, startBits, linBits, maxBits, minBits; + HuffTabType_t tabType; + uint16_t cw, *tBase, *tCurr; + uint32_t cache; + + if (nVals <= 0) + return 0; + + if (bitsLeft < 0) + return -1; + startBits = bitsLeft; + + tBase = (uint16_t *) (huffTable + huffTabOffset[tabIdx]); + linBits = huffTabLookup[tabIdx].linBits; + tabType = (HuffTabType_t)huffTabLookup[tabIdx].tabType; + +// assert(!(nVals & 0x01)); +// assert(tabIdx < m_HUFF_PAIRTABS); +// assert(tabIdx >= 0); +// assert(tabType != invalidTab); + + if((nVals & 0x01)){log_d("assert(!(nVals & 0x01))"); return -1;} + if(!(tabIdx < m_HUFF_PAIRTABS)){log_d("assert(tabIdx < m_HUFF_PAIRTABS)"); return -1;} + if(!(tabIdx >= 0)){log_d("(tabIdx >= 0)"); return -1;} + if(!(tabType != invalidTab)){log_d("(tabType != invalidTab)"); return -1;} + + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits = (8 - bitOffset) & 0x07; + if (cachedBits) + cache = (uint32_t) (*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + if (tabType == noBits) { + /* table 0, no data, x = y = 0 */ + for (i = 0; i < nVals; i += 2) { + xy[i + 0] = 0; + xy[i + 1] = 0; + } + return 0; + } else if (tabType == oneShot) { + /* single lookup, no escapes */ + + maxBits = (int32_t)( (((uint16_t)(pgm_read_word(&tBase[0])) >> 0) & 0x000f)); + tBase++; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + cache |= (uint32_t) (*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0){ + return -1; + } + if (bitsLeft > 0) + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + if (bitsLeft > 8) + cache |= (uint32_t) (*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t) 0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11) { + cw = pgm_read_word(&tBase[cache >> (32 - maxBits)]); + + len=(int32_t)( (((uint16_t)(cw)) >> 12) & 0x000f); + cachedBits -= len; + cache <<= len; + + x=(int32_t)( (((uint16_t)(cw)) >> 4) & 0x000f); + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + y=(int32_t)( (((uint16_t)(cw)) >> 8) & 0x000f); + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits){ + break; // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + // return -1; + } + + *xy++ = x; + *xy++ = y; + nVals -= 2; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } else if (tabType == loopLinbits || tabType == loopNoLinbits) { + tCurr = tBase; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + cache |= (uint32_t) (*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0){ + return -1; + } + if (bitsLeft > 0) + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + if (bitsLeft > 8) + cache |= (uint32_t) (*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t) 0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11) { + maxBits = (int32_t)( (((uint16_t)(pgm_read_word(&tCurr[0]))) >> 0) & 0x000f); + cw = pgm_read_word(&tCurr[(cache >> (32 - maxBits)) + 1]); + len=(int32_t)( (((uint16_t)(cw)) >> 12) & 0x000f); + if (!len) { + cachedBits -= maxBits; + cache <<= maxBits; + tCurr += cw; + continue; + } + cachedBits -= len; + cache <<= len; + + x=(int32_t)( (((uint16_t)(cw)) >> 4) & 0x000f); + y=(int32_t)( (((uint16_t)(cw)) >> 8) & 0x000f); + + if (x == 15 && tabType == loopLinbits) { + minBits = linBits + 1 + (y ? 1 : 0); + if (cachedBits + bitsLeft < minBits) + return -1; + while (cachedBits < minBits) { + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (int32_t) 0x80000000 >> (cachedBits - 1); + } + x += (int32_t) (cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + if (y == 15 && tabType == loopLinbits) { + minBits = linBits + 1; + if (cachedBits + bitsLeft < minBits) + break; // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + // return -1; + while (cachedBits < minBits) { + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (int32_t) 0x80000000 >> (cachedBits - 1); + } + y += (int32_t) (cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits){ + break; // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + // return -1; + } + + *xy++ = x; + *xy++ = y; + nVals -= 2; + tCurr = tBase; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } + + /* error in bitstream - trying to access unused Huffman table */ + return -1; +} + +/*********************************************************************************************************************** + * Function: DecodeHuffmanQuads + * + * Description: decode 4-way vector Huffman codes in the "count1" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of quadword codes + * pointer to vwxy buffer to received decoded values + * maximum number of codewords to decode + * index of quadword table (0 = table A, 1 = table B) + * number of bits remaining in bitstream + * + * Outputs: quadruples of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: index of the first "zero_part" value (index of the first sample + * of the quad word after which all samples are 0) + * + * Notes: si_huff.bit tests every vwxy output in both quad tables + **********************************************************************************************************************/ +// no improvement with section=data +int32_t DecodeHuffmanQuads(int32_t *vwxy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t *buf, int32_t bitOffset){ + int32_t i, v, w, x, y; + int32_t len, maxBits, cachedBits, padBits; + uint32_t cache; + uint8_t cw, *tBase; + + if(bitsLeft<=0) return 0; + + tBase = (uint8_t *) quadTable + quadTabOffset[tabIdx]; + maxBits = quadTabMaxBits[tabIdx]; + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits=(8-bitOffset) & 0x07; + if(cachedBits)cache=(uint32_t)(*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + i = padBits = 0; + while (i < (nVals - 3)) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t) (*buf++) << (24 - cachedBits); + cache |= (uint32_t) (*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if(cachedBits+bitsLeft <= 0) return i; + if(bitsLeft>0) cache |= (uint32_t)(*buf++)<<(24-cachedBits); + if (bitsLeft > 8) cache |= (uint32_t)(*buf++)<<(16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t) 0x80000000 >> (cachedBits - 1); + padBits = 10; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 6, plus 4 for sign bits, so make sure cache has at least 10 bits */ + while(i < (nVals - 3) && cachedBits >= 10){ + cw = pgm_read_byte(&tBase[cache >> (32 - maxBits)]); + len=(int32_t)( (((uint8_t)(cw)) >> 4) & 0x0f); + cachedBits -= len; + cache <<= len; + + v=(int32_t)( (((uint8_t)(cw)) >> 3) & 0x01); + if (v) { + (v) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + w=(int32_t)( (((uint8_t)(cw)) >> 2) & 0x01); + if (w) { + (w) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + x=(int32_t)( (((uint8_t)(cw)) >> 1) & 0x01); + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + y=(int32_t)( (((uint8_t)(cw)) >> 0) & 0x01); + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - okay (means we're done) */ + if (cachedBits < padBits) + return i; + + *vwxy++ = v; + *vwxy++ = w; + *vwxy++ = x; + *vwxy++ = y; + i += 4; + } + } + + /* decoded max number of quad values */ + return i; +} + +/*********************************************************************************************************************** + * Function: DecodeHuffman + * + * Description: decode one granule, one channel worth of Huffman codes + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * and UnpackScaleFactors() (for this granule) + * buffer pointing to start of Huffman data in MP3 frame + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits in the Huffman data section of the frame + * (could include padding bits) + * index of current granule and channel + * + * Outputs: decoded coefficients in hi->huffDecBuf[ch] (hi pointer in mp3DecInfo) + * updated bitOffset + * + * Return: length (in bytes) of Huffman codes + * bitOffset also returned in parameter (0 = MSB, 7 = LSB of + * byte located at buf + offset) + * -1 if null input pointers, huffBlockBits < 0, or decoder runs + * out of bits prematurely (invalid bitstream) + **********************************************************************************************************************/ +// .data about 1ms faster per frame +int32_t DecodeHuffman(uint8_t *buf, int32_t *bitOffset, int32_t huffBlockBits, int32_t gr, int32_t ch){ + + int32_t r1Start, r2Start, rEnd[4]; /* region boundaries */ + int32_t i, w, bitsUsed, bitsLeft; + uint8_t *startBuf = buf; + + SideInfoSub_t *sis; + sis = &m_SideInfoSub[gr][ch]; + //hi = (HuffmanInfo_t*) (m_MP3DecInfo->HuffmanInfoPS); + + if (huffBlockBits < 0){ + return -1; + } + + /* figure out region boundaries (the first 2*bigVals coefficients divided into 3 regions) */ + if (sis->winSwitchFlag && sis->blockType == 2) { + if (sis->mixedBlock == 0) { + r1Start = m_SFBandTable.s[(sis->region0Count + 1) / 3] * 3; + } else { + if (m_MPEGVersion == MPEG1) { + r1Start = m_SFBandTable.l[sis->region0Count + 1]; + } else { + /* see MPEG2 spec for explanation */ + w = m_SFBandTable.s[4] - m_SFBandTable.s[3]; + r1Start = m_SFBandTable.l[6] + 2 * w; + } + } + r2Start = m_MAX_NSAMP; /* short blocks don't have region 2 */ + } else { + r1Start = m_SFBandTable.l[sis->region0Count + 1]; + r2Start = m_SFBandTable.l[sis->region0Count + 1 + sis->region1Count + 1]; + } + + /* offset rEnd index by 1 so first region = rEnd[1] - rEnd[0], etc. */ + rEnd[3] = (m_MAX_NSAMP < (2 * sis->nBigvals) ? m_MAX_NSAMP : (2 * sis->nBigvals)); + rEnd[2] = (r2Start < rEnd[3] ? r2Start : rEnd[3]); + rEnd[1] = (r1Start < rEnd[3] ? r1Start : rEnd[3]); + rEnd[0] = 0; + + /* rounds up to first all-zero pair (we don't check last pair for (x,y) == (non-zero, zero)) */ + m_HuffmanInfo->nonZeroBound[ch] = rEnd[3]; + + /* decode Huffman pairs (rEnd[i] are always even numbers) */ + bitsLeft = huffBlockBits; + for (i = 0; i < 3; i++) { + bitsUsed = DecodeHuffmanPairs(m_HuffmanInfo->huffDecBuf[ch] + rEnd[i], + rEnd[i + 1] - rEnd[i], sis->tableSelect[i], bitsLeft, buf, + *bitOffset); + if (bitsUsed < 0 || bitsUsed > bitsLeft){ /* error - overran end of bitstream */ + return -1; + } + /* update bitstream position */ + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + bitsLeft -= bitsUsed; + } + + /* decode Huffman quads (if any) */ + m_HuffmanInfo->nonZeroBound[ch] += DecodeHuffmanQuads(m_HuffmanInfo->huffDecBuf[ch] + rEnd[3], + m_MAX_NSAMP - rEnd[3], sis->count1TableSelect, bitsLeft, buf, + *bitOffset); + + assert(m_HuffmanInfo->nonZeroBound[ch] <= m_MAX_NSAMP); + for (i = m_HuffmanInfo->nonZeroBound[ch]; i < m_MAX_NSAMP; i++) + m_HuffmanInfo->huffDecBuf[ch][i] = 0; + + /* If bits used for 576 samples < huffBlockBits, then the extras are considered + * to be stuffing bits (throw away, but need to return correct bitstream position) + */ + buf += (bitsLeft + *bitOffset) >> 3; + *bitOffset = (bitsLeft + *bitOffset) & 0x07; + + return (buf - startBuf); +} + +/*********************************************************************************************************************** + * D E Q U A N T + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: MP3Dequantize + * + * Description: dequantize coefficients, decode stereo, reorder short blocks + * (one granule-worth) + * + * Inputs: index of current granule + * + * Outputs: dequantized and reordered coefficients in hi->huffDecBuf + * (one granule-worth, all channels), format = Q26 + * operates in-place on huffDecBuf but also needs di->workBuf + * updated hi->nonZeroBound index for both channels + * + * Return: 0 on success, -1 if null input pointers + * + * Notes: In calling output Q(DQ_FRACBITS_OUT), we assume an implicit bias + * of 2^15. Some (floating-point) reference implementations factor this + * into the 2^(0.25 * gain) scaling explicitly. But to avoid precision + * loss, we don't do that. Instead take it into account in the final + * round to PCM (>> by 15 less than we otherwise would have). + * Equivalently, we can think of the dequantized coefficients as + * Q(DQ_FRACBITS_OUT - 15) with no implicit bias. + **********************************************************************************************************************/ +int32_t MP3Dequantize(int32_t gr){ + int32_t i, ch, nSamps, mOut[2]; + CriticalBandInfo_t *cbi; + cbi = &m_CriticalBandInfo[0]; + mOut[0] = mOut[1] = 0; + + /* dequantize all the samples in each channel */ + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + m_HuffmanInfo->gb[ch] = DequantChannel(m_HuffmanInfo->huffDecBuf[ch], m_DequantInfo->workBuf, + &m_HuffmanInfo->nonZeroBound[ch], &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], &cbi[ch]); + } + + /* joint stereo processing assumes one guard bit in input samples + * it's extremely rare not to have at least one gb, so if this is the case + * just make a pass over the data and clip to [-2^30+1, 2^30-1] + * in practice this may never happen + */ + if (m_FrameHeader->modeExt && (m_HuffmanInfo->gb[0] < 1 || m_HuffmanInfo->gb[1] < 1)) { + for (i = 0; i < m_HuffmanInfo->nonZeroBound[0]; i++) { + if (m_HuffmanInfo->huffDecBuf[0][i] < -0x3fffffff) m_HuffmanInfo->huffDecBuf[0][i] = -0x3fffffff; + if (m_HuffmanInfo->huffDecBuf[0][i] > 0x3fffffff) m_HuffmanInfo->huffDecBuf[0][i] = 0x3fffffff; + } + for (i = 0; i < m_HuffmanInfo->nonZeroBound[1]; i++) { + if (m_HuffmanInfo->huffDecBuf[1][i] < -0x3fffffff) m_HuffmanInfo->huffDecBuf[1][i] = -0x3fffffff; + if (m_HuffmanInfo->huffDecBuf[1][i] > 0x3fffffff) m_HuffmanInfo->huffDecBuf[1][i] = 0x3fffffff; + } + } + + /* do mid-side stereo processing, if enabled */ + if (m_FrameHeader->modeExt >> 1) { + if (m_FrameHeader->modeExt & 0x01) { + /* intensity stereo enabled - run mid-side up to start of right zero region */ + if (cbi[1].cbType == 0) + nSamps = m_SFBandTable.l[cbi[1].cbEndL + 1]; + else + nSamps = 3 * m_SFBandTable.s[cbi[1].cbEndSMax + 1]; + } else { + /* intensity stereo disabled - run mid-side on whole spectrum */ + nSamps = (m_HuffmanInfo->nonZeroBound[0] > m_HuffmanInfo->nonZeroBound[1] ? + m_HuffmanInfo->nonZeroBound[0] : m_HuffmanInfo->nonZeroBound[1]); + } + MidSideProc(m_HuffmanInfo->huffDecBuf, nSamps, mOut); + } + + /* do intensity stereo processing, if enabled */ + if (m_FrameHeader->modeExt & 0x01) { + nSamps = m_HuffmanInfo->nonZeroBound[0]; + if (m_MPEGVersion == MPEG1) { + IntensityProcMPEG1(m_HuffmanInfo->huffDecBuf, nSamps, &m_ScaleFactorInfoSub[gr][1], &m_CriticalBandInfo[0], + m_FrameHeader->modeExt >> 1, m_SideInfoSub[gr][1].mixedBlock, mOut); + } else { + IntensityProcMPEG2(m_HuffmanInfo->huffDecBuf, nSamps, &m_ScaleFactorInfoSub[gr][1], &m_CriticalBandInfo[0], + m_ScaleFactorJS, m_FrameHeader->modeExt >> 1, m_SideInfoSub[gr][1].mixedBlock, mOut); + } + } + + /* adjust guard bit count and nonZeroBound if we did any stereo processing */ + if (m_FrameHeader->modeExt) { + m_HuffmanInfo->gb[0] = CLZ(mOut[0]) - 1; + m_HuffmanInfo->gb[1] = CLZ(mOut[1]) - 1; + nSamps = (m_HuffmanInfo->nonZeroBound[0] > m_HuffmanInfo->nonZeroBound[1] ? + m_HuffmanInfo->nonZeroBound[0] : m_HuffmanInfo->nonZeroBound[1]); + m_HuffmanInfo->nonZeroBound[0] = nSamps; + m_HuffmanInfo->nonZeroBound[1] = nSamps; + } + + /* output format Q(DQ_FRACBITS_OUT) */ + return 0; +} + +/*********************************************************************************************************************** + * D Q C H A N + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: DequantBlock + * + * Description: Ken's highly-optimized, low memory dequantizer performing the operation + * y = pow(x, 4.0/3.0) * pow(2, 25 - scale/4.0) + * + * Inputs: input buffer of decode Huffman codewords (signed-magnitude) + * output buffer of same length (in-place (outbuf = inbuf) is allowed) + * number of samples + * + * Outputs: dequantized samples in Q25 format + * + * Return: bitwise-OR of the unsigned outputs (for guard bit calculations) + **********************************************************************************************************************/ +int32_t DequantBlock(int32_t *inbuf, int32_t *outbuf, int32_t num, int32_t scale){ + int32_t tab4[4]; + int32_t scalef, scalei, shift; + int32_t sx, x, y; + int32_t mask = 0; + const int32_t *tab16; + const uint32_t *coef; + + tab16 = pow43_14[scale & 0x3]; + scalef = pow14[scale & 0x3]; + scalei =((scale >> 2) < 31 ? (scale >> 2) : 31 ); + //scalei = MIN(scale >> 2, 31); /* smallest input scale = -47, so smallest scalei = -12 */ + + /* cache first 4 values */ + shift = (scalei + 3 < 31 ? scalei + 3 : 31); + shift = (shift > 0 ? shift : 0); + + tab4[0] = 0; + tab4[1] = tab16[1] >> shift; + tab4[2] = tab16[2] >> shift; + tab4[3] = tab16[3] >> shift; + + do { + sx = *inbuf++; + x = sx & 0x7fffffff; /* sx = sign|mag */ + if (x < 4) { + y = tab4[x]; + } else if (x < 16) { + y = tab16[x]; + y = (scalei < 0) ? y << -scalei : y >> scalei; + } else { + if (x < 64) { + y = pow43[x-16]; + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - 3; + } else { + /* normalize to [0x40000000, 0x7fffffff] */ + x <<= 17; + shift = 0; + if (x < 0x08000000) + x <<= 4, shift += 4; + if (x < 0x20000000) + x <<= 2, shift += 2; + if (x < 0x40000000) + x <<= 1, shift += 1; + + coef = (x < m_SQRTHALF) ? poly43lo : poly43hi; + + /* polynomial */ + y = coef[0]; + y = MULSHIFT32(y, x) + coef[1]; + y = MULSHIFT32(y, x) + coef[2]; + y = MULSHIFT32(y, x) + coef[3]; + y = MULSHIFT32(y, x) + coef[4]; + y = MULSHIFT32(y, pow2frac[shift]) << 3; + + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - pow2exp[shift]; + } + + /* integer scale */ + if (shift < 0) { + shift = -shift; + if (y > (0x7fffffff >> shift)) + y = 0x7fffffff; /* clip */ + else + y <<= shift; + } else { + y >>= shift; + } + } + + /* sign and store */ + mask |= y; + *outbuf++ = (sx < 0) ? -y : y; + + } while (--num); + + return mask; +} + +/*********************************************************************************************************************** + * Function: DequantChannel + * + * Description: dequantize one granule, one channel worth of decoded Huffman codewords + * + * Inputs: sample buffer (decoded Huffman codewords), length = m_MAX_NSAMP samples + * work buffer for reordering short-block, length = m_MAX_REORDER_SAMPS + * samples (3 * width of largest short-block critical band) + * non-zero bound for this channel/granule + * valid FrameHeader, SideInfoSub, ScaleFactorInfoSub, and CriticalBandInfo + * structures for this channel/granule + * + * Outputs: MAX_NSAMP dequantized samples in sampleBuf + * updated non-zero bound (indicating which samples are != 0 after DQ) + * filled-in cbi structure indicating start and end critical bands + * + * Return: minimum number of guard bits in dequantized sampleBuf + * + * Notes: dequantized samples in Q(DQ_FRACBITS_OUT) format + **********************************************************************************************************************/ +int32_t DequantChannel(int32_t *sampleBuf, int32_t *workBuf, int32_t *nonZeroBound, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, + CriticalBandInfo_t *cbi) +{ + int32_t i, j, w, cb; + int32_t /* cbStartL, */ cbEndL, cbStartS, cbEndS; + int32_t nSamps, nonZero, sfactMultiplier, gbMask; + int32_t globalGain, gainI; + int32_t cbMax[3]; + typedef int32_t ARRAY3[3]; /* for short-block reordering */ + ARRAY3 *buf; /* short block reorder */ + + /* set default start/end points for short/long blocks - will update with non-zero cb info */ + if (sis->blockType == 2) { + // cbStartL = 0; + if (sis->mixedBlock) { + cbEndL = (m_MPEGVersion == MPEG1 ? 8 : 6); + cbStartS = 3; + } else { + cbEndL = 0; + cbStartS = 0; + } + cbEndS = 13; + } else { + /* long block */ + //cbStartL = 0; + cbEndL = 22; + cbStartS = 13; + cbEndS = 13; + } + cbMax[2] = cbMax[1] = cbMax[0] = 0; + gbMask = 0; + i = 0; + + /* sfactScale = 0 --> quantizer step size = 2 + * sfactScale = 1 --> quantizer step size = sqrt(2) + * so sfactMultiplier = 2 or 4 (jump through globalGain by powers of 2 or sqrt(2)) + */ + sfactMultiplier = 2 * (sis->sfactScale + 1); + + /* offset globalGain by -2 if midSide enabled, for 1/sqrt(2) used in MidSideProc() + * (DequantBlock() does 0.25 * gainI so knocking it down by two is the same as + * dividing every sample by sqrt(2) = multiplying by 2^-.5) + */ + globalGain = sis->globalGain; + if (m_FrameHeader->modeExt >> 1) + globalGain -= 2; + globalGain += m_IMDCT_SCALE; /* scale everything by sqrt(2), for fast IMDCT36 */ + + /* long blocks */ + for (cb = 0; cb < cbEndL; cb++) { + + nonZero = 0; + nSamps = m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + gainI = 210 - globalGain + sfactMultiplier * (sfis->l[cb] + (sis->preFlag ? (int32_t)preTab[cb] : 0)); + + nonZero |= DequantBlock(sampleBuf + i, sampleBuf + i, nSamps, gainI); + i += nSamps; + + /* update highest non-zero critical band */ + if (nonZero) + cbMax[0] = cb; + gbMask |= nonZero; + + if (i >= *nonZeroBound) + break; + } + + /* set cbi (Type, EndS[], EndSMax will be overwritten if we proceed to do short blocks) */ + cbi->cbType = 0; /* long only */ + cbi->cbEndL = cbMax[0]; + cbi->cbEndS[0] = cbi->cbEndS[1] = cbi->cbEndS[2] = 0; + cbi->cbEndSMax = 0; + + /* early exit if no short blocks */ + if (cbStartS >= 12) + return CLZ(gbMask) - 1; + + /* short blocks */ + cbMax[2] = cbMax[1] = cbMax[0] = cbStartS; + for (cb = cbStartS; cb < cbEndS; cb++) { + + nSamps = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + for (w = 0; w < 3; w++) { + nonZero = 0; + gainI = 210 - globalGain + 8*sis->subBlockGain[w] + sfactMultiplier*(sfis->s[cb][w]); + + nonZero |= DequantBlock(sampleBuf + i + nSamps*w, workBuf + nSamps*w, nSamps, gainI); + + /* update highest non-zero critical band */ + if (nonZero) + cbMax[w] = cb; + gbMask |= nonZero; + } + + /* reorder blocks */ + buf = (ARRAY3 *)(sampleBuf + i); + i += 3*nSamps; + for (j = 0; j < nSamps; j++) { + buf[j][0] = workBuf[0*nSamps + j]; + buf[j][1] = workBuf[1*nSamps + j]; + buf[j][2] = workBuf[2*nSamps + j]; + } + + assert(3*nSamps <= m_MAX_REORDER_SAMPS); + + if (i >= *nonZeroBound) + break; + } + + /* i = last non-zero INPUT sample processed, which corresponds to highest possible non-zero + * OUTPUT sample (after reorder) + * however, the original nzb is no longer necessarily true + * for each cb, buf[][] is updated with 3*nSamps samples (i increases 3*nSamps each time) + * (buf[j + 1][0] = 3 (input) samples ahead of buf[j][0]) + * so update nonZeroBound to i + */ + *nonZeroBound = i; + + assert(*nonZeroBound <= m_MAX_NSAMP); + + cbi->cbType = (sis->mixedBlock ? 2 : 1); /* 2 = mixed short/long, 1 = short only */ + + cbi->cbEndS[0] = cbMax[0]; + cbi->cbEndS[1] = cbMax[1]; + cbi->cbEndS[2] = cbMax[2]; + + cbi->cbEndSMax = cbMax[0]; + cbi->cbEndSMax = (cbi->cbEndSMax > cbMax[1] ? cbi->cbEndSMax : cbMax[1]); + cbi->cbEndSMax = (cbi->cbEndSMax > cbMax[2] ? cbi->cbEndSMax : cbMax[2]); + + return CLZ(gbMask) - 1; +} + +/*********************************************************************************************************************** + * S T P R O C + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: MidSideProc + * + * Description: sum-difference stereo reconstruction + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples (MAX of left and right) + * assume 1 guard bit in input + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + **********************************************************************************************************************/ +void MidSideProc(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, int32_t mOut[2]){ + int32_t i, xr, xl, mOutL, mOutR; + + /* L = (M+S)/sqrt(2), R = (M-S)/sqrt(2) + * NOTE: 1/sqrt(2) done in DequantChannel() - see comments there + */ + mOutL = mOutR = 0; + for (i = 0; i < nSamps; i++) { + xl = x[0][i]; + xr = x[1][i]; + x[0][i] = xl + xr; + x[1][i] = xl - xr; + mOutL |= FASTABS(x[0][i]); + mOutR |= FASTABS(x[1][i]); + } + mOut[0] |= mOutL; + mOut[1] |= mOutR; +} + +/*********************************************************************************************************************** + * Function: IntensityProcMPEG1 + * + * Description: intensity stereo processing for MPEG1 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + **********************************************************************************************************************/ +void IntensityProcMPEG1(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t *sfis, + CriticalBandInfo_t *cbi, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]) +{ + int32_t i = 0, j = 0, n = 0, cb = 0, w = 0; + int32_t sampsLeft, isf, mOutL, mOutR, xl, xr; + int32_t fl, fr, fls[3], frs[3]; + int32_t cbStartL = 0, cbStartS = 0, cbEndL = 0, cbEndS = 0; + int32_t *isfTab; + (void) mixFlag; + + /* NOTE - this works fine for mixed blocks, as long as the switch point starts in the + * short block section (i.e. on or after sample 36 = sfBand->l[8] = 3*sfBand->s[3] + * is this a safe assumption? + */ + if (cbi[1].cbType == 0) { + /* long block */ + cbStartL = cbi[1].cbEndL + 1; + cbEndL = cbi[0].cbEndL + 1; + cbStartS = cbEndS = 0; + i = m_SFBandTable.l[cbStartL]; + } else if (cbi[1].cbType == 1 || cbi[1].cbType == 2) { + /* short or mixed block */ + cbStartS = cbi[1].cbEndSMax + 1; + cbEndS = cbi[0].cbEndSMax + 1; + cbStartL = cbEndL = 0; + i = 3 * m_SFBandTable.s[cbStartS]; + } + sampsLeft = nSamps - i; /* process to length of left */ + isfTab = (int32_t *) ISFMpeg1[midSideFlag]; + mOutL = mOutR = 0; + + /* long blocks */ + for (cb = cbStartL; cb < cbEndL && sampsLeft > 0; cb++) { + isf = sfis->l[cb]; + if (isf == 7) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + fl = isfTab[isf]; + fr = isfTab[6] - isfTab[isf]; + } + + n = m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + for (j = 0; j < n && sampsLeft > 0; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + sampsLeft--; + } + } + /* short blocks */ + for (cb = cbStartS; cb < cbEndS && sampsLeft >= 3; cb++) { + for (w = 0; w < 3; w++) { + isf = sfis->s[cb][w]; + if (isf == 7) { + fls[w] = ISFIIP[midSideFlag][0]; + frs[w] = ISFIIP[midSideFlag][1]; + } else { + fls[w] = isfTab[isf]; + frs[w] = isfTab[6] - isfTab[isf]; + } + } + n = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + for (j = 0; j < n && sampsLeft >= 3; j++, i += 3) { + xr = MULSHIFT32(frs[0], x[0][i + 0]) << 2; + x[1][i + 0] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[0], x[0][i + 0]) << 2; + x[0][i + 0] = xl; + mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[1], x[0][i + 1]) << 2; + x[1][i + 1] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[1], x[0][i + 1]) << 2; + x[0][i + 1] = xl; + mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[2], x[0][i + 2]) << 2; + x[1][i + 2] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[2], x[0][i + 2]) << 2; + x[0][i + 2] = xl; + mOutL |= FASTABS(xl); + sampsLeft -= 3; + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + return; +} + +/*********************************************************************************************************************** + * Function: IntensityProcMPEG2 + * + * Description: intensity stereo processing for MPEG2 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * ScaleFactorJS struct with joint stereo info from UnpackSFMPEG2() + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + **********************************************************************************************************************/ +void IntensityProcMPEG2(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, + ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi, + ScaleFactorJS_t *sfjs, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]) { + int32_t i, j, k, n, r, cb, w; + int32_t fl, fr, mOutL, mOutR, xl, xr; + int32_t sampsLeft; + int32_t isf, sfIdx, tmp, il[23]; + int32_t *isfTab; + int32_t cbStartL, cbStartS, cbEndL, cbEndS; + + (void) mixFlag; + + isfTab = (int32_t *) ISFMpeg2[sfjs->intensityScale][midSideFlag]; + mOutL = mOutR = 0; + + /* fill buffer with illegal intensity positions (depending on slen) */ + for (k = r = 0; r < 4; r++) { + tmp = (1 << sfjs->slen[r]) - 1; + for (j = 0; j < sfjs->nr[r]; j++, k++) + il[k] = tmp; + } + + if (cbi[1].cbType == 0) { + /* long blocks */ + il[21] = il[22] = 1; + cbStartL = cbi[1].cbEndL + 1; /* start at end of right */ + cbEndL = cbi[0].cbEndL + 1; /* process to end of left */ + i = m_SFBandTable.l[cbStartL]; + sampsLeft = nSamps - i; + + for (cb = cbStartL; cb < cbEndL; cb++) { + sfIdx = sfis->l[cb]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->l[cb] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + int32_t r=m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + n=(r < sampsLeft ? r : sampsLeft); + //n = MIN(fh->sfBand->l[cb + 1] - fh->sfBand->l[cb], sampsLeft); + for (j = 0; j < n; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + } + /* early exit once we've used all the non-zero samples */ + sampsLeft -= n; + if (sampsLeft == 0) + break; + } + } else { + /* short or mixed blocks */ + il[12] = 1; + + for (w = 0; w < 3; w++) { + cbStartS = cbi[1].cbEndS[w] + 1; /* start at end of right */ + cbEndS = cbi[0].cbEndS[w] + 1; /* process to end of left */ + i = 3 * m_SFBandTable.s[cbStartS] + w; + + /* skip through sample array by 3, so early-exit logic would be more tricky */ + for (cb = cbStartS; cb < cbEndS; cb++) { + sfIdx = sfis->s[cb][w]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->s[cb][w] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + n = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + + for (j = 0; j < n; j++, i += 3) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + } + } + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + return; +} + +/*********************************************************************************************************************** + * I M D C T + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: AntiAlias + * + * Description: smooth transition across DCT block boundaries (every 18 coefficients) + * + * Inputs: vector of dequantized coefficients, length = (nBfly+1) * 18 + * number of "butterflies" to perform (one butterfly means one + * inter-block smoothing operation) + * + * Outputs: updated coefficient vector x + * + * Return: none + * + * Notes: weighted average of opposite bands (pairwise) from the 8 samples + * before and after each block boundary + * nBlocks = (nonZeroBound + 7) / 18, since nZB is the first ZERO sample + * above which all other samples are also zero + * max gain per sample = 1.372 + * MAX(i) (abs(csa[i][0]) + abs(csa[i][1])) + * bits gained = 0 + * assume at least 1 guard bit in x[] to avoid overflow + * (should be guaranteed from dequant, and max gain from stproc * max + * gain from AntiAlias < 2.0) + **********************************************************************************************************************/ +// a little bit faster in RAM (< 1 ms per block) +/* __attribute__ ((section (".data"))) */ +void AntiAlias(int32_t *x, int32_t nBfly){ + int32_t k, a0, b0, c0, c1; + const uint32_t *c; + + /* csa = Q31 */ + for (k = nBfly; k > 0; k--) { + c = csa[0]; + x += 18; + a0 = x[-1]; + c0 = *c; + c++; + b0 = x[0]; + c1 = *c; + c++; + x[-1] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[0] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-2]; + c0 = *c; + c++; + b0 = x[1]; + c1 = *c; + c++; + x[-2] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[1] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-3]; + c0 = *c; + c++; + b0 = x[2]; + c1 = *c; + c++; + x[-3] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[2] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-4]; + c0 = *c; + c++; + b0 = x[3]; + c1 = *c; + c++; + x[-4] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[3] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-5]; + c0 = *c; + c++; + b0 = x[4]; + c1 = *c; + c++; + x[-5] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[4] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-6]; + c0 = *c; + c++; + b0 = x[5]; + c1 = *c; + c++; + x[-6] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[5] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-7]; + c0 = *c; + c++; + b0 = x[6]; + c1 = *c; + c++; + x[-7] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[6] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-8]; + c0 = *c; + c++; + b0 = x[7]; + c1 = *c; + c++; + x[-8] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[7] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + } +} + +/*********************************************************************************************************************** + * Function: WinPrevious + * + * Description: apply specified window to second half of previous IMDCT (overlap part) + * + * Inputs: vector of 9 coefficients (xPrev) + * + * Outputs: 18 windowed output coefficients (gain 1 integer bit) + * window type (0, 1, 2, 3) + * + * Return: none + * + * Notes: produces 9 output samples from 18 input samples via symmetry + * all blocks gain at least 1 guard bit via window (long blocks get extra + * sign bit, short blocks can have one addition but max gain < 1.0) + **********************************************************************************************************************/ + +void WinPrevious(int32_t *xPrev, int32_t *xPrevWin, int32_t btPrev){ + int32_t i, x, *xp, *xpwLo, *xpwHi, wLo, wHi; + const uint32_t *wpLo, *wpHi; + + xp = xPrev; + /* mapping (see IMDCT12x3): xPrev[0-2] = sum[6-8], xPrev[3-8] = sum[12-17] */ + if (btPrev == 2) { + /* this could be reordered for minimum loads/stores */ + wpLo = imdctWin[btPrev]; + xPrevWin[0] = MULSHIFT32(wpLo[6], xPrev[2]) + + MULSHIFT32(wpLo[0], xPrev[6]); + xPrevWin[1] = MULSHIFT32(wpLo[7], xPrev[1]) + + MULSHIFT32(wpLo[1], xPrev[7]); + xPrevWin[2] = MULSHIFT32(wpLo[8], xPrev[0]) + + MULSHIFT32(wpLo[2], xPrev[8]); + xPrevWin[3] = MULSHIFT32(wpLo[9], xPrev[0]) + + MULSHIFT32(wpLo[3], xPrev[8]); + xPrevWin[4] = MULSHIFT32(wpLo[10], xPrev[1]) + + MULSHIFT32(wpLo[4], xPrev[7]); + xPrevWin[5] = MULSHIFT32(wpLo[11], xPrev[2]) + + MULSHIFT32(wpLo[5], xPrev[6]); + xPrevWin[6] = MULSHIFT32(wpLo[6], xPrev[5]); + xPrevWin[7] = MULSHIFT32(wpLo[7], xPrev[4]); + xPrevWin[8] = MULSHIFT32(wpLo[8], xPrev[3]); + xPrevWin[9] = MULSHIFT32(wpLo[9], xPrev[3]); + xPrevWin[10] = MULSHIFT32(wpLo[10], xPrev[4]); + xPrevWin[11] = MULSHIFT32(wpLo[11], xPrev[5]); + xPrevWin[12] = xPrevWin[13] = xPrevWin[14] = xPrevWin[15] = + xPrevWin[16] = xPrevWin[17] = 0; + } else { + /* use ARM-style pointers (*ptr++) so that ADS compiles well */ + wpLo = imdctWin[btPrev] + 18; + wpHi = wpLo + 17; + xpwLo = xPrevWin; + xpwHi = xPrevWin + 17; + for (i = 9; i > 0; i--) { + x = *xp++; + wLo = *wpLo++; + wHi = *wpHi--; + *xpwLo++ = MULSHIFT32(wLo, x); + *xpwHi-- = MULSHIFT32(wHi, x); + } + } +} + +/*********************************************************************************************************************** + * Function: FreqInvertRescale + * + * Description: do frequency inversion (odd samples of odd blocks) and rescale + * if necessary (extra guard bits added before IMDCT) + * + * Inputs: output vector y (18 new samples, spaced NBANDS apart) + * previous sample vector xPrev (9 samples) + * index of current block + * number of extra shifts added before IMDCT (usually 0) + * + * Outputs: inverted and rescaled (as necessary) outputs + * rescaled (as necessary) previous samples + * + * Return: updated mOut (from new outputs y) + **********************************************************************************************************************/ + +int32_t FreqInvertRescale(int32_t *y, int32_t *xPrev, int32_t blockIdx, int32_t es) { + + if (es == 0) { + /* fast case - frequency invert only (no rescaling) */ + if (blockIdx & 0x01) { + y += m_NBANDS; + for (int32_t i = 0; i < 9; i++) { + *y = - *y; y += 2 * m_NBANDS; + } + } + return 0; + } + + int32_t d, mOut; + /* undo pre-IMDCT scaling, clipping if necessary */ + mOut = 0; + if (blockIdx & 0x01) { + /* frequency invert */ + for (int32_t i = 0; i < 9; i++) { + d = *y; CLIP_2N(d, (31 - es)); *y = d << es; mOut |= FASTABS(*y); y += m_NBANDS; + d = -*y; CLIP_2N(d, (31 - es)); *y = d << es; mOut |= FASTABS(*y); y += m_NBANDS; + d = *xPrev; CLIP_2N(d, (31 - es)); *xPrev++ = d << es; + } + } else { + for (int32_t i = 0; i < 9; i++) { + d = *y; CLIP_2N(d, (31 - es)); *y = d << es; mOut |= FASTABS(*y); y += m_NBANDS; + d = *y; CLIP_2N(d, (31 - es)); *y = d << es; mOut |= FASTABS(*y); y += m_NBANDS; + d = *xPrev; CLIP_2N(d, (31 - es)); *xPrev++ = d << es; + } + } + return mOut; + +} + + +/* require at least 3 guard bits in x[] to ensure no overflow */ +void idct9(int32_t *x) { + int32_t a1, a2, a3, a4, a5, a6, a7, a8, a9; + int32_t a10, a11, a12, a13, a14, a15, a16, a17, a18; + int32_t a19, a20, a21, a22, a23, a24, a25, a26, a27; + int32_t m1, m3, m5, m6, m7, m8, m9, m10, m11, m12; + int32_t x0, x1, x2, x3, x4, x5, x6, x7, x8; + + x0 = x[0]; + x1 = x[1]; + x2 = x[2]; + x3 = x[3]; + x4 = x[4]; + x5 = x[5]; + x6 = x[6]; + x7 = x[7]; + x8 = x[8]; + + a1 = x0 - x6; + a2 = x1 - x5; + a3 = x1 + x5; + a4 = x2 - x4; + a5 = x2 + x4; + a6 = x2 + x8; + a7 = x1 + x7; + + a8 = a6 - a5; /* ie x[8] - x[4] */ + a9 = a3 - a7; /* ie x[5] - x[7] */ + a10 = a2 - x7; /* ie x[1] - x[5] - x[7] */ + a11 = a4 - x8; /* ie x[2] - x[4] - x[8] */ + + /* do the << 1 as constant shifts where mX is actually used (free, no stall or extra inst.) */ + m1 = MULSHIFT32(c9_0, x3); + m3 = MULSHIFT32(c9_0, a10); + m5 = MULSHIFT32(c9_1, a5); + m6 = MULSHIFT32(c9_2, a6); + m7 = MULSHIFT32(c9_1, a8); + m8 = MULSHIFT32(c9_2, a5); + m9 = MULSHIFT32(c9_3, a9); + m10 = MULSHIFT32(c9_4, a7); + m11 = MULSHIFT32(c9_3, a3); + m12 = MULSHIFT32(c9_4, a9); + + a12 = x[0] + (x[6] >> 1); + a13 = a12 + (m1 << 1); + a14 = a12 - (m1 << 1); + a15 = a1 + (a11 >> 1); + a16 = (m5 << 1) + (m6 << 1); + a17 = (m7 << 1) - (m8 << 1); + a18 = a16 + a17; + a19 = (m9 << 1) + (m10 << 1); + a20 = (m11 << 1) - (m12 << 1); + + a21 = a20 - a19; + a22 = a13 + a16; + a23 = a14 + a16; + a24 = a14 + a17; + a25 = a13 + a17; + a26 = a14 - a18; + a27 = a13 - a18; + + x0 = a22 + a19; + x[0] = x0; + x1 = a15 + (m3 << 1); + x[1] = x1; + x2 = a24 + a20; + x[2] = x2; + x3 = a26 - a21; + x[3] = x3; + x4 = a1 - a11; + x[4] = x4; + x5 = a27 + a21; + x[5] = x5; + x6 = a25 - a20; + x[6] = x6; + x7 = a15 - (m3 << 1); + x[7] = x7; + x8 = a23 - a19; + x[8] = x8; +} + + +/*********************************************************************************************************************** + * Function: IMDCT36 + * + * Description: 36-point modified DCT, with windowing and overlap-add (50% overlap) + * + * Inputs: vector of 18 coefficients (N/2 inputs produces N outputs, by symmetry) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of current and previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: 18 output samples, after windowing and overlap-add with last frame + * second half of (unwindowed) 36-point IMDCT - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Notes: this is Ken's hyper-fast algorithm, including symmetric sin window + * optimization, if applicable + * total number of multiplies, general case: + * 2*10 (idct9) + 9 (last stage imdct) + 36 (for windowing) = 65 + * total number of multiplies, btCurr == 0 && btPrev == 0: + * 2*10 (idct9) + 9 (last stage imdct) + 18 (for windowing) = 47 + * + * blockType == 0 is by far the most common case, so it should be + * possible to use the fast path most of the time + * this is the fastest known algorithm for performing + * long IMDCT + windowing + overlap-add in MP3 + * + * Return: mOut (OR of abs(y) for all y calculated here) + **********************************************************************************************************************/ +// barely faster in RAM + +int32_t IMDCT36(int32_t *xCurr, int32_t *xPrev, int32_t *y, int32_t btCurr, int32_t btPrev, int32_t blockIdx, int32_t gb){ + int32_t i, es, xBuf[18], xPrevWin[18]; + int32_t acc1, acc2, s, d, t, mOut; + int32_t xo, xe, c, *xp, yLo, yHi; + const uint32_t *cp, *wp; + acc1 = acc2 = 0; + xCurr += 17; + /* 7 gb is always adequate for antialias + accumulator loop + idct9 */ + if (gb < 7) { + /* rarely triggered - 5% to 10% of the time on normal clips (with Q25 input) */ + es = 7 - gb; + for (i = 8; i >= 0; i--) { + acc1 = ((*xCurr--) >> es) - acc1; + acc2 = acc1 - acc2; + acc1 = ((*xCurr--) >> es) - acc1; + xBuf[i + 9] = acc2; /* odd */ + xBuf[i + 0] = acc1; /* even */ + xPrev[i] >>= es; + } + } else { + es = 0; + /* max gain = 18, assume adequate guard bits */ + for (i = 8; i >= 0; i--) { + acc1 = (*xCurr--) - acc1; + acc2 = acc1 - acc2; + acc1 = (*xCurr--) - acc1; + xBuf[i + 9] = acc2; /* odd */ + xBuf[i + 0] = acc1; /* even */ + } + } + /* xEven[0] and xOdd[0] scaled by 0.5 */ + xBuf[9] >>= 1; + xBuf[0] >>= 1; + + /* do 9-point IDCT on even and odd */ + idct9(xBuf + 0); /* even */ + idct9(xBuf + 9); /* odd */ + + xp = xBuf + 8; + cp = c18 + 8; + mOut = 0; + if (btPrev == 0 && btCurr == 0) { + /* fast path - use symmetry of sin window to reduce windowing multiplies to 18 (N/2) */ + wp = fastWin36; + for (i = 0; i < 9; i++) { + /* do ARM-style pointer arithmetic (i still needed for y[] indexing - compiler spills if 2 y pointers) */ + c = *cp--; + xo = *(xp + 9); + xe = *xp--; + /* gain 2int32_t bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + s = -(*xPrev); /* sum from last block (always at least 2 guard bits) */ + d = -(xe - xo); /* gain 2int32_t bits, don't shift xo (effective << 1 to eat sign bit, << 1 for mul by 2) */ + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + t = s - d; + + yLo = (d + (MULSHIFT32(t, *wp++) << 2)); + yHi = (s + (MULSHIFT32(t, *wp++) << 2)); + y[(i) * m_NBANDS] = yLo; + y[(17 - i) * m_NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } else { + /* slower method - either prev or curr is using window type != 0 so do full 36-point window + * output xPrevWin has at least 3 guard bits (xPrev has 2, gain 1 in WinPrevious) + */ + WinPrevious(xPrev, xPrevWin, btPrev); + + wp = imdctWin[btCurr]; + for (i = 0; i < 9; i++) { + c = *cp--; + xo = *(xp + 9); + xe = *xp--; + /* gain 2int32_t bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + d = xe - xo; + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + + yLo = (xPrevWin[i] + MULSHIFT32(d, wp[i])) << 2; + yHi = (xPrevWin[17 - i] + MULSHIFT32(d, wp[17 - i])) << 2; + y[(i) * m_NBANDS] = yLo; + y[(17 - i) * m_NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} + + + +/* 12-point inverse DCT, used in IMDCT12x3() + * 4 input guard bits will ensure no overflow + */ +void imdct12(int32_t *x, int32_t *out) { + int32_t a0, a1, a2; + int32_t x0, x1, x2, x3, x4, x5; + + x0 = *x; + x += 3; + x1 = *x; + x += 3; + x2 = *x; + x += 3; + x3 = *x; + x += 3; + x4 = *x; + x += 3; + x5 = *x; + x += 3; + + x4 -= x5; + x3 -= x4; + x2 -= x3; + x3 -= x5; + x1 -= x2; + x0 -= x1; + x1 -= x3; + + x0 >>= 1; + x1 >>= 1; + + a0 = MULSHIFT32(c3_0, x2) << 1; + a1 = x0 + (x4 >> 1); + a2 = x0 - x4; + x0 = a1 + a0; + x2 = a2; + x4 = a1 - a0; + + a0 = MULSHIFT32(c3_0, x3) << 1; + a1 = x1 + (x5 >> 1); + a2 = x1 - x5; + + /* cos window odd samples, mul by 2, eat sign bit */ + x1 = MULSHIFT32(c6[0], a1 + a0) << 2; + x3 = MULSHIFT32(c6[1], a2) << 2; + x5 = MULSHIFT32(c6[2], a1 - a0) << 2; + + *out = x0 + x1; + out++; + *out = x2 + x3; + out++; + *out = x4 + x5; + out++; + *out = x4 - x5; + out++; + *out = x2 - x3; + out++; + *out = x0 - x1; +} + +/*********************************************************************************************************************** + * Function: IMDCT12x3 + * + * Description: three 12-point modified DCT's for short blocks, with windowing, + * short block concatenation, and overlap-add + * + * Inputs: 3 interleaved vectors of 6 samples each + * (block0[0], block1[0], block2[0], block0[1], block1[1]....) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: updated sample vector x, net gain of 1 integer bit + * second half of (unwindowed) IMDCT's - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Return: mOut (OR of abs(y) for all y calculated here) + **********************************************************************************************************************/ +// barely faster in RAM +int32_t IMDCT12x3(int32_t *xCurr, int32_t *xPrev, int32_t *y, int32_t btPrev, int32_t blockIdx, int32_t gb){ + int32_t i, es, mOut, yLo, xBuf[18], xPrevWin[18]; /* need temp buffer for reordering short blocks */ + const uint32_t *wp; + es = 0; + /* 7 gb is always adequate for accumulator loop + idct12 + window + overlap */ + if (gb < 7) { + es = 7 - gb; + for (i = 0; i < 18; i += 2) { + xCurr[i + 0] >>= es; + xCurr[i + 1] >>= es; + *xPrev++ >>= es; + } + xPrev -= 9; + } + + /* requires 4 input guard bits for each imdct12 */ + imdct12(xCurr + 0, xBuf + 0); + imdct12(xCurr + 1, xBuf + 6); + imdct12(xCurr + 2, xBuf + 12); + + /* window previous from last time */ + WinPrevious(xPrev, xPrevWin, btPrev); + + /* could unroll this for speed, minimum loads (short blocks usually rare, so doesn't make much overall difference) + * xPrevWin[i] << 2 still has 1 gb always, max gain of windowed xBuf stuff also < 1.0 and gain the sign bit + * so y calculations won't overflow + */ + wp = imdctWin[2]; + mOut = 0; + for (i = 0; i < 3; i++) { + yLo = (xPrevWin[0 + i] << 2); + mOut |= FASTABS(yLo); + y[(0 + i) * m_NBANDS] = yLo; + yLo = (xPrevWin[3 + i] << 2); + mOut |= FASTABS(yLo); + y[(3 + i) * m_NBANDS] = yLo; + yLo = (xPrevWin[6 + i] << 2) + (MULSHIFT32(wp[0 + i], xBuf[3 + i])); + mOut |= FASTABS(yLo); + y[(6 + i) * m_NBANDS] = yLo; + yLo = (xPrevWin[9 + i] << 2) + (MULSHIFT32(wp[3 + i], xBuf[5 - i])); + mOut |= FASTABS(yLo); + y[(9 + i) * m_NBANDS] = yLo; + yLo = (xPrevWin[12 + i] << 2) + + (MULSHIFT32(wp[6 + i], xBuf[2 - i]) + + MULSHIFT32(wp[0 + i], xBuf[(6 + 3) + i])); + mOut |= FASTABS(yLo); + y[(12 + i) * m_NBANDS] = yLo; + yLo = (xPrevWin[15 + i] << 2) + + (MULSHIFT32(wp[9 + i], xBuf[0 + i]) + + MULSHIFT32(wp[3 + i], xBuf[(6 + 5) - i])); + mOut |= FASTABS(yLo); + y[(15 + i) * m_NBANDS] = yLo; + } + + /* save previous (unwindowed) for overlap - only need samples 6-8, 12-17 */ + for (i = 6; i < 9; i++) + *xPrev++ = xBuf[i] >> 2; + for (i = 12; i < 18; i++) + *xPrev++ = xBuf[i] >> 2; + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} + +/*********************************************************************************************************************** + * Function: HybridTransform + * + * Description: IMDCT's, windowing, and overlap-add on long/short/mixed blocks + * + * Inputs: vector of input coefficients, length = nBlocksTotal * 18) + * vector of overlap samples from last time, length = nBlocksPrev * 9) + * buffer for output samples, length = MAXNSAMP + * SideInfoSub struct for this granule/channel + * BlockCount struct with necessary info + * number of non-zero input and overlap blocks + * number of long blocks in input vector (rest assumed to be short blocks) + * number of blocks which use long window (type) 0 in case of mixed block + * (bc->currWinSwitch, 0 for non-mixed blocks) + * + * Outputs: transformed, windowed, and overlapped sample buffer + * does frequency inversion on odd blocks + * updated buffer of samples for overlap + * + * Return: number of non-zero IMDCT blocks calculated in this call + * (including overlap-add) + **********************************************************************************************************************/ +int32_t HybridTransform(int32_t *xCurr, int32_t *xPrev, int32_t y[m_BLOCK_SIZE][m_NBANDS], SideInfoSub_t *sis, BlockCount_t *bc){ + int32_t xPrevWin[18], currWinIdx, prevWinIdx; + int32_t i, j, nBlocksOut, nonZero, mOut; + int32_t fiBit, xp; + + assert(bc->nBlocksLong <= m_NBANDS); + assert(bc->nBlocksTotal <= m_NBANDS); + assert(bc->nBlocksPrev <= m_NBANDS); + + mOut = 0; + + /* do long blocks, if any */ + for (i = 0; i < bc->nBlocksLong; i++) { + /* currWinIdx picks the right window for long blocks (if mixed, long blocks use window type 0) */ + currWinIdx = sis->blockType; + if (sis->mixedBlock && i < bc->currWinSwitch) + currWinIdx = 0; + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + + /* do 36-point IMDCT, including windowing and overlap-add */ + mOut |= IMDCT36(xCurr, xPrev, &(y[0][i]), currWinIdx, prevWinIdx, i, + bc->gbIn); + xCurr += 18; + xPrev += 9; + } + + /* do short blocks (if any) */ + for (; i < bc->nBlocksTotal; i++) { + assert(sis->blockType == 2); + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + + mOut |= IMDCT12x3(xCurr, xPrev, &(y[0][i]), prevWinIdx, i, bc->gbIn); + xCurr += 18; + xPrev += 9; + } + nBlocksOut = i; + + /* window and overlap prev if prev longer that current */ + for (; i < bc->nBlocksPrev; i++) { + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + WinPrevious(xPrev, xPrevWin, prevWinIdx); + + nonZero = 0; + fiBit = i << 31; + for (j = 0; j < 9; j++) { + xp = xPrevWin[2 * j + 0] << 2; /* << 2 temp for scaling */ + nonZero |= xp; + y[2 * j + 0][i] = xp; + mOut |= FASTABS(xp); + + /* frequency inversion on odd blocks/odd samples (flip sign if i odd, j odd) */ + xp = xPrevWin[2 * j + 1] << 2; + xp = (xp ^ (fiBit >> 31)) + (i & 0x01); + nonZero |= xp; + y[2 * j + 1][i] = xp; + mOut |= FASTABS(xp); + + xPrev[j] = 0; + } + xPrev += 9; + if (nonZero) + nBlocksOut = i; + } + + /* clear rest of blocks */ + for (; i < 32; i++) { + for (j = 0; j < 18; j++) + y[j][i] = 0; + } + + bc->gbOut = CLZ(mOut) - 1; + + return nBlocksOut; +} + +/*********************************************************************************************************************** + * Function: IMDCT + * + * Description: do alias reduction, inverse MDCT, overlap-add, and frequency inversion + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * UnpackScaleFactors(), and DecodeHuffman() (for this granule, channel) + * includes PCM samples in overBuf (from last call to IMDCT) for OLA + * index of current granule and channel + * + * Outputs: PCM samples in outBuf, for input to subband transform + * PCM samples in overBuf, for OLA next time + * updated hi->nonZeroBound index for this channel + * + * Return: 0 on success, -1 if null input pointers + **********************************************************************************************************************/ +// a bit faster in RAM +/*__attribute__ ((section (".data")))*/ +int32_t IMDCT(int32_t gr, int32_t ch) { + int32_t nBfly, blockCutoff; + BlockCount_t bc; + + /* m_SideInfo is an array of up to 4 structs, stored as gr0ch0, gr0ch1, gr1ch0, gr1ch1 */ + /* anti-aliasing done on whole long blocks only + * for mixed blocks, nBfly always 1, except 3 for 8 kHz MPEG 2.5 (see sfBandTab) + * nLongBlocks = number of blocks with (possibly) non-zero power + * nBfly = number of butterflies to do (nLongBlocks - 1, unless no long blocks) + */ + blockCutoff = m_SFBandTable.l[(m_MPEGVersion == MPEG1 ? 8 : 6)] / 18; /* same as 3* num short sfb's in spec */ + if (m_SideInfoSub[gr][ch].blockType != 2) { + /* all long transforms */ + int32_t x=(m_HuffmanInfo->nonZeroBound[ch] + 7) / 18 + 1; + bc.nBlocksLong=(x<32 ? x : 32); + //bc.nBlocksLong = min((hi->nonZeroBound[ch] + 7) / 18 + 1, 32); + nBfly = bc.nBlocksLong - 1; + } else if (m_SideInfoSub[gr][ch].blockType == 2 && m_SideInfoSub[gr][ch].mixedBlock) { + /* mixed block - long transforms until cutoff, then short transforms */ + bc.nBlocksLong = blockCutoff; + nBfly = bc.nBlocksLong - 1; + } else { + /* all short transforms */ + bc.nBlocksLong = 0; + nBfly = 0; + } + + AntiAlias(m_HuffmanInfo->huffDecBuf[ch], nBfly); + int32_t x=m_HuffmanInfo->nonZeroBound[ch]; + int32_t y=nBfly * 18 + 8; + m_HuffmanInfo->nonZeroBound[ch]=(x>y ? x: y); + + assert(m_HuffmanInfo->nonZeroBound[ch] <= m_MAX_NSAMP); + + /* for readability, use a struct instead of passing a million parameters to HybridTransform() */ + bc.nBlocksTotal = (m_HuffmanInfo->nonZeroBound[ch] + 17) / 18; + bc.nBlocksPrev = m_IMDCTInfo->numPrevIMDCT[ch]; + bc.prevType = m_IMDCTInfo->prevType[ch]; + bc.prevWinSwitch = m_IMDCTInfo->prevWinSwitch[ch]; + /* where WINDOW switches (not nec. transform) */ + bc.currWinSwitch = (m_SideInfoSub[gr][ch].mixedBlock ? blockCutoff : 0); + bc.gbIn = m_HuffmanInfo->gb[ch]; + + m_IMDCTInfo->numPrevIMDCT[ch] = HybridTransform(m_HuffmanInfo->huffDecBuf[ch], m_IMDCTInfo->overBuf[ch], + m_IMDCTInfo->outBuf[ch], &m_SideInfoSub[gr][ch], &bc); + m_IMDCTInfo->prevType[ch] = m_SideInfoSub[gr][ch].blockType; + m_IMDCTInfo->prevWinSwitch[ch] = bc.currWinSwitch; /* 0 means not a mixed block (either all short or all long) */ + m_IMDCTInfo->gb[ch] = bc.gbOut; + + assert(m_IMDCTInfo->numPrevIMDCT[ch] <= m_NBANDS); + + /* output has gained 2int32_t bits */ + return 0; +} + +/*********************************************************************************************************************** + * S U B B A N D + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: Subband + * + * Description: do subband transform on all the blocks in one granule, all channels + * + * Inputs: filled MP3DecInfo structure, after calling IMDCT for all channels + * vbuf[ch] and vindex[ch] must be preserved between calls + * + * Outputs: decoded PCM data, interleaved LRLRLR... if stereo + * + * Return: 0 on success, -1 if null input pointers + **********************************************************************************************************************/ +int32_t Subband(int16_t *pcmBuf) { + int32_t b; + if (m_MP3DecInfo->nChans == 2) { + /* stereo */ + for (b = 0; b < m_BLOCK_SIZE; b++) { + FDCT32(m_IMDCTInfo->outBuf[0][b], m_SubbandInfo->vbuf + 0 * 32, m_SubbandInfo->vindex, + (b & 0x01), m_IMDCTInfo->gb[0]); + FDCT32(m_IMDCTInfo->outBuf[1][b], m_SubbandInfo->vbuf + 1 * 32, m_SubbandInfo->vindex, + (b & 0x01), m_IMDCTInfo->gb[1]); + PolyphaseStereo(pcmBuf, + m_SubbandInfo->vbuf + m_SubbandInfo->vindex + m_VBUF_LENGTH * (b & 0x01), + polyCoef); + m_SubbandInfo->vindex = (m_SubbandInfo->vindex - (b & 0x01)) & 7; + pcmBuf += (2 * m_NBANDS); + } + } else { + /* mono */ + for (b = 0; b < m_BLOCK_SIZE; b++) { + FDCT32(m_IMDCTInfo->outBuf[0][b], m_SubbandInfo->vbuf + 0 * 32, m_SubbandInfo->vindex, + (b & 0x01), m_IMDCTInfo->gb[0]); + PolyphaseMono(pcmBuf, m_SubbandInfo->vbuf + m_SubbandInfo->vindex + m_VBUF_LENGTH * (b & 0x01), polyCoef); + m_SubbandInfo->vindex = (m_SubbandInfo->vindex - (b & 0x01)) & 7; + pcmBuf += m_NBANDS; + } + } + + return 0; +} + +/*********************************************************************************************************************** + * D C T 3 2 + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Function: FDCT32 + * + * Description: Ken's highly-optimized 32-point DCT (radix-4 + radix-8) + * + * Inputs: input buffer, length = 32 samples + * require at least 6 guard bits in input vector x to avoid possibility + * of overflow in internal calculations (see bbtest_imdct test app) + * buffer offset and oddblock flag for polyphase filter input buffer + * number of guard bits in input + * + * Outputs: output buffer, data copied and interleaved for polyphase filter + * no guarantees about number of guard bits in output + * + * Return: none + * + * Notes: number of muls = 4*8 + 12*4 = 80 + * final stage of DCT is hardcoded to shuffle data into the proper order + * for the polyphase filterbank + * fully unrolled stage 1, for max precision (scale the 1/cos() factors + * differently, depending on magnitude) + * guard bit analysis verified by exhaustive testing of all 2^32 + * combinations of max pos/max neg values in x[] + **********************************************************************************************************************/ +#define D32FP(i, s1, s2) { \ + a0 = buf[i]; a3 = buf[31-i]; \ + a1 = buf[15-i]; a2 = buf[16+i]; \ + b0 = a0 + a3; b3 = MULSHIFT32(*cptr++, a0 - a3) << 1; \ + b1 = a1 + a2; b2 = MULSHIFT32(*cptr++, a1 - a2) << (s1); \ + buf[i] = b0 + b1; buf[15-i] = MULSHIFT32(*cptr, b0 - b1) << (s2); \ + buf[16+i] = b2 + b3; buf[31-i] = MULSHIFT32(*cptr++, b3 - b2) << (s2); \ +} + +static const uint8_t FDCT32s1s2[16] = {5,3,3,2,2,1,1,1, 1,1,1,1,1,2,2,4}; + +void FDCT32(int32_t *buf, int32_t *dest, int32_t offset, int32_t oddBlock, int32_t gb) { + int32_t i, s, tmp, es; + const int32_t *cptr = (const int32_t*)m_dcttab; + int32_t a0, a1, a2, a3, a4, a5, a6, a7; + int32_t b0, b1, b2, b3, b4, b5, b6, b7; + int32_t *d; + + /* scaling - ensure at least 6 guard bits for DCT + * (in practice this is already true 99% of time, so this code is + * almost never triggered) + */ + es = 0; + if (gb < 6) { + es = 6 - gb; + for (i = 0; i < 32; i++) + buf[i] >>= es; + } + + /* first pass */ + for (unsigned i=0; i < 8; i++) { + D32FP(i, FDCT32s1s2[0 + i], FDCT32s1s2[8 + i]); + } + + /* second pass */ + for (i = 4; i > 0; i--) { + a0 = buf[0]; a7 = buf[7]; a3 = buf[3]; a4 = buf[4]; + b0 = a0 + a7; b7 = MULSHIFT32(*cptr++, a0 - a7) << 1; + b3 = a3 + a4; b4 = MULSHIFT32(*cptr++, a3 - a4) << 3; + a0 = b0 + b3; a3 = MULSHIFT32(*cptr, b0 - b3) << 1; + a4 = b4 + b7; a7 = MULSHIFT32(*cptr++, b7 - b4) << 1; + + a1 = buf[1]; a6 = buf[6]; a2 = buf[2]; a5 = buf[5]; + b1 = a1 + a6; b6 = MULSHIFT32(*cptr++, a1 - a6) << 1; + b2 = a2 + a5; b5 = MULSHIFT32(*cptr++, a2 - a5) << 1; + a1 = b1 + b2; a2 = MULSHIFT32(*cptr, b1 - b2) << 2; + a5 = b5 + b6; a6 = MULSHIFT32(*cptr++, b6 - b5) << 2; + + b0 = a0 + a1; b1 = MULSHIFT32(m_COS4_0, a0 - a1) << 1; + b2 = a2 + a3; b3 = MULSHIFT32(m_COS4_0, a3 - a2) << 1; + buf[0] = b0; buf[1] = b1; + buf[2] = b2 + b3; buf[3] = b3; + + b4 = a4 + a5; b5 = MULSHIFT32(m_COS4_0, a4 - a5) << 1; + b6 = a6 + a7; b7 = MULSHIFT32(m_COS4_0, a7 - a6) << 1; + b6 += b7; + buf[4] = b4 + b6; buf[5] = b5 + b7; + buf[6] = b5 + b6; buf[7] = b7; + + buf += 8; + } + buf -= 32; /* reset */ + + /* sample 0 - always delayed one block */ + d = dest + 64*16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : m_VBUF_LENGTH); + s = buf[ 0]; d[0] = d[8] = s; + + /* samples 16 to 31 */ + d = dest + offset + (oddBlock ? m_VBUF_LENGTH : 0); + + s = buf[ 1]; d[0] = d[8] = s; d += 64; + + tmp = buf[25] + buf[29]; + s = buf[17] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 9] + buf[13]; d[0] = d[8] = s; d += 64; + s = buf[21] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[29] + buf[27]; + s = buf[ 5]; d[0] = d[8] = s; d += 64; + s = buf[21] + tmp; d[0] = d[8] = s; d += 64; + s = buf[13] + buf[11]; d[0] = d[8] = s; d += 64; + s = buf[19] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[27] + buf[31]; + s = buf[ 3]; d[0] = d[8] = s; d += 64; + s = buf[19] + tmp; d[0] = d[8] = s; d += 64; + s = buf[11] + buf[15]; d[0] = d[8] = s; d += 64; + s = buf[23] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[31]; + s = buf[ 7]; d[0] = d[8] = s; d += 64; + s = buf[23] + tmp; d[0] = d[8] = s; d += 64; + s = buf[15]; d[0] = d[8] = s; d += 64; + s = tmp; d[0] = d[8] = s; + + /* samples 16 to 1 (sample 16 used again) */ + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : m_VBUF_LENGTH); + + s = buf[ 1]; d[0] = d[8] = s; d += 64; + + tmp = buf[30] + buf[25]; + s = buf[17] + tmp; d[0] = d[8] = s; d += 64; + s = buf[14] + buf[ 9]; d[0] = d[8] = s; d += 64; + s = buf[22] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 6]; d[0] = d[8] = s; d += 64; + + tmp = buf[26] + buf[30]; + s = buf[22] + tmp; d[0] = d[8] = s; d += 64; + s = buf[10] + buf[14]; d[0] = d[8] = s; d += 64; + s = buf[18] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 2]; d[0] = d[8] = s; d += 64; + + tmp = buf[28] + buf[26]; + s = buf[18] + tmp; d[0] = d[8] = s; d += 64; + s = buf[12] + buf[10]; d[0] = d[8] = s; d += 64; + s = buf[20] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 4]; d[0] = d[8] = s; d += 64; + + tmp = buf[24] + buf[28]; + s = buf[20] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 8] + buf[12]; d[0] = d[8] = s; d += 64; + s = buf[16] + tmp; d[0] = d[8] = s; + + /* this is so rarely invoked that it's not worth making two versions of the output + * shuffle code (one for no shift, one for clip + variable shift) like in IMDCT + * here we just load, clip, shift, and store on the rare instances that es != 0 + */ + if (es) { + d = dest + 64*16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : m_VBUF_LENGTH); + s = d[0]; CLIP_2N(s, (31 - es)); d[0] = d[8] = (s << es); + + d = dest + offset + (oddBlock ? m_VBUF_LENGTH : 0); + for (i = 16; i <= 31; i++) { + s = d[0]; CLIP_2N(s, (31 - es)); d[0] = d[8] = (s << es); d += 64; + } + + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : m_VBUF_LENGTH); + for (i = 15; i >= 0; i--) { + s = d[0]; CLIP_2N(s, (31 - es)); d[0] = d[8] = (s << es); d += 64; + } + } +} + +/*********************************************************************************************************************** + * P O L Y P H A S E + **********************************************************************************************************************/ +inline +short ClipToShort(int32_t x, int32_t fracBits){ + + /* assumes you've already rounded (x += (1 << (fracBits-1))) */ + x >>= fracBits; + +#ifndef __XTENSA__ + /* Ken's trick: clips to [-32768, 32767] */ + //ok vor generic case (fb) + int32_t sign = x >> 31; + if (sign != (x >> 15)) + x = sign ^ ((1 << 15) - 1); + + return (short)x; +#else + //this is better on xtensa (fb) + asm ("clamps %0, %1, 15" : "=a" (x) : "a" (x) : ); + return x; +#endif +} +/*********************************************************************************************************************** + * Function: PolyphaseMono + * + * Description: filter one subband and produce 32 output PCM samples for one channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of one channel of decoded PCM data, (i.e. Q16.0) + * + * Return: none + **********************************************************************************************************************/ +void PolyphaseMono(int16_t *pcm, int32_t *vbuf, const uint32_t *coefBase){ + int32_t i; + const uint32_t *coef; + int32_t *vb1; + int32_t vLo, vHi, c1, c2; + uint64_t sum1L, sum2L, rndVal; + + rndVal = (uint64_t)( 1ULL << ((m_DQ_FRACBITS_OUT - 2 - 2 - 15) - 1 + (32 - m_CSHIFT)) ); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = rndVal; + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; c2=*coef; coef++; vLo=*(vb1+(j)); vHi=*(vb1+(23-(j))); // 0...7 + sum1L=MADD64(sum1L, vLo, c1); sum1L=MADD64(sum1L, vHi, -c2); + } + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64*16; + sum1L = rndVal; + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; vLo=*(vb1+(j)); sum1L = MADD64(sum1L, vLo, c1); // 0...7 + } + *(pcm + 16) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm++; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; c2=*coef; coef++; vLo=*(vb1+(j)); vHi = *(vb1+(23-(j))); + sum1L=MADD64(sum1L, vLo, c1); sum2L = MADD64(sum2L, vLo, c2); + sum1L=MADD64(sum1L, vHi, -c2); sum2L = MADD64(sum2L, vHi, c1); + } + vb1 += 64; + *(pcm) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2*i) = ClipToShort((int32_t)SAR64(sum2L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + pcm++; + } +} +/*********************************************************************************************************************** + * Function: PolyphaseStereo + * + * Description: filter one subband and produce 32 output PCM samples for each channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of two channels of decoded PCM data, (i.e. Q16.0) + * + * Return: none + * + * Notes: interleaves PCM samples LRLRLR... + **********************************************************************************************************************/ +void PolyphaseStereo(int16_t *pcm, int32_t *vbuf, const uint32_t *coefBase){ + int32_t i; + const uint32_t *coef; + int32_t *vb1; + int32_t vLo, vHi, c1, c2; + uint64_t sum1L, sum2L, sum1R, sum2R, rndVal; + + rndVal = (uint64_t)( 1 << ((m_DQ_FRACBITS_OUT - 2 - 2 - 15) - 1 + (32 - m_CSHIFT)) ); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = sum1R = rndVal; + + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; c2=*coef; coef++; vLo=*(vb1+(j)); vHi = *(vb1+(23-(j))); + sum1L=MADD64(sum1L, vLo, c1); sum1L=MADD64(sum1L, vHi, -c2); + vLo=*(vb1+32+(j)); vHi=*(vb1+32+(23-(j))); + sum1R=MADD64(sum1R, vLo, c1); sum1R=MADD64(sum1R, vHi, -c2); \ + } + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 1) = ClipToShort((int32_t)SAR64(sum1R, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64*16; + sum1L = sum1R = rndVal; + + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; vLo = *(vb1+(j)); sum1L = MADD64(sum1L, vLo, c1); + vLo = *(vb1+32+(j)); sum1R = MADD64(sum1R, vLo, c1); + } + *(pcm + 2*16 + 0) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2*16 + 1) = ClipToShort((int32_t)SAR64(sum1R, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm += 2; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + sum1R = sum2R = rndVal; + + for(int32_t j=0; j<8; j++){ + c1=*coef; coef++; c2=*coef; coef++; vLo=*(vb1+(j)); vHi = *(vb1+(23-(j))); + sum1L=MADD64(sum1L, vLo, c1); sum2L=MADD64(sum2L, vLo, c2); + sum1L=MADD64(sum1L, vHi, -c2); sum2L=MADD64(sum2L, vHi, c1); + vLo=*(vb1+32+(j)); vHi=*(vb1+32+(23-(j))); + sum1R=MADD64(sum1R, vLo, c1); sum2R=MADD64(sum2R, vLo, c2); + sum1R=MADD64(sum1R, vHi, -c2); sum2R=MADD64(sum2R, vHi, c1); + } + vb1 += 64; + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 1) = ClipToShort((int32_t)SAR64(sum1R, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2*2*i + 0) = ClipToShort((int32_t)SAR64(sum2L, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2*2*i + 1) = ClipToShort((int32_t)SAR64(sum2R, (32-m_CSHIFT)), m_DQ_FRACBITS_OUT - 2 - 2 - 15); + pcm += 2; + } +} + +/*********************************************************************************************************************** + * Function: AnalyzeFrame + * + * Description: filter one subband and produce 32 output PCM samples for each channel + * + * Inputs: pointer to inpit buffer and length + * + * Outputs: MPEG_VERSION + * LAYER + * CHANNEL_MODE + * + * Return: main_data_begin + * + **********************************************************************************************************************/ +int MP3_AnalyzeFrame(const uint8_t *frame_data, size_t frame_len) { + if (frame_len < 4) { + log_e("Error: Frame data too short for header (need 4 bytes, got %zu).\n", frame_len); + return -3; // Frame too short for header + } + + // Define constants for better readability + const uint8_t MPEG_VERSION_2_5 = 0; // 00 - unofficial, but often so coded + const uint8_t MPEG_VERSION_RESERVED = 1; // 01 + const uint8_t MPEG_VERSION_2 = 2; // 10 + const uint8_t MPEG_VERSION_1 = 3; // 11 + + const uint8_t LAYER_RESERVED = 0; // 00 + const uint8_t LAYER_III = 1; // 01 + const uint8_t LAYER_II = 2; // 10 + const uint8_t LAYER_I = 3; // 11 + + const uint8_t CHANNEL_MODE_STEREO = 0; // 00 + const uint8_t CHANNEL_MODE_JOINT_STEREO = 1; // 01 + const uint8_t CHANNEL_MODE_DUAL_CHANNEL = 2; // 10 + const uint8_t CHANNEL_MODE_MONO = 3; // 11 + + (void)MPEG_VERSION_RESERVED; (void)LAYER_III; (void)LAYER_II; (void)LAYER_I; (void)CHANNEL_MODE_STEREO; + (void)CHANNEL_MODE_JOINT_STEREO; (void)CHANNEL_MODE_DUAL_CHANNEL; (void)LAYER_RESERVED; + + // ---- 1. Analyze frame header (first 4 bytes) --- + // combine the first 4 bytes into a 32-bit integer (Big Endian) + uint32_t header = ((uint32_t)frame_data[0] << 24) | + ((uint32_t)frame_data[1] << 16) | + ((uint32_t)frame_data[2] << 8) | + ((uint32_t)frame_data[3]); + + // check sync word (first 11 bits must be 1) + // MPEG 2.5 Layer III often uses 12 bits (0xfff), other 11 bits (0xffe) + // simple check: data [0] == 0xff and (data [1] & 0xe0) == 0xe0 + if (! (frame_data[0] == 0xFF && (frame_data[1] & 0xE0) == 0xE0) ) { + log_e("Error: Invalid MP3 sync word.\n"); + return -4; + } + + // MPEG version ID (Bits 11-12 of the header, or Bits 19-20 from right in the Uint32_t) + // Header: SSSS SSSS SSSV Vllp PBBB BFFM MCCE (S = Sync, V = version, L = layer, p = Protection ...) + // In our `Header` Uint32_t: + // Bit 31..21: Sync word (11 bits) + // Bit 20..19: MPEG Audio version ID + // Bit 18..17: Layer description + // Bit 16: Protection bit + // Bit 15..12: Bitrate index + // Bit 11..10: Sampling rate frequency index + // Bit 9: Padding bit + // Bit 8: Private bit + // Bit 7..6: Channel mode + // Bit 5..4: Mode extension (for Joint Stereo) + // Bit 3: Copyright + // Bit 2: Original + // Bit 1..0: Emphasis + + uint8_t mpeg_version_id = (header >> 19) & 0x03; + uint8_t layer_description = (header >> 17) & 0x03; + uint8_t protection_bit = (header >> 16) & 0x01; + uint8_t channel_mode = (header >> 6) & 0x03; + + // Debug output(optional) + // log_w("MPEG Version ID raw: %u\n", mpeg_version_id); + // log_w("Layer Description raw: %u\n", layer_description); + // log_w("Protection Bit: %u\n", protection_bit); + // log_w("Channel Mode raw: %u\n", channel_mode); + + + // --- 2. Check whether it is Layer III --- + if (layer_description != LAYER_III) { + //fprintf(stderr, "Info: Not an MPEG Layer III frame (Layer: %u).\n", layer_description); + return -1; // no Layer III + } + + // --- 3. Side Information, Determine offset and size --- + int side_info_offset = 4; // after the 4-Byte Header + if (protection_bit == 0) { // 0 means CRC is available + side_info_offset += 2; // Skip 16-bit CRC + } + + int side_info_size; (void)side_info_size; + // Derive MPEG versions from the ID (according to ISO/IEC 13818-3 Table B.1) + // ID '00' -> MPEG 2.5 + // ID '01' -> reserved + // ID '10' -> MPEG 2 + // ID '11' -> MPEG 1 + if (mpeg_version_id == MPEG_VERSION_1) { // MPEG-1 + if (channel_mode == CHANNEL_MODE_MONO) { + side_info_size = 17; // Mono + } else { + side_info_size = 32; // Stereo, Joint Stereo, Dual Channel + } + } else if (mpeg_version_id == MPEG_VERSION_2 || mpeg_version_id == MPEG_VERSION_2_5) { // MPEG-2 oder MPEG-2.5 + if (channel_mode == CHANNEL_MODE_MONO) { + side_info_size = 9; // Mono + } else { + side_info_size = 17; // Stereo, Joint Stereo, Dual Channel + } + } else { + fprintf(stderr, "Error: Reserved or unknown MPEG version ID: %u.\n", mpeg_version_id); + return -2; //Unknown/reserved MPEG version + } + + // ensure that the frame is long enough for the side information + // We need at least 2 bytes of the side info for Main_data_begin + if (frame_len < (size_t)(side_info_offset + 2)) { + fprintf(stderr, "Error: Frame data too short for side information (need %d bytes, got %zu).\n", side_info_offset + 2, frame_len); + return -3; + } + // (optional) Check whether the entire Side Information is available + /* + if (frame_len < (size_t)(side_info_offset + side_info_size)) { + fprintf(stderr, "Warning: Frame data might be too short for full side information (expected %d, got %zu available after header/CRC).\n", side_info_size, frame_len - side_info_offset); + // Fortfahren, da main_data_begin am Anfang ist, aber es ist ein Hinweis + } + */ + + // --- 4. Main_data_begin extract from the Side Information --- + // Main_data_begin are the first 9 bits of the Side Information + // Side information begins with frame_data [side_info_offset] + const uint8_t *side_info_ptr = frame_data + side_info_offset; + + // The 9 bits consist of: + // - the complete 8 bits of the first bytes of the Side Information + // - the MSB (highest quality bit) of the second bytes of the Side Information + uint16_t main_data_begin_val = ((uint16_t)side_info_ptr[0] << 1) | (side_info_ptr[1] >> 7); + + return main_data_begin_val; +} + diff --git a/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.h_ b/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.h_ new file mode 100644 index 0000000..ebbe4a1 --- /dev/null +++ b/libraries/ESP32-audioI2S/additional_info/old/Helix MP3_decoder/mp3_decoder.h_ @@ -0,0 +1,606 @@ +// based om helix mp3 decoder +#pragma once + +#include "Arduino.h" +#include "../psram_unique_ptr.hpp" +#include "assert.h" + +extern __attribute__((weak)) void audio_info(const char*); + +static const uint8_t m_HUFF_PAIRTABS =32; +static const uint8_t m_BLOCK_SIZE =18; +static const uint8_t m_NBANDS =32; +static const uint8_t m_MAX_REORDER_SAMPS =(192-126)*3; // largest critical band for short blocks (see sfBandTable) +static const uint16_t m_VBUF_LENGTH =17*2* m_NBANDS; // for double-sized vbuf FIFO +static const uint8_t m_MAX_SCFBD =4; // max scalefactor bands per channel +static const uint16_t m_MAINBUF_SIZE =1940; +static const uint8_t m_MAX_NGRAN =2; // max granules +static const uint8_t m_MAX_NCHAN =2; // max channels +static const uint16_t m_MAX_NSAMP =576; // max samples per channel, per granule + +enum { + MP3_NONE = 0, + MP3_ERR = -1, + MP3_STOP = -100, +}; + +typedef struct MP3FrameInfo { + int32_t bitrate; + int32_t nChans; + int32_t samprate; + int32_t bitsPerSample; + int32_t outputSamps; + int32_t layer; + int32_t version; +} MP3FrameInfo_t; + +typedef struct SFBandTable { + int32_t l[23]; + int32_t s[14]; +} SFBandTable_t; + +typedef struct BitStreamInfo { + uint8_t *bytePtr; + uint32_t iCache; + int32_t cachedBits; + int32_t nBytes; +} BitStreamInfo_t; + +typedef enum { /* map these to the corresponding 2-bit values in the frame header */ + Stereo = 0x00, /* two independent channels, but L and R frames might have different # of bits */ + Joint = 0x01, /* coupled channels - layer III: mix of M-S and intensity, Layers I/II: intensity and direct coding only */ + Dual = 0x02, /* two independent channels, L and R always have exactly 1/2 the total bitrate */ + Mono = 0x03 /* one channel */ +} StereoMode_t; + +typedef enum { /* map to 0,1,2 to make table indexing easier */ + MPEG1 = 0, + MPEG2 = 1, + MPEG25 = 2 +} MPEGVersion_t; + +typedef struct FrameHeader { + int32_t layer; /* layer index (1, 2, or 3) */ + int32_t crc; /* CRC flag: 0 = disabled, 1 = enabled */ + int32_t brIdx; /* bitrate index (0 - 15) */ + int32_t srIdx; /* sample rate index (0 - 2) */ + int32_t paddingBit; /* padding flag: 0 = no padding, 1 = single pad byte */ + int32_t privateBit; /* unused */ + int32_t modeExt; /* used to decipher joint stereo mode */ + int32_t copyFlag; /* copyright flag: 0 = no, 1 = yes */ + int32_t origFlag; /* original flag: 0 = copy, 1 = original */ + int32_t emphasis; /* deemphasis mode */ + int32_t CRCWord; /* CRC word (16 bits, 0 if crc not enabled) */ +} FrameHeader_t; + +typedef struct SideInfoSub { + int32_t part23Length; /* number of bits in main data */ + int32_t nBigvals; /* 2x this = first set of Huffman cw's (maximum amplitude can be > 1) */ + int32_t globalGain; /* overall gain for dequantizer */ + int32_t sfCompress; /* unpacked to figure out number of bits in scale factors */ + int32_t winSwitchFlag; /* window switching flag */ + int32_t blockType; /* block type */ + int32_t mixedBlock; /* 0 = regular block (all short or long), 1 = mixed block */ + int32_t tableSelect[3]; /* index of Huffman tables for the big values regions */ + int32_t subBlockGain[3]; /* subblock gain offset, relative to global gain */ + int32_t region0Count; /* 1+region0Count = num scale factor bands in first region of bigvals */ + int32_t region1Count; /* 1+region1Count = num scale factor bands in second region of bigvals */ + int32_t preFlag; /* for optional high frequency boost */ + int32_t sfactScale; /* scaling of the scalefactors */ + int32_t count1TableSelect; /* index of Huffman table for quad codewords */ +} SideInfoSub_t; + +typedef struct SideInfo { + int32_t mainDataBegin; + int32_t privateBits; + int32_t scfsi[m_MAX_NCHAN][m_MAX_SCFBD]; /* 4 scalefactor bands per channel */ +} SideInfo_t; + +typedef struct { + int32_t cbType; /* pure long = 0, pure short = 1, mixed = 2 */ + int32_t cbEndS[3]; /* number nonzero short cb's, per subbblock */ + int32_t cbEndSMax; /* max of cbEndS[] */ + int32_t cbEndL; /* number nonzero long cb's */ +} CriticalBandInfo_t; + +typedef struct DequantInfo { + int32_t workBuf[m_MAX_REORDER_SAMPS]; /* workbuf for reordering short blocks */ +} DequantInfo_t; + +typedef struct HuffmanInfo { + int32_t huffDecBuf[m_MAX_NCHAN][m_MAX_NSAMP]; /* used both for decoded Huffman values and dequantized coefficients */ + int32_t nonZeroBound[m_MAX_NCHAN]; /* number of coeffs in huffDecBuf[ch] which can be > 0 */ + int32_t gb[m_MAX_NCHAN]; /* minimum number of guard bits in huffDecBuf[ch] */ +} HuffmanInfo_t; + +typedef enum HuffTabType { + noBits, + oneShot, + loopNoLinbits, + loopLinbits, + quadA, + quadB, + invalidTab +} HuffTabType_t; + +typedef struct HuffTabLookup { + int32_t linBits; + int32_t tabType; /*HuffTabType*/ +} HuffTabLookup_t; + +typedef struct IMDCTInfo { + int32_t outBuf[m_MAX_NCHAN][m_BLOCK_SIZE][m_NBANDS]; /* output of IMDCT */ + int32_t overBuf[m_MAX_NCHAN][m_MAX_NSAMP / 2]; /* overlap-add buffer (by symmetry, only need 1/2 size) */ + int32_t numPrevIMDCT[m_MAX_NCHAN]; /* how many IMDCT's calculated in this channel on prev. granule */ + int32_t prevType[m_MAX_NCHAN]; + int32_t prevWinSwitch[m_MAX_NCHAN]; + int32_t gb[m_MAX_NCHAN]; +} IMDCTInfo_t; + +typedef struct BlockCount { + int32_t nBlocksLong; + int32_t nBlocksTotal; + int32_t nBlocksPrev; + int32_t prevType; + int32_t prevWinSwitch; + int32_t currWinSwitch; + int32_t gbIn; + int32_t gbOut; +} BlockCount_t; + +typedef struct ScaleFactorInfoSub { /* max bits in scalefactors = 5, so use char's to save space */ + char l[23]; /* [band] */ + char s[13][3]; /* [band][window] */ +} ScaleFactorInfoSub_t; + +typedef struct ScaleFactorJS { /* used in MPEG 2, 2.5 intensity (joint) stereo only */ + int32_t intensityScale; + int32_t slen[4]; + int32_t nr[4]; +} ScaleFactorJS_t; + +/* NOTE - could get by with smaller vbuf if memory is more important than speed + * (in Subband, instead of replicating each block in FDCT32 you would do a memmove on the + * last 15 blocks to shift them down one, a hardware style FIFO) + */ +typedef struct SubbandInfo { + int32_t vbuf[m_MAX_NCHAN * m_VBUF_LENGTH]; /* vbuf for fast DCT-based synthesis PQMF - double size for speed (no modulo indexing) */ + int32_t vindex; /* internal index for tracking position in vbuf */ +} SubbandInfo_t; + +typedef struct MP3DecInfo { + /* buffer which must be large enough to hold largest possible main_data section */ + uint8_t mainBuf[m_MAINBUF_SIZE]; + /* special info for "free" bitrate files */ + int32_t freeBitrateFlag; + int32_t freeBitrateSlots; + /* user-accessible info */ + int32_t bitrate; + int32_t nChans; + int32_t samprate; + int32_t nGrans; /* granules per frame */ + int32_t nGranSamps; /* samples per granule */ + int32_t nSlots; + int32_t layer; + + int32_t mainDataBegin; + int32_t mainDataBytes; + int32_t part23Length[m_MAX_NGRAN][m_MAX_NCHAN]; +} MP3DecInfo_t; + +const uint16_t mpeg1_layer3_bitrates[16] = { // Bitraten-Lookup tables (example for MPEG1 Layer III) + 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 // Attention: These tables must be complete and correct! +}; // Index 0 is invalid, index 15 is invalid. + +// SamplingFrequenz-Lookup tables(Beispiel für MPEG1, MPEG2, MPEG2.5) +const uint16_t sampling_rates[3][4] = { + {44100, 48000, 32000, 0}, // MPEG1 + {22050, 24000, 16000, 0}, // MPEG2 + {11025, 12000, 8000, 0} // MPEG2.5 +}; + +typedef struct { + uint8_t mpeg_version; // 0=MPEG2.5, 1=reserved, 2=MPEG2, 3=MPEG1 + uint8_t layer; // 0=reserved, 1=Layer III, 2=Layer II, 3=Layer I + bool crc_protected; + uint8_t bitrate_idx; + uint8_t sample_rate_idx; + bool padding; + uint8_t channel_mode; + uint32_t frame_length; // In Bytes +} Mp3FrameHeader; + + +/* format = Q31 + * #define M_PI 3.14159265358979323846 + * double u = 2.0 * M_PI / 9.0; + * float c0 = sqrt(3.0) / 2.0; + * float c1 = cos(u); + * float c2 = cos(2*u); + * float c3 = sin(u); + * float c4 = sin(2*u); + */ + +const int32_t c9_0 = 0x6ed9eba1; +const int32_t c9_1 = 0x620dbe8b; +const int32_t c9_2 = 0x163a1a7e; +const int32_t c9_3 = 0x5246dd49; +const int32_t c9_4 = 0x7e0e2e32; + + + +const int32_t c3_0 = 0x6ed9eba1; /* format = Q31, cos(pi/6) */ +const int32_t c6[3] = { 0x7ba3751d, 0x5a82799a, 0x2120fb83 }; /* format = Q31, cos(((0:2) + 0.5) * (pi/6)) */ + +/* format = Q31 + * cos(((0:8) + 0.5) * (pi/18)) + */ +const uint32_t c18[9] = { 0x7f834ed0, 0x7ba3751d, 0x7401e4c1, 0x68d9f964, 0x5a82799a, 0x496af3e2, 0x36185aee, 0x2120fb83, 0x0b27eb5c}; + +/* scale factor lengths (num bits) */ +const char m_SFLenTab[16][2] = { {0, 0}, {0, 1}, {0, 2}, {0, 3}, {3, 0}, {1, 1}, {1, 2}, {1, 3}, + {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}, {4, 2}, {4, 3}}; + +/* NRTab[size + 3*is_right][block type][partition] + * block type index: 0 = (bt0,bt1,bt3), 1 = bt2 non-mixed, 2 = bt2 mixed + * partition: scale factor groups (sfb1 through sfb4) + * for block type = 2 (mixed or non-mixed) / by 3 is rolled into this table + * (for 3 short blocks per long block) + * see 2.4.3.2 in MPEG 2 (low sample rate) spec + * stuff rolled into this table: + * NRTab[x][1][y] --> (NRTab[x][1][y]) / 3 + * NRTab[x][2][>=1] --> (NRTab[x][2][>=1]) / 3 (first partition is long block) + */ +const char NRTab[6][3][4] = { + {{ 6, 5, 5, 5}, {3, 3, 3, 3}, {6, 3, 3, 3}}, + {{ 6, 5, 7, 3}, {3, 3, 4, 2}, {6, 3, 4, 2}}, + {{11, 10, 0, 0}, {6, 6, 0, 0}, {6, 3, 6, 0}}, + {{ 7, 7, 7, 0}, {4, 4, 4, 0}, {6, 5, 4, 0}}, + {{ 6, 6, 6, 3}, {4, 3, 3, 2}, {6, 4, 3, 2}}, + {{ 8, 8, 5, 0}, {5, 4, 3, 0}, {6, 6, 3, 0}} +}; + + + +/* optional pre-emphasis for high-frequency scale factor bands */ +const char preTab[22] = { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0 }; + +/* pow(2,-i/4) for i=0..3, Q31 format */ +const int32_t pow14[4] PROGMEM = { + 0x7fffffff, 0x6ba27e65, 0x5a82799a, 0x4c1bf829 +}; + + +/* + * Minimax polynomial approximation to pow(x, 4/3), over the range + * poly43lo: x = [0.5, 0.7071] + * poly43hi: x = [0.7071, 1.0] + * + * Relative error < 1E-7 + * Coefs are scaled by 4, 2, 1, 0.5, 0.25 + */ +const uint32_t poly43lo[5] PROGMEM = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 }; +const uint32_t poly43hi[5] PROGMEM = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 }; + +/* pow(2, i*4/3) as exp and frac */ +const int32_t pow2exp[8] PROGMEM = { 14, 13, 11, 10, 9, 7, 6, 5 }; + +const int32_t pow2frac[8] PROGMEM = { + 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, + 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6 +}; + +const uint16_t m_HUFF_OFFSET_01= 0; +const uint16_t m_HUFF_OFFSET_02= 9 + m_HUFF_OFFSET_01; +const uint16_t m_HUFF_OFFSET_03= 65 + m_HUFF_OFFSET_02; +const uint16_t m_HUFF_OFFSET_05= 65 + m_HUFF_OFFSET_03; +const uint16_t m_HUFF_OFFSET_06=257 + m_HUFF_OFFSET_05; +const uint16_t m_HUFF_OFFSET_07=129 + m_HUFF_OFFSET_06; +const uint16_t m_HUFF_OFFSET_08=110 + m_HUFF_OFFSET_07; +const uint16_t m_HUFF_OFFSET_09=280 + m_HUFF_OFFSET_08; +const uint16_t m_HUFF_OFFSET_10= 93 + m_HUFF_OFFSET_09; +const uint16_t m_HUFF_OFFSET_11=320 + m_HUFF_OFFSET_10; +const uint16_t m_HUFF_OFFSET_12=296 + m_HUFF_OFFSET_11; +const uint16_t m_HUFF_OFFSET_13=185 + m_HUFF_OFFSET_12; +const uint16_t m_HUFF_OFFSET_15=497 + m_HUFF_OFFSET_13; +const uint16_t m_HUFF_OFFSET_16=580 + m_HUFF_OFFSET_15; +const uint16_t m_HUFF_OFFSET_24=651 + m_HUFF_OFFSET_16; + +const int32_t huffTabOffset[m_HUFF_PAIRTABS] PROGMEM = { + 0, m_HUFF_OFFSET_01, m_HUFF_OFFSET_02, m_HUFF_OFFSET_03, + 0, m_HUFF_OFFSET_05, m_HUFF_OFFSET_06, m_HUFF_OFFSET_07, + m_HUFF_OFFSET_08, m_HUFF_OFFSET_09, m_HUFF_OFFSET_10, m_HUFF_OFFSET_11, + m_HUFF_OFFSET_12, m_HUFF_OFFSET_13, 0, m_HUFF_OFFSET_15, + m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, + m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, + m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, + m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24,}; + +const HuffTabLookup_t huffTabLookup[m_HUFF_PAIRTABS] PROGMEM = { + { 0, noBits }, + { 0, oneShot }, + { 0, oneShot }, + { 0, oneShot }, + { 0, invalidTab }, + { 0, oneShot }, + { 0, oneShot }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, invalidTab }, + { 0, loopNoLinbits }, + { 1, loopLinbits }, + { 2, loopLinbits }, + { 3, loopLinbits }, + { 4, loopLinbits }, + { 6, loopLinbits }, + { 8, loopLinbits }, + { 10, loopLinbits }, + { 13, loopLinbits }, + { 4, loopLinbits }, + { 5, loopLinbits }, + { 6, loopLinbits }, + { 7, loopLinbits }, + { 8, loopLinbits }, + { 9, loopLinbits }, + { 11, loopLinbits }, + { 13, loopLinbits }, +}; + + +const int32_t quadTabOffset[2] PROGMEM = {0, 64}; +const int32_t quadTabMaxBits[2] PROGMEM = {6, 4}; + +/* indexing = [version][samplerate index] + * sample rate of frame (Hz) + */ +const int32_t samplerateTab[3][3] PROGMEM = { + { 44100, 48000, 32000 }, /* MPEG-1 */ + { 22050, 24000, 16000 }, /* MPEG-2 */ + { 11025, 12000, 8000 }, /* MPEG-2.5 */ +}; + + + +/* indexing = [version][layer] + * number of samples in one frame (per channel) + */ +const uint16_t samplesPerFrameTab[3][3] PROGMEM = { { 384, 1152, 1152 }, /* MPEG1 */ +{ 384, 1152, 576 }, /* MPEG2 */ +{ 384, 1152, 576 }, /* MPEG2.5 */ +}; + +/* layers 1, 2, 3 */ +const uint8_t bitsPerSlotTab[3] = { 32, 8, 8 }; + +/* indexing = [version][mono/stereo] + * number of bytes in side info section of bitstream + */ +const uint8_t sideBytesTab[3][2] PROGMEM = { { 17, 32 }, /* MPEG-1: mono, stereo */ +{ 9, 17 }, /* MPEG-2: mono, stereo */ +{ 9, 17 }, /* MPEG-2.5: mono, stereo */ +}; + +/* indexing = [version][sampleRate][long (.l) or short (.s) block] + * sfBandTable[v][s].l[cb] = index of first bin in critical band cb (long blocks) + * sfBandTable[v][s].s[cb] = index of first bin in critical band cb (short blocks) + */ +const SFBandTable_t sfBandTable[3][3] PROGMEM = { + { /* MPEG-1 (44, 48, 32 kHz) */ + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 }, + {0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192} }, + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 }, + {0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192} }, + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 }, + {0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192} } }, + { /* MPEG-2 (22, 24, 16 kHz) */ + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192} }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, 540, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192} }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192} }, }, + { /* MPEG-2.5 (11, 12, 8 kHz) */ + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } }, + { {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 }, + {0, 8, 16, 24, 36, 52, 72, 96, 124, 160, 162, 164, 166, 192 } }, }, +}; + + +/* indexing = [intensity scale on/off][left/right] + * format = Q30, range = [0.0, 1.414] + * + * illegal intensity position scalefactors (see comments on ISFMpeg1) + */ +const int32_t ISFIIP[2][2] PROGMEM = { + {0x40000000, 0x00000000}, /* mid-side off */ + {0x40000000, 0x40000000}, /* mid-side on */ +}; + +const uint8_t uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f}; + +/* anti-alias coefficients - see spec Annex B, table 3-B.9 + * csa[0][i] = CSi, csa[1][i] = CAi + * format = Q31 + */ +const uint32_t csa[8][2] PROGMEM = { + {0x6dc253f0, 0xbe2500aa}, + {0x70dcebe4, 0xc39e4949}, + {0x798d6e73, 0xd7e33f4a}, + {0x7ddd40a7, 0xe8b71176}, + {0x7f6d20b7, 0xf3e4fe2f}, + {0x7fe47e40, 0xfac1a3c7}, + {0x7ffcb263, 0xfe2ebdc6}, + {0x7fffc694, 0xff86c25d}, +}; + +/* format = Q30, right shifted by 12 (sign bits only in top 12 - undo this when rounding to short) + * this is to enable early-terminating multiplies on ARM + * range = [-1.144287109, 1.144989014] + * max gain of filter (per output sample) ~= 2.731 + * + * new (properly sign-flipped) values + * - these actually are correct to 32 bits, (floating-pt coefficients in spec + * chosen such that only ~20 bits are required) + * + * Reordering - see table 3-B.3 in spec (appendix B) + * + * polyCoef[i] = + * D[ 0, 32, 64, ... 480], i = [ 0, 15] + * D[ 1, 33, 65, ... 481], i = [ 16, 31] + * D[ 2, 34, 66, ... 482], i = [ 32, 47] + * ... + * D[15, 47, 79, ... 495], i = [240,255] + * + * also exploits symmetry: D[i] = -D[512 - i], for i = [1, 255] + * + * polyCoef[256, 257, ... 263] are for special case of sample 16 (out of 0) + * see PolyphaseStereo() and PolyphaseMono() + */ + +static const char* mpeg_version_table[] = { + "MPEG-2.5", // 0 + "reserved", // 1 + "MPEG-2", // 2 + "MPEG-1" // 3 +}; + +static const char* layer_table[] = { + "Unknown", // 0 + "Layer I", // 1 + "Layer II", // 2 + "Layer III" // 3 +}; + +// prototypes +bool MP3Decoder_AllocateBuffers(void); +bool MP3Decoder_IsInit(); +void MP3Decoder_FreeBuffers(); +int32_t MP3Decode( uint8_t *inbuf, int32_t *bytesLeft, int16_t *outbuf); +void MP3GetLastFrameInfo(); +int32_t MP3GetNextFrameInfo(uint8_t *buf); +int32_t MP3FindSyncWord(uint8_t *buf, int32_t nBytes); +int32_t MP3GetSampRate(); +int32_t MP3GetChannels(); +int32_t MP3GetBitsPerSample(); +int32_t MP3GetBitrate(); +int32_t MP3GetOutputSamps(); +const char* MP3GetLayer(); +const char* MP3GetMPEGVersion(); + +//internally used +int MP3_AnalyzeFrame(const uint8_t *frame_data, size_t frame_len); +void MP3Decoder_ClearBuffer(void); +void PolyphaseMono(int16_t *pcm, int32_t *vbuf, const uint32_t* coefBase); +void PolyphaseStereo(int16_t *pcm, int32_t *vbuf, const uint32_t* coefBase); +void SetBitstreamPointer(BitStreamInfo_t *bsi, int32_t nBytes, uint8_t *buf); +uint32_t GetBits(BitStreamInfo_t *bsi, int32_t nBits); +int32_t CalcBitsUsed(BitStreamInfo_t *bsi, uint8_t *startBuf, int32_t startOffset); +int32_t DequantChannel(int32_t *sampleBuf, int32_t *workBuf, int32_t *nonZeroBound, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi); +void MidSideProc(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, int32_t mOut[2]); +void IntensityProcMPEG1(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]); +void IntensityProcMPEG2(int32_t x[m_MAX_NCHAN][m_MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t *sfis, CriticalBandInfo_t *cbi, ScaleFactorJS_t *sfjs, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]); +void FDCT32(int32_t *x, int32_t *d, int32_t offset, int32_t oddBlock, int32_t gb);// __attribute__ ((section (".data"))); +int32_t CheckPadBit(); +int32_t UnpackFrameHeader(uint8_t *buf); +int32_t UnpackSideInfo(uint8_t *buf); +int32_t DecodeHuffman( uint8_t *buf, int32_t *bitOffset, int32_t huffBlockBits, int32_t gr, int32_t ch); +int32_t MP3Dequantize( int32_t gr); +int32_t IMDCT( int32_t gr, int32_t ch); +int32_t UnpackScaleFactors( uint8_t *buf, int32_t *bitOffset, int32_t bitsAvail, int32_t gr, int32_t ch); +int32_t Subband(int16_t *pcmBuf); +int16_t ClipToShort(int32_t x, int32_t fracBits); +void RefillBitstreamCache(BitStreamInfo_t *bsi); +void UnpackSFMPEG1(BitStreamInfo_t *bsi, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, int32_t *scfsi, int32_t gr, ScaleFactorInfoSub_t *sfisGr0); +void UnpackSFMPEG2(BitStreamInfo_t *bsi, SideInfoSub_t *sis, ScaleFactorInfoSub_t *sfis, int32_t gr, int32_t ch, int32_t modeExt, ScaleFactorJS_t *sfjs); +int32_t MP3FindFreeSync(uint8_t *buf, uint8_t firstFH[4], int32_t nBytes); +void MP3ClearBadFrame( int16_t *outbuf); +int32_t DecodeHuffmanPairs(int32_t *xy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t *buf, int32_t bitOffset); +int32_t DecodeHuffmanQuads(int32_t *vwxy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t *buf, int32_t bitOffset); +int32_t DequantBlock(int32_t *inbuf, int32_t *outbuf, int32_t num, int32_t scale); +void AntiAlias(int32_t *x, int32_t nBfly); +void WinPrevious(int32_t *xPrev, int32_t *xPrevWin, int32_t btPrev); +int32_t FreqInvertRescale(int32_t *y, int32_t *xPrev, int32_t blockIdx, int32_t es); +void idct9(int32_t *x); +int32_t IMDCT36(int32_t *xCurr, int32_t *xPrev, int32_t *y, int32_t btCurr, int32_t btPrev, int32_t blockIdx, int32_t gb); +void imdct12(int32_t *x, int32_t *out); +int32_t IMDCT12x3(int32_t *xCurr, int32_t *xPrev, int32_t *y, int32_t btPrev, int32_t blockIdx, int32_t gb); +int32_t HybridTransform(int32_t *xCurr, int32_t *xPrev, int32_t y[m_BLOCK_SIZE][m_NBANDS], SideInfoSub_t *sis, BlockCount_t *bc); +inline uint64_t SAR64(uint64_t x, int32_t n) {return x >> n;} +inline int32_t MULSHIFT32(int32_t x, int32_t y) { int32_t z; z = (uint64_t) x * (uint64_t) y >> 32; return z;} +inline uint64_t MADD64(uint64_t sum64, int32_t x, int32_t y) {sum64 += (uint64_t) x * (uint64_t) y; return sum64;}/* returns 64-bit value in [edx:eax] */ +inline uint64_t xSAR64(uint64_t x, int32_t n){return x >> n;} +inline int32_t FASTABS(int32_t x){ return __builtin_abs(x);} //xtensa has a fast abs instruction //fb +#define CLZ(x) __builtin_clz(x) //fb + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 L O G G I N G 📌📌📌 + +template +void MP3_ERROR_IMPL(uint8_t level, const char* path, int line, const char* fmt, Args&&... args) { + extern __attribute__((weak)) void audio_info(const char*); + #define ANSI_ESC_RESET "\033[0m" + #define ANSI_ESC_BLACK "\033[30m" + #define ANSI_ESC_RED "\033[31m" + #define ANSI_ESC_GREEN "\033[32m" + #define ANSI_ESC_YELLOW "\033[33m" + #define ANSI_ESC_BLUE "\033[34m" + #define ANSI_ESC_MAGENTA "\033[35m" + #define ANSI_ESC_CYAN "\033[36m" + #define ANSI_ESC_WHITE "\033[37m" + + ps_ptr result; + ps_ptr file; + + file.copy_from(path); + while(file.contains("/")){ + file.remove_before('/', false); + } + + // First run: determine size + int len = std::snprintf(nullptr, 0, fmt, std::forward(args)...); + if (len <= 0) return; + + result.alloc(len + 1, "result"); + char* dst = result.get(); + if (!dst) return; + std::snprintf(dst, len + 1, fmt, std::forward(args)...); + + // build a final string with file/line prefix + ps_ptr final; + int total_len = std::snprintf(nullptr, 0, "%s:%d:" ANSI_ESC_RED " %s" ANSI_ESC_RESET, file.c_get(), line, dst); + if (total_len <= 0) return; + final.alloc(total_len + 1, "final"); + char* dest = final.get(); + if (!dest) return; // Or error treatment + if(audio_info){ + if (level == 1) snprintf(dest, total_len + 1, "%s:%d:" ANSI_ESC_RED " %s" ANSI_ESC_RESET, file.c_get(), line, dst); + else if(level == 2) snprintf(dest, total_len + 1, "%s:%d:" ANSI_ESC_YELLOW " %s" ANSI_ESC_RESET, file.c_get(), line, dst); + else if(level == 3) snprintf(dest, total_len + 1, "%s:%d:" ANSI_ESC_GREEN " %s" ANSI_ESC_RESET, file.c_get(), line, dst); + else snprintf(dest, total_len + 1, "%s:%d:" ANSI_ESC_BLUE " %s" ANSI_ESC_RESET, file.c_get(), line, dst); + audio_info(final.get()); + } + else{ + std::snprintf(dest, total_len + 1, "%s:%d: %s", file.c_get(), line, dst); + if (level == 1) log_e("%s", final.c_get()); + else if(level == 2) log_w("%s", final.c_get()); + else if(level == 3) log_i("%s", final.c_get()); + else log_d("%s", final.c_get()); + } + final.reset(); + result.reset(); +} + +// Macro for comfortable calls +#define MP3_ERROR(fmt, ...) MP3_ERROR_IMPL(1, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define MP3_WARN(fmt, ...) MP3_ERROR_IMPL(2, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define MP3_INFO(fmt, ...) MP3_ERROR_IMPL(3, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + diff --git a/libraries/ESP32-audioI2S/examples/AC101/AC101.cpp b/libraries/ESP32-audioI2S/examples/AC101/AC101.cpp new file mode 100644 index 0000000..cf80aff --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/AC101/AC101.cpp @@ -0,0 +1,352 @@ +/* + AC101 - An AC101 Codec driver library for Arduino + Copyright (C) 2019, Ivo Pullens, Emmission + + Inspired by: + https://github.com/donny681/esp-adf/tree/master/components/audio_hal/driver/AC101 + + 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 3 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, see . + + Febr 2021 modified by schreibfaul1 - set correct pll values + March 2021 modified by schreibfaul1 - can handle two i2c instances + May 2021 modified by schreibfaul1 - constructor changed + Oct 2021 modified by schreibfaul1 - I2C wrong ACK in ReadReg + Jan 2022 modified by schreibfaul1 - left right channel swapped + Jan 2022 modified by schreibfaul1 - suppress compiler warning: left shift of negative value + + examples: + + //one I2C bus: (default behaviour) + AC101 ac; + ac.begin(sda, scl); + + //two I2C busses: + TwoWire i2cBusOne = TwoWire(0); + TwoWire i2cBusTwo = TwoWire(1); + AC101 ac(&i2cBusOne); + + i2cBusOne.begin(sda, scl, 400000); +*/ + +#include "AC101.h" + +#define BCLK // clock over BCLK comment out: clock over MCLK + +#define AC101_ADDR 0x1A // Device address + +#define CHIP_AUDIO_RS 0x00 +#define PLL_CTRL1 0x01 +#define PLL_CTRL2 0x02 +#define SYSCLK_CTRL 0x03 +#define MOD_CLK_ENA 0x04 +#define MOD_RST_CTRL 0x05 +#define I2S_SR_CTRL 0x06 +#define I2S1LCK_CTRL 0x10 +#define I2S1_SDOUT_CTRL 0x11 +#define I2S1_SDIN_CTRL 0x12 +#define I2S1_MXR_SRC 0x13 +#define I2S1_VOL_CTRL1 0x14 +#define I2S1_VOL_CTRL2 0x15 +#define I2S1_VOL_CTRL3 0x16 +#define I2S1_VOL_CTRL4 0x17 +#define I2S1_MXR_GAIN 0x18 +#define ADC_DIG_CTRL 0x40 +#define ADC_VOL_CTRL 0x41 +#define HMIC_CTRL1 0x44 +#define HMIC_CTRL2 0x45 +#define HMIC_STATUS 0x46 +#define DAC_DIG_CTRL 0x48 +#define DAC_VOL_CTRL 0x49 +#define DAC_MXR_SRC 0x4C +#define DAC_MXR_GAIN 0x4D +#define ADC_APC_CTRL 0x50 +#define ADC_SRC 0x51 +#define ADC_SRCBST_CTRL 0x52 +#define OMIXER_DACA_CTRL 0x53 +#define OMIXER_SR 0x54 +#define OMIXER_BST1_CTRL 0x55 +#define HPOUT_CTRL 0x56 +#define SPKOUT_CTRL 0x58 +#define AC_DAC_DAPCTRL 0xA0 +#define AC_DAC_DAPHHPFC 0xA1 +#define AC_DAC_DAPLHPFC 0xA2 +#define AC_DAC_DAPLHAVC 0xA3 +#define AC_DAC_DAPLLAVC 0xA4 +#define AC_DAC_DAPRHAVC 0xA5 +#define AC_DAC_DAPRLAVC 0xA6 +#define AC_DAC_DAPHGDEC 0xA7 +#define AC_DAC_DAPLGDEC 0xA8 +#define AC_DAC_DAPHGATC 0xA9 +#define AC_DAC_DAPLGATC 0xAA +#define AC_DAC_DAPHETHD 0xAB +#define AC_DAC_DAPLETHD 0xAC +#define AC_DAC_DAPHGKPA 0xAD +#define AC_DAC_DAPLGKPA 0xAE +#define AC_DAC_DAPHGOPA 0xAF +#define AC_DAC_DAPLGOPA 0xB0 +#define AC_DAC_DAPOPT 0xB1 +#define DAC_DAP_ENA 0xB5 + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +const uint8_t regs[] = { + CHIP_AUDIO_RS , + PLL_CTRL1 , + PLL_CTRL2 , + SYSCLK_CTRL , + MOD_CLK_ENA , + MOD_RST_CTRL , + I2S_SR_CTRL , + I2S1LCK_CTRL , + I2S1_SDOUT_CTRL , + I2S1_SDIN_CTRL , + I2S1_MXR_SRC , + I2S1_VOL_CTRL1 , + I2S1_VOL_CTRL2 , + I2S1_VOL_CTRL3 , + I2S1_VOL_CTRL4 , + I2S1_MXR_GAIN , + ADC_DIG_CTRL , + ADC_VOL_CTRL , + HMIC_CTRL1 , + HMIC_CTRL2 , + HMIC_STATUS , + DAC_DIG_CTRL , + DAC_VOL_CTRL , + DAC_MXR_SRC , + DAC_MXR_GAIN , + ADC_APC_CTRL , + ADC_SRC , + ADC_SRCBST_CTRL , + OMIXER_DACA_CTRL , + OMIXER_SR , + OMIXER_BST1_CTRL , + HPOUT_CTRL , + SPKOUT_CTRL , + AC_DAC_DAPCTRL , + AC_DAC_DAPHHPFC , + AC_DAC_DAPLHPFC , + AC_DAC_DAPLHAVC , + AC_DAC_DAPLLAVC , + AC_DAC_DAPRHAVC , + AC_DAC_DAPRLAVC , + AC_DAC_DAPHGDEC , + AC_DAC_DAPLGDEC , + AC_DAC_DAPHGATC , + AC_DAC_DAPLGATC , + AC_DAC_DAPHETHD , + AC_DAC_DAPLETHD , + AC_DAC_DAPHGKPA , + AC_DAC_DAPLGKPA , + AC_DAC_DAPHGOPA , + AC_DAC_DAPLGOPA , + AC_DAC_DAPOPT , + DAC_DAP_ENA +}; +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::WriteReg(uint8_t reg, uint16_t val) +{ + _TwoWireInstance->beginTransmission(AC101_ADDR); + _TwoWireInstance->write(reg); + _TwoWireInstance->write(uint8_t((val >> 8) & 0xff)); + _TwoWireInstance->write(uint8_t(val & 0xff)); + return 0 == _TwoWireInstance->endTransmission(true); +} + +uint16_t AC101::ReadReg(uint8_t reg) +{ + _TwoWireInstance->beginTransmission(AC101_ADDR); + _TwoWireInstance->write(reg); + _TwoWireInstance->endTransmission(false); + + uint16_t val = 0u; + if (2 == _TwoWireInstance->requestFrom(uint16_t(AC101_ADDR), uint8_t(2))) + { + val = uint16_t(_TwoWireInstance->read() << 8) + uint16_t(_TwoWireInstance->read()); + } + _TwoWireInstance->endTransmission(true); + return val; +} +//---------------------------------------------------------------------------------------------------------------------- +AC101::AC101( TwoWire *TwoWireInstance ){ + _TwoWireInstance = TwoWireInstance; +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::begin(int32_t sda, int32_t scl, uint32_t frequency) { + bool ok; + if((sda >= 0) && (scl >= 0)){ + ok = _TwoWireInstance->begin(sda, scl, frequency); + } + else { + ok = true; + } + + // Reset all registers, readback default as sanity check + ok &= WriteReg(CHIP_AUDIO_RS, 0x123); + delay(100); + ok &= 0x0101 == ReadReg(CHIP_AUDIO_RS); + ok &= WriteReg(SPKOUT_CTRL, 0xe880); + // Enable the PLL from 256*44.1KHz MCLK source + ok &= WriteReg(PLL_CTRL1, 0x0141); + uint16_t N = 48 << 4; /* 512 / (M * (2*K+1)) / (CHANNELS * WORD_SIZE) -> 512 / 3 * (2 * 16) */ + uint16_t PLL_EN = 1 << 15; + uint16_t N_f = 0<<0; /* 0.2 N */ + ok &= WriteReg(PLL_CTRL2, N | PLL_EN | N_f); + + // Clocking system + uint16_t PLLCLK_ENA = 1<<15; /* 0: Disable, 1: Enable */ +#ifdef BCLK + uint16_t PLL_CLK = 0x2 << 12; /* bclk1 */ + uint16_t I2S1CLK_SRC = 0x3<<8; /* PLL */ +#else + uint16_t PLL_CLK = 0x0 << 12; /* MCLK1 */ + uint16_t I2S1CLK_SRC = 0x0<<8; /* MLCK1 */ +#endif + uint16_t I2S1CLK_ENA = 1<<11; /* 0: Disable, 1: Enable */ + + uint16_t SYSCLK_ENA = 1<<3; + ok &= WriteReg(SYSCLK_CTRL, PLLCLK_ENA|PLL_CLK| I2S1CLK_ENA|I2S1CLK_SRC|SYSCLK_ENA/*0x8b08*/); + + ok &= WriteReg(MOD_CLK_ENA, 0x800c); + ok &= WriteReg(MOD_RST_CTRL, 0x800c); + + // Set default at I2S, 44.1KHz, 16bit + ok &= SetI2sSampleRate(SAMPLE_RATE_44100); + ok &= SetI2sClock(BCLK_DIV_8, false, LRCK_DIV_32, false); + ok &= SetI2sMode(MODE_SLAVE); + ok &= SetI2sWordSize(WORD_SIZE_16_BITS); + ok &= SetI2sFormat(DATA_FORMAT_I2S); + + // AIF config + ok &= WriteReg(I2S1_SDOUT_CTRL, 0xc000); + ok &= WriteReg(I2S1_SDIN_CTRL, 0xc000); + ok &= WriteReg(I2S1_MXR_SRC, 0x2200); + + ok &= WriteReg(ADC_SRCBST_CTRL, 0xccc4); + ok &= WriteReg(ADC_SRC, 0x1040); + ok &= WriteReg(ADC_DIG_CTRL, 0x8000); + ok &= WriteReg(ADC_APC_CTRL, 0xbbc3); + + // Path Configuration + ok &= WriteReg(DAC_MXR_SRC, 0xcc00); + ok &= WriteReg(DAC_DIG_CTRL, 0x8000); + ok &= WriteReg(OMIXER_SR, 0x0081); + ok &= WriteReg(OMIXER_DACA_CTRL, 0xf080); + + ok &= SetMode( MODE_DAC ); + + return ok; +} +//---------------------------------------------------------------------------------------------------------------------- +void AC101::DumpRegisters() { + for (size_t i = 0; i < ARRAY_SIZE(regs); ++i){ + Serial.print(regs[i], HEX); + Serial.print(" = "); + Serial.println(ReadReg(regs[i]), HEX); + } +} +//---------------------------------------------------------------------------------------------------------------------- +uint8_t AC101::GetVolumeSpeaker() { + // Times 2, to scale to same range as headphone volume + return (ReadReg(SPKOUT_CTRL) & 31) * 2; +} + +bool AC101::SetVolumeSpeaker(uint8_t volume) { + // Divide by 2, as it is scaled to same range as headphone volume + volume /= 2; + if(volume > 31) volume = 31; + + uint16_t val = ReadReg(SPKOUT_CTRL); + val &= ~31; + val |= volume; + return WriteReg(SPKOUT_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +uint8_t AC101::GetVolumeHeadphone() { + return (ReadReg(HPOUT_CTRL) >> 4) & 63; +} + +bool AC101::SetVolumeHeadphone(uint8_t volume) { + if(volume > 63) volume = 63; + + uint16_t val = ReadReg(HPOUT_CTRL); + val &= ~63U << 4; + val |= volume << 4; + return WriteReg(HPOUT_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetI2sSampleRate(I2sSampleRate_t rate) { + return WriteReg(I2S_SR_CTRL, rate); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetI2sMode(I2sMode_t mode) { + uint16_t val = ReadReg(I2S1LCK_CTRL); + val &= ~0x8000; + val |= uint16_t(mode) << 15; + return WriteReg(I2S1LCK_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetI2sWordSize(I2sWordSize_t size) { + uint16_t val = ReadReg(I2S1LCK_CTRL); + val &= ~0x0030; + val |= uint16_t(size) << 4; + return WriteReg(I2S1LCK_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetI2sFormat(I2sFormat_t format) { + uint16_t val = ReadReg(I2S1LCK_CTRL); + val &= ~0x000C; + val |= uint16_t(format) << 2; + return WriteReg(I2S1LCK_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetI2sClock(I2sBitClockDiv_t bitClockDiv, bool bitClockInv, I2sLrClockDiv_t lrClockDiv, bool lrClockInv) { + uint16_t val = ReadReg(I2S1LCK_CTRL); + val &= ~0x7FC0; + val |= uint16_t(bitClockInv ? 1 : 0) << 14; + val |= uint16_t(bitClockDiv) << 9; + val |= uint16_t(lrClockInv ? 1 : 0) << 13; + val |= uint16_t(lrClockDiv) << 6; + return WriteReg(I2S1LCK_CTRL, val); +} +//---------------------------------------------------------------------------------------------------------------------- +bool AC101::SetMode(Mode_t mode) { + bool ok = true; + if(MODE_LINE == mode) { + ok &= WriteReg(ADC_SRC, 0x0408); + ok &= WriteReg(ADC_DIG_CTRL, 0x8000); + ok &= WriteReg(ADC_APC_CTRL, 0x3bc0); + } + + if((MODE_ADC == mode) or (MODE_ADC_DAC == mode) or (MODE_LINE == mode)) { + ok &= WriteReg(MOD_CLK_ENA, 0x800c); + ok &= WriteReg(MOD_RST_CTRL, 0x800c); + } + + if((MODE_DAC == mode) or (MODE_ADC_DAC == mode) or (MODE_LINE == mode)) { + // Enable Headphone output + ok &= WriteReg(OMIXER_DACA_CTRL, 0xff80); + ok &= WriteReg(HPOUT_CTRL, 0xc3c1); + ok &= WriteReg(HPOUT_CTRL, 0xcb00); + delay(100); + ok &= WriteReg(HPOUT_CTRL, 0xfbc0); + ok &= SetVolumeHeadphone(30); + + // Enable Speaker output + ok &= WriteReg(SPKOUT_CTRL, 0xeabd); + delay(10); + ok &= SetVolumeSpeaker(30); + } + return ok; +} diff --git a/libraries/ESP32-audioI2S/examples/AC101/AC101.h b/libraries/ESP32-audioI2S/examples/AC101/AC101.h new file mode 100644 index 0000000..f34127b --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/AC101/AC101.h @@ -0,0 +1,166 @@ +/* + AC101 - An AC101 Codec driver library for Arduino + Copyright (C) 2019, Ivo Pullens, Emmission + + Inspired by: + https://github.com/donny681/esp-adf/tree/master/components/audio_hal/driver/AC101 + + 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 3 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, see . +*/ + +#ifndef AC101_H +#define AC101_H + +#include +#include +#include + +class AC101 +{ +public: + typedef enum { + SAMPLE_RATE_8000 = 0x0000, + SAMPLE_RATE_11052 = 0x1000, + SAMPLE_RATE_12000 = 0x2000, + SAMPLE_RATE_16000 = 0x3000, + SAMPLE_RATE_22050 = 0x4000, + SAMPLE_RATE_24000 = 0x5000, + SAMPLE_RATE_32000 = 0x6000, + SAMPLE_RATE_44100 = 0x7000, + SAMPLE_RATE_48000 = 0x8000, + SAMPLE_RATE_96000 = 0x9000, + SAMPLE_RATE_192000 = 0xa000, + } I2sSampleRate_t; + + typedef enum { + MODE_MASTER = 0x00, + MODE_SLAVE = 0x01, + } I2sMode_t; + + typedef enum { + WORD_SIZE_8_BITS = 0x00, + WORD_SIZE_16_BITS = 0x01, + WORD_SIZE_20_BITS = 0x02, + WORD_SIZE_24_BITS = 0x03, + } I2sWordSize_t; + + typedef enum { + DATA_FORMAT_I2S = 0x00, + DATA_FORMAT_LEFT = 0x01, + DATA_FORMAT_RIGHT = 0x02, + DATA_FORMAT_DSP = 0x03, + } I2sFormat_t; + + typedef enum { + BCLK_DIV_1 = 0x0, + BCLK_DIV_2 = 0x1, + BCLK_DIV_4 = 0x2, + BCLK_DIV_6 = 0x3, + BCLK_DIV_8 = 0x4, + BCLK_DIV_12 = 0x5, + BCLK_DIV_16 = 0x6, + BCLK_DIV_24 = 0x7, + BCLK_DIV_32 = 0x8, + BCLK_DIV_48 = 0x9, + BCLK_DIV_64 = 0xa, + BCLK_DIV_96 = 0xb, + BCLK_DIV_128 = 0xc, + BCLK_DIV_192 = 0xd, + } I2sBitClockDiv_t; + + typedef enum { + LRCK_DIV_16 = 0x0, + LRCK_DIV_32 = 0x1, + LRCK_DIV_64 = 0x2, + LRCK_DIV_128 = 0x3, + LRCK_DIV_256 = 0x4, + } I2sLrClockDiv_t; + + + typedef enum { + MODE_ADC, + MODE_DAC, + MODE_ADC_DAC, + MODE_LINE + } Mode_t; + + // Constructor. + AC101(TwoWire *TwoWireInstance = &Wire); + + // Initialize codec, using provided I2C pins and bus frequency. + // @return True on success, false on failure. + bool begin(int32_t sda = -1, int32_t scl = -1, uint32_t frequency = 400000); + + // Get speaker volume. + // @return Speaker volume, [63..0] for [0..-43.5] [dB], in increments of 2. + uint8_t GetVolumeSpeaker(); + + // Set speaker volume. + // @param volume Target volume, [63..0] for [0..-43.5] [dB], in increments of 2. + // @return True on success, false on failure. + bool SetVolumeSpeaker(uint8_t volume); + + // Get headphone volume. + // @return Headphone volume, [63..0] for [0..-62] [dB] + uint8_t GetVolumeHeadphone(); + + // Set headphone volume + // @param volume Target volume, [63..0] for [0..-62] [dB] + // @return True on success, false on failure. + bool SetVolumeHeadphone(uint8_t volume); + + // Configure I2S samplerate. + // @param rate Samplerate. + // @return True on success, false on failure. + bool SetI2sSampleRate(I2sSampleRate_t rate); + + // Configure I2S mode (master/slave). + // @param mode Mode. + // @return True on success, false on failure. + bool SetI2sMode(I2sMode_t mode); + + // Configure I2S word size (8/16/20/24 bits). + // @param size Word size. + // @return True on success, false on failure. + bool SetI2sWordSize(I2sWordSize_t size); + + // Configure I2S format (I2S/Left/Right/Dsp). + // @param format I2S format. + // @return True on success, false on failure. + bool SetI2sFormat(I2sFormat_t format); + + // Configure I2S clock. + // @param bitClockDiv I2S1CLK/BCLK1 ratio. + // @param bitClockInv I2S1 BCLK Polarity. + // @param lrClockDiv BCLK1/LRCK ratio. + // @param lrClockInv I2S1 LRCK Polarity. + // @return True on success, false on failure. + bool SetI2sClock(I2sBitClockDiv_t bitClockDiv, bool bitClockInv, I2sLrClockDiv_t lrClockDiv, bool lrClockInv); + + // Configure the mode (Adc/Dac/Adc+Dac/Line) + // @param mode Operating mode. + // @return True on success, false on failure. + bool SetMode(Mode_t mode); + + // Dumpt the current register configuration to serial. + void DumpRegisters(); + +protected: + bool WriteReg(uint8_t reg, uint16_t val); + uint16_t ReadReg(uint8_t reg); +private: + TwoWire *_TwoWireInstance = NULL; // TwoWire Instance +}; + +#endif diff --git a/libraries/ESP32-audioI2S/examples/AC101/main.cpp b/libraries/ESP32-audioI2S/examples/AC101/main.cpp new file mode 100644 index 0000000..28f2a59 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/AC101/main.cpp @@ -0,0 +1,85 @@ +#include "Arduino.h" +#include "WiFi.h" +#include "SPI.h" +#include "SD.h" +#include "FS.h" +#include "Wire.h" +#include "AC101.h" +#include "Audio.h" + +// I2S GPIOs, the names refer on AC101, AS1 Audio Kit V2.2 2379 +#define I2S_DSIN 35 // pin not used +#define I2S_BCLK 27 +#define I2S_LRC 26 +#define I2S_MCLK 0 +#define I2S_DOUT 25 + +// I2C GPIOs +#define IIC_CLK 32 +#define IIC_DATA 33 + +// amplifier enable +#define GPIO_PA_EN 21 + +//Switch S1: 1-OFF, 2-ON, 3-ON, 4-OFF, 5-OFF + +String ssid = "*****"; +String password = "*****"; + +static AC101 dac; // AC101 +int volume = 40; // 0...100 + +Audio audio; + +//##################################################################### + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + + while (WiFi.status() != WL_CONNECTED){ + Serial.print("."); + delay(100); + } + + Serial.printf_P(PSTR("Connected\r\nRSSI: ")); + Serial.print(WiFi.RSSI()); + Serial.print(" IP: "); + Serial.println(WiFi.localIP()); + + Serial.printf("Connect to DAC codec... "); + while (not dac.begin(IIC_DATA, IIC_CLK)){ + Serial.printf("Failed!\n"); + delay(1000); + } + Serial.printf("OK\n"); + + dac.SetVolumeSpeaker(volume); + dac.SetVolumeHeadphone(volume); +// ac.DumpRegisters(); + + // Enable amplifier + pinMode(GPIO_PA_EN, OUTPUT); + digitalWrite(GPIO_PA_EN, HIGH); + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT, I2S_MCLK); + audio.setVolume(10); // 0...21 + + audio.connecttohost("http://mp3channels.webradio.antenne.de:80/oldies-but-goldies"); +// audio.connecttohost("http://dg-rbb-http-dus-dtag-cdn.cast.addradio.de/rbb/antennebrandenburg/live/mp3/128/stream.mp3"); +// audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de"); + +} + +//----------------------------------------------------------------------- + +void loop(){ + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/Audio Recorder/audio_recorder.cpp b/libraries/ESP32-audioI2S/examples/Audio Recorder/audio_recorder.cpp new file mode 100644 index 0000000..9d87749 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/Audio Recorder/audio_recorder.cpp @@ -0,0 +1,292 @@ + +// example AUDIO RECORDER +// starts an audio stream and records 10 seconds of it on the SD card. + + +#include "Arduino.h" +#include "Audio.h" +#include "WiFiMulti.h" +#include +#include + +Audio audio; +WiFiMulti wifiMulti; + +//______________________________________________________________________________________________________________________________________________________________________________________________________ +// A U D I O R E C O R D E R +//______________________________________________________________________________________________________________________________________________________________________________________________________ + +struct WAVHeader { + char riff[4] = {'R', 'I', 'F', 'F'}; + uint32_t size; + char wave[4] = {'W', 'A', 'V', 'E'}; + char fmt[4] = {'f', 'm', 't', ' '}; + uint32_t fmtSize = 16; + uint16_t format = 1; + uint16_t channels = 2; + uint32_t sampleRate; + uint32_t byteRate; + uint16_t blockAlign; + uint16_t bits; + char data[4] = {'d', 'a', 't', 'a'}; + uint32_t dataSize; +}; + +constexpr size_t REC_BUFFER_SIZE = 512 * 1024; // 512KB für 2-3 Sekunden Puffer +constexpr size_t WRITE_CHUNK_SIZE = 10242; // not too big! +constexpr size_t SD_FLUSH_INTERVAL = 65536; // Alle 64KB flush +ps_ptr rec_buffer; +ps_ptr writeBuffer; + +class AudioRecorder { + public: + std::atomic writePos{0}; + std::atomic readPos{0}; + uint32_t totalBytes = 0; + uint16_t sampleRate = 44100; + uint32_t overflowCount = 0; + + volatile bool startRequested = false; + volatile bool stopRequested = false; + volatile bool running = false; + + bool push16(const int32_t* data, size_t frames) { + // frames = Stereo-Frames + size_t bytes16 = frames * 2 * sizeof(int16_t); + + size_t currentWrite = writePos.load(std::memory_order_relaxed); + size_t currentRead = readPos.load(std::memory_order_acquire); + + size_t free = (currentRead + REC_BUFFER_SIZE - currentWrite - 1) % REC_BUFFER_SIZE; + + if (bytes16 > free) { + overflowCount++; + return false; + } + + for (size_t i = 0; i < frames * 2; i++) { + // 32 → 16 Bit (High word) + int32_t v = data[i] >> 16; + + // Optional Clipping (save) + if (v > 32767) v = 32767; + if (v < -32768) v = -32768; + + int16_t s = (int16_t)v; + + // Write byte by byte (LE) + rec_buffer[currentWrite] = s & 0xFF; + currentWrite = (currentWrite + 1) % REC_BUFFER_SIZE; + rec_buffer[currentWrite] = (s >> 8) & 0xFF; + currentWrite = (currentWrite + 1) % REC_BUFFER_SIZE; + } + writePos.store(currentWrite, std::memory_order_release); + return true; + } + + // Copies data to dest, returns bytes actually read + size_t pop(uint8_t* dest, size_t maxLen) { + size_t currentRead = readPos.load(std::memory_order_relaxed); + size_t currentWrite = writePos.load(std::memory_order_acquire); + + if (currentRead == currentWrite) return 0; + + size_t avail = (currentWrite > currentRead) ? (currentWrite - currentRead) : (REC_BUFFER_SIZE - currentRead); + + size_t toRead = std::min(avail, maxLen); + + // Wrap-around handling + size_t firstChunk = std::min(toRead, REC_BUFFER_SIZE - currentRead); + memcpy(dest, &rec_buffer[currentRead], firstChunk); + if (toRead > firstChunk) { memcpy(dest + firstChunk, &rec_buffer[0], toRead - firstChunk); } + + readPos.store((currentRead + toRead) % REC_BUFFER_SIZE, std::memory_order_release); + return toRead; + } + + // For external access to buffers (e.g. for pop with pointer math, but not recommended) + size_t available() { + size_t w = writePos.load(std::memory_order_acquire); + size_t r = readPos.load(std::memory_order_acquire); + return (w >= r) ? (w - r) : (REC_BUFFER_SIZE - r + w); + } +}; + +AudioRecorder recorder; + +void wavWriterTask(void*) { + File file; + WAVHeader hdr; + bool fileOpen = false; + + size_t writeBufferFill = 0; + uint32_t bytesSinceFlush = 0; + + while (true) { + // --- START REQUEST --- + if (recorder.startRequested && !fileOpen) { + recorder.startRequested = false; + + // Datei mit Zeitstempel erstellen + char filename[64]; + snprintf(filename, sizeof(filename), "/recording.wav"); + + file = SD_MMC.open(filename, FILE_WRITE); + if (!file) { + Serial.println("Failed to open file! \"/recording.wav\""); + continue; + } + // prepeare header + hdr.sampleRate = recorder.sampleRate; + hdr.byteRate = recorder.sampleRate * 2 * 2; // Stereo, 16-bit + hdr.blockAlign = 2 * 2; // 8 bytes per frame + hdr.bits = 16; + hdr.dataSize = 0; + hdr.size = 36; // 44 - 8 (RIFF header) + + file.write((uint8_t*)&hdr, sizeof(hdr)); + recorder.totalBytes = 0; + writeBufferFill = 0; + bytesSinceFlush = 0; + fileOpen = true; + recorder.running = true; + + Serial.printf("Recording started: %s\n", filename); + } + + // --- WRITE DATA --- + if (fileOpen) { + // fill local buffer + while (writeBufferFill < WRITE_CHUNK_SIZE) { + size_t spaceInLocalBuffer = WRITE_CHUNK_SIZE - writeBufferFill; + size_t bytesRead = recorder.pop(writeBuffer + writeBufferFill, spaceInLocalBuffer); + + if (bytesRead == 0) break; // ringbuffer is empty + + writeBufferFill += bytesRead; + } + + // write full block to SD + if (writeBufferFill >= WRITE_CHUNK_SIZE) { + size_t written = file.write(writeBuffer.get(), WRITE_CHUNK_SIZE); + if (written != WRITE_CHUNK_SIZE) { + Serial.println("SD write error!"); + // Optional: error handling, hold buffer? + } + + recorder.totalBytes += written; + bytesSinceFlush += written; + writeBufferFill = 0; // buffer is empty (or move remaining data) + + // Periodic flush for data integrity + if (bytesSinceFlush >= SD_FLUSH_INTERVAL) { + file.flush(); + bytesSinceFlush = 0; + } + } + } + + // --- STOP REQUEST --- + if (recorder.stopRequested && fileOpen) { + recorder.stopRequested = false; + + // Write remaining data to local buffer + if (writeBufferFill > 0) { + file.write(writeBuffer.get(), writeBufferFill); + recorder.totalBytes += writeBufferFill; + } + + // Update header + hdr.dataSize = recorder.totalBytes; + hdr.size = recorder.totalBytes + 36; + + file.seek(0); + file.write((uint8_t*)&hdr, sizeof(hdr)); + file.flush(); + file.close(); + + fileOpen = false; + writeBufferFill = 0; + recorder.running = false; + Serial.printf("Recording stopped. Total bytes: %u, Overflows: %u\n", recorder.totalBytes, recorder.overflowCount); + } + + // Small delay to feed watchdog and release CPU + // But not too long, so that the ring buffer does not overflow! + vTaskDelay(pdMS_TO_TICKS(1)); // 1ms = ~176 Bytes bei 44.1kHz Stereo 32-bit + } +} + +//______________________________________________________________________________________________________________________________________________________________________________________________________ + +#define I2S_DOUT 25 +#define I2S_BCLK 27 +#define I2S_LRC 26 +#define SD_MMC_D0 2 +#define SD_MMC_CLK 14 +#define SD_MMC_CMD 15 + +String ssid = "*****"; +String password = "*****"; + +uint32_t t; +enum {IDLE, RECORDING, FINISH, PLAYBACK}; +uint8_t state = IDLE; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Serial.begin(115200); + Audio::audio_info_callback = my_audio_info; + Serial.print("\n\n"); + + wifiMulti.addAP(ssid.c_str(), password.c_str()); + wifiMulti.run(); // if there are multiple access points, use the strongest one + while (WiFi.status() != WL_CONNECTED) delay(1500); + pinMode(SD_MMC_D0, INPUT_PULLUP); + SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0); + SD_MMC.begin("/sdcard", true); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(20); // default 0...21 + audio.connecttohost("http://stream.antennethueringen.de/live/aac-64/stream.antennethueringen.de/"); // aac + + rec_buffer.alloc_array(REC_BUFFER_SIZE, "rec_buffer"); // allocate in PSRAM + writeBuffer.alloc_array(WRITE_CHUNK_SIZE, "writeBuffer"); // allocate in PSRAM + xTaskCreatePinnedToCore(wavWriterTask, "wavWriter", 4096, nullptr, 1, nullptr, 0); // start recorder task + Serial.printf("recorder task started, Free heap: %u\n", ESP.getFreeHeap()); + t = millis(); +} + +void loop() { + audio.loop(); + vTaskDelay(1); + if (t + 5000 < millis() && state == IDLE && audio.isRunning()) { + Serial.println("start recording"); + state = RECORDING; + recorder.sampleRate = audio.getSampleRate(); + recorder.startRequested = true; + } + if (t + 15000 < millis() && state == RECORDING) { + Serial.println("stop recording"); + state = FINISH; + recorder.stopRequested = true; + audio.stopSong(); + } + if (t + 17000 < millis() && state == FINISH) { + state = PLAYBACK; + audio.connecttoFS(SD_MMC, "/recording.wav"); + } + if (t + 29000 < millis() && state == PLAYBACK && !audio.isRunning()) { + state = IDLE; + audio.connecttohost("http://stream.antennethueringen.de/live/aac-64/stream.antennethueringen.de/"); + t = millis(); + } +} +//______________________________________________________________________________________________________________________________________________________________________________________________________ +void audio_process_raw_samples(int32_t* outBuff, int16_t validSamples) { // samples are available, write in wav file + if (recorder.running == true) { + recorder.push16(outBuff, validSamples); + } +} diff --git a/libraries/ESP32-audioI2S/examples/ES8311/ES8311_DS.pdf b/libraries/ESP32-audioI2S/examples/ES8311/ES8311_DS.pdf new file mode 100644 index 0000000..dd5b658 Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ES8311/ES8311_DS.pdf differ diff --git a/libraries/ESP32-audioI2S/examples/ES8311/es8311.cpp b/libraries/ESP32-audioI2S/examples/ES8311/es8311.cpp new file mode 100644 index 0000000..1da6c0a --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8311/es8311.cpp @@ -0,0 +1,316 @@ +/* + ES8311 - An ES8311 Codec driver library for Arduino + + 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 3 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, see . + + examples: + + //one I2C bus: (default behaviour) + ES8311 es; + es.begin(sda, scl); + + //two I2C busses: + TwoWire i2cBusOne = TwoWire(0); + TwoWire i2cBusTwo = TwoWire(1); + ES8311 es(&i2cBusOne); + + i2cBusOne.begin(sda, scl, 400000); +*/ + +#include "es8311.h" + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /*!end(); + } +} + +/* +* look for the coefficient in coeff_div[] table +*/ +int ES8311::get_coeff(uint32_t mclk, uint32_t rate){ + for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) { + return i; + } + } + return -1; +} + +bool ES8311::begin(int32_t sda, int32_t scl, uint32_t frequency) { + bool ok = true; + uint8_t reg = 0; + + if((sda >= 0) && (scl >= 0)){ + ok = _TwoWireInstance->begin(sda, scl, frequency); + _TwoWireInstance->beginTransmission(ES8311_ADDR); + ok = (Wire.endTransmission() == 0); + if(!ok) { + _TwoWireInstance->end(); + log_e("ES8311 not found"); return false; + } + } + else { + log_e("Invalid SDA/SCL pins"); + return false; + } + + ok |= WriteReg(0x00, 0x1F); // Reset + vTaskDelay(20 / portTICK_PERIOD_MS); + ok |= WriteReg(0x00, 0x00); // Release reset + ok |= WriteReg(0x00, 0x80); // Power on + + ok |= WriteReg(0x01, 0x3F); // Enable all clocks + + reg = ReadReg(0x06); + reg &= ~BIT(5); // SCLK (BCLK) pin not inverted + ok |= WriteReg(0x06, reg); // + + ok |= setSampleRate(ES8311_SAMPLE_RATE48); // default + ok |= setBitsPerSample(ES8311_BITS_PER_SAMPLE16); // default + + ok |= WriteReg(0x0D, 0x01); // Power up analog circuitry + ok |= WriteReg(0x0E, 0x02); // Enable analog PGA, enable ADC modulator + ok |= WriteReg(0x12, 0x00); // Power-up DAC + ok |= WriteReg(0x13, 0x10); // Enable output to HP drive + ok |= WriteReg(0x1C, 0x6A); // ADC Equalizer bypass, cancel DC offset in digital domain + ok |= WriteReg(0x37, 0x08); // Bypass DAC equalizer + + return ok; +} + +bool ES8311::setVolume(uint8_t volume){ // 0...100 + if (volume > 100) {volume = 100;} + int reg32; + if (volume == 0) {reg32 = 0;} + else { reg32 = ((volume) * 256 / 100) - 1;} + return WriteReg(0x32, reg32); +} + +uint8_t ES8311::getVolume(){ + uint8_t reg32 = ReadReg(0x32); + uint8_t volume; + if (reg32 == 0) { + volume = 0; + } else { + volume = ((reg32 * 100) / 256) + 1; + } + return volume; +} + +bool ES8311::setSampleRate(uint32_t sample_rate){ + uint8_t reg = 0; + bool ok = true; + _mclk_hz = sample_rate * 256; // default MCLK frequency + if(sample_rate > 64000) _mclk_hz /= 2; + int coeff = get_coeff(_mclk_hz, sample_rate); + if (coeff < 0) {log_e("Invalid sample rate %i", sample_rate); return false;} + const struct _coeff_div *const selected_coeff = &coeff_div[coeff]; + reg = ReadReg(0x02); + reg |= (selected_coeff->pre_div - 1) << 5; + reg |= selected_coeff->pre_multi << 3; + ok |= WriteReg(0x02, reg); // Set pre_div and pre_multi + const uint8_t reg03 = (selected_coeff->fs_mode << 6) | selected_coeff->adc_osr; + ok |= WriteReg(0x03, reg03); // Set fs_mode and adc_osr + ok |= WriteReg(0x04, selected_coeff->dac_osr); // Set dac_osr + const uint8_t reg05 = ((selected_coeff->adc_div - 1) << 4) | (selected_coeff->dac_div - 1); + ok |= WriteReg(0x05, reg05); // Set adc_div and dac_div + reg = ReadReg(0x06); + reg &= 0xE0; + if (selected_coeff->bclk_div < 19) {reg |= (selected_coeff->bclk_div - 1) << 0;} + else { reg |= (selected_coeff->bclk_div) << 0;} + ok |= WriteReg(0x06, reg); // Set bclk_div + reg = ReadReg(0x07); + reg &= 0xC0; + reg |= selected_coeff->lrck_h << 0; + ok |= WriteReg(0x07, reg); // Set lrck_h + ok |= WriteReg(0x08, selected_coeff->lrck_l); // Set lrck_l + return ok; +} + +bool ES8311::setBitsPerSample(uint8_t bps){ + uint8_t reg09 = ReadReg(0x09); + uint8_t reg0A = ReadReg(0x0A); + switch (bps) { + case 16: reg09 |= (3 << 2); reg0A |= (3 << 2); break; + case 18: reg09 |= (2 << 2); reg0A |= (2 << 2); break; + case 20: reg09 |= (1 << 2); reg0A |= (1 << 2); break; + case 24: reg09 |= (0 << 2); reg0A |= (0 << 2); break; + case 32: reg09 |= (4 << 2); reg0A |= (4 << 2); break; + default: return false; // Invalid bits per sample + } + bool ok = WriteReg(0x09, reg09); + ok |= WriteReg(0x0A, reg0A); + return ok; +} + +bool ES8311::enableMicrophone(bool enable){ + uint8_t reg = 0x1A; // enable analog MIC and max PGA gain + if (enable) { + reg |= BIT(6); + } + bool ok = WriteReg(0x17, 0xC8); // ADC_VOLUME + ok |= WriteReg(0x14, reg); // Enable MIC + return ok; +} + +bool ES8311::setMicrophoneGain(uint8_t gain){ // 0...7 + uint8_t reg = ReadReg(0x16); + reg &= 0xF8; // Clear gain bits + if (gain > 7) {gain = 7;} + reg |= gain; // Set gain bits + bool ok = WriteReg(0x16, gain); // ADC_VOLUME + return ok; +} + +uint8_t ES8311::getMicrophoneGain(){ + uint8_t reg = ReadReg(0x16); + return (reg & 0x07); // Get gain bits +} + +bool ES8311::WriteReg(uint8_t reg, uint8_t val){ + _TwoWireInstance->beginTransmission(ES8311_ADDR); + _TwoWireInstance->write(reg); + _TwoWireInstance->write(val); + return _TwoWireInstance->endTransmission() == 0; +} + +uint8_t ES8311::ReadReg(uint8_t reg){ + _TwoWireInstance->beginTransmission(ES8311_ADDR); + _TwoWireInstance->write(reg); + _TwoWireInstance->endTransmission(false); + + uint8_t val = 0u; + _TwoWireInstance->requestFrom(uint16_t(ES8311_ADDR), (uint8_t)1, true); + if(_TwoWireInstance->available() >= 1){ + val = _TwoWireInstance->read(); + } + _TwoWireInstance->endTransmission(); + return val; +} + +void ES8311::read_all(){ + for (uint8_t i = 0; i < 0x4A; i++) { + Serial.printf("0x%02X: 0x%02X\n", i, ReadReg(i)); + } +} + diff --git a/libraries/ESP32-audioI2S/examples/ES8311/es8311.h b/libraries/ESP32-audioI2S/examples/ES8311/es8311.h new file mode 100644 index 0000000..842fb6c --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8311/es8311.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include + + +#define ES8311_ADDR 0x18 +#define ES8311_SAMPLE_RATE48 48000 +#define ES8311_BITS_PER_SAMPLE16 16 + +struct _coeff_div { /* Clock coefficient structure */ + uint32_t mclk; /* mclk frequency */ + uint32_t rate; /* sample rate */ + uint8_t pre_div; /* the pre divider with range from 1 to 8 */ + uint8_t pre_multi; /* the pre multiplier with 0: 1x, 1: 2x, 2: 4x, 3: 8x selection */ + uint8_t adc_div; /* adcclk divider */ + uint8_t dac_div; /* dacclk divider */ + uint8_t fs_mode; /* double speed or single speed, =0, ss, =1, ds */ + uint8_t lrck_h; /* adclrck divider and daclrck divider */ + uint8_t lrck_l; + uint8_t bclk_div; /* sclk divider */ + uint8_t adc_osr; /* adc osr */ + uint8_t dac_osr; /* dac osr */ +}; + +class ES8311{ + +private: + TwoWire *_TwoWireInstance = NULL; // TwoWire Instance + uint32_t _mclk_hz = 48000 * 256; // default MCLK frequency +public: + // Constructor. + ES8311(TwoWire *TwoWireInstance = &Wire); + ~ES8311(); + bool begin(int32_t sda, int32_t scl, uint32_t frequency); + bool setVolume(uint8_t volume); + uint8_t getVolume(); + bool setSampleRate(uint32_t sample_rate); + bool setBitsPerSample(uint8_t bps); + bool enableMicrophone(bool enable); + bool setMicrophoneGain(uint8_t gain); + uint8_t getMicrophoneGain(); + void read_all(); +protected: + int get_coeff(uint32_t mclk, uint32_t rate); + bool WriteReg(uint8_t reg, uint8_t val); + uint8_t ReadReg(uint8_t reg); +}; + diff --git a/libraries/ESP32-audioI2S/examples/ES8311/main.cpp b/libraries/ESP32-audioI2S/examples/ES8311/main.cpp new file mode 100644 index 0000000..37e785b --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8311/main.cpp @@ -0,0 +1,62 @@ +#include "Arduino.h" +#include "Audio.h" +#include "WiFi.h" +#include "es8311.h" +#include "Wire.h" + +// Pins: Waveshare ESP32-P4-Module-DEV-KIT and ESP32-P4-NANO High-performance Development Board +#define I2S_DOUT 9 // DSDIN pin(es8311) +#define I2S_BCLK 12 // SCLK +#define I2S_MCLK 13 +#define I2S_LRC 10 // LRCK +#define I2C_SCL 8 +#define I2C_SDA 7 +#define PA_ENABLE 53 + +Audio audio; +ES8311 es; + +String ssid = "*****"; +String password = "*****"; + + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + Serial.print("\n\n"); + Serial.println("----------------------------------"); + Serial.printf("ESP32 Chip: %s\n", ESP.getChipModel()); + Serial.printf("Arduino Version: %d.%d.%d\n", ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH); + Serial.printf("ESP-IDF Version: %d.%d.%d\n", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR, ESP_IDF_VERSION_PATCH); + Serial.printf("ARDUINO_LOOP_STACK_SIZE %d words (32 bit)\n", CONFIG_ARDUINO_LOOP_STACK_SIZE); + Serial.println("----------------------------------"); + Serial.print("\n\n"); + + WiFi.begin(ssid.c_str(), password.c_str()); + while (WiFi.status() != WL_CONNECTED) {delay(1500); Serial.print(".");} + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT, I2S_MCLK); + audio.setVolume(21); // default 0...21 + + pinMode(PA_ENABLE, OUTPUT); + digitalWrite(PA_ENABLE, HIGH); + + if(!es.begin(I2C_SDA, I2C_SCL, 400000)) log_e("ES8311 begin failed"); + es.setVolume(50); + es.setBitsPerSample(16); + + // es.setSampleRate(22050); + // es.read_all(); + // audio.connecttohost("http://www.wdr.de/wdrlive/media/einslive.m3u"); + audio.connecttohost("http://stream.antennethueringen.de/live/aac-64/stream.antennethueringen.de/"); // aac + +} + +void loop() { + audio.loop(); + vTaskDelay(1); +} diff --git a/libraries/ESP32-audioI2S/examples/ES8388/ES8388.cpp b/libraries/ESP32-audioI2S/examples/ES8388/ES8388.cpp new file mode 100644 index 0000000..bf286b5 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8388/ES8388.cpp @@ -0,0 +1,270 @@ +#include +#include "ES8388.h" +#include + +#define ES8388_ADDR 0x10 + +/* ES8388 register */ +#define ES8388_CONTROL1 0x00 +#define ES8388_CONTROL2 0x01 +#define ES8388_CHIPPOWER 0x02 +#define ES8388_ADCPOWER 0x03 +#define ES8388_DACPOWER 0x04 +#define ES8388_CHIPLOPOW1 0x05 +#define ES8388_CHIPLOPOW2 0x06 +#define ES8388_ANAVOLMANAG 0x07 +#define ES8388_MASTERMODE 0x08 + +/* ADC */ +#define ES8388_ADCCONTROL1 0x09 +#define ES8388_ADCCONTROL2 0x0a +#define ES8388_ADCCONTROL3 0x0b +#define ES8388_ADCCONTROL4 0x0c +#define ES8388_ADCCONTROL5 0x0d +#define ES8388_ADCCONTROL6 0x0e +#define ES8388_ADCCONTROL7 0x0f +#define ES8388_ADCCONTROL8 0x10 +#define ES8388_ADCCONTROL9 0x11 +#define ES8388_ADCCONTROL10 0x12 +#define ES8388_ADCCONTROL11 0x13 +#define ES8388_ADCCONTROL12 0x14 +#define ES8388_ADCCONTROL13 0x15 +#define ES8388_ADCCONTROL14 0x16 + +/* DAC */ +#define ES8388_DACCONTROL1 0x17 +#define ES8388_DACCONTROL2 0x18 +#define ES8388_DACCONTROL3 0x19 +#define ES8388_DACCONTROL4 0x1a +#define ES8388_DACCONTROL5 0x1b +#define ES8388_DACCONTROL6 0x1c +#define ES8388_DACCONTROL7 0x1d +#define ES8388_DACCONTROL8 0x1e +#define ES8388_DACCONTROL9 0x1f +#define ES8388_DACCONTROL10 0x20 +#define ES8388_DACCONTROL11 0x21 +#define ES8388_DACCONTROL12 0x22 +#define ES8388_DACCONTROL13 0x23 +#define ES8388_DACCONTROL14 0x24 +#define ES8388_DACCONTROL15 0x25 +#define ES8388_DACCONTROL16 0x26 +#define ES8388_DACCONTROL17 0x27 +#define ES8388_DACCONTROL18 0x28 +#define ES8388_DACCONTROL19 0x29 +#define ES8388_DACCONTROL20 0x2a +#define ES8388_DACCONTROL21 0x2b +#define ES8388_DACCONTROL22 0x2c +#define ES8388_DACCONTROL23 0x2d +#define ES8388_DACCONTROL24 0x2e +#define ES8388_DACCONTROL25 0x2f +#define ES8388_DACCONTROL26 0x30 +#define ES8388_DACCONTROL27 0x31 +#define ES8388_DACCONTROL28 0x32 +#define ES8388_DACCONTROL29 0x33 +#define ES8388_DACCONTROL30 0x34 + +bool ES8388::write_reg(uint8_t slave_add, uint8_t reg_add, uint8_t data) +{ + Wire.beginTransmission(slave_add); + Wire.write(reg_add); + Wire.write(data); + return Wire.endTransmission() == 0; +} + +bool ES8388::read_reg(uint8_t slave_add, uint8_t reg_add, uint8_t &data) +{ + bool retval = false; + Wire.beginTransmission(slave_add); + Wire.write(reg_add); + Wire.endTransmission(false); + Wire.requestFrom((uint16_t)slave_add, (uint8_t)1, true); + if (Wire.available() >= 1) + { + data = Wire.read(); + retval = true; + } + return retval; +} + +bool ES8388::begin(int32_t sda, int32_t scl, uint32_t frequency) +{ + bool res = identify(sda, scl, frequency); + + if (res == true) + { + + /* mute DAC during setup, power up all systems, slave mode */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04); + res &= write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50); + res &= write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00); + res &= write_reg(ES8388_ADDR, ES8388_MASTERMODE, 0x00); + + /* power up DAC and enable LOUT1+2 / ROUT1+2, ADC sample rate = DAC sample rate */ + res &= write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x3e); + res &= write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x12); + + /* DAC I2S setup: 16 bit word length, I2S format; MCLK / Fs = 256*/ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL1, 0x18); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL2, 0x02); + + /* DAC to output route mixer configuration: ADC MIX TO OUTPUT */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x1B); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90); + + /* DAC and ADC use same LRCK, enable MCLK input; output resistance setup */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00); + + /* DAC volume control: 0dB (maximum, unattenuated) */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL5, 0x00); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL4, 0x00); + + /* power down ADC while configuring; volume: +9dB for both channels */ + res &= write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xff); + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, 0x88); // +24db + + /* select LINPUT2 / RINPUT2 as ADC input; stereo; 16 bit word length, format right-justified, MCLK / Fs = 256 */ + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, 0xf0); // 50 + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL3, 0x80); // 00 + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, 0x0e); + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, 0x02); + + /* set ADC volume */ + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL8, 0x20); + res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL9, 0x20); + + /* set LOUT1 / ROUT1 volume: 0dB (unattenuated) */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL24, 0x1e); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL25, 0x1e); + + /* set LOUT2 / ROUT2 volume: 0dB (unattenuated) */ + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0x1e); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0x1e); + + /* power up and enable DAC; power up ADC (no MIC bias) */ + res &= write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x3c); + res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x00); + res &= write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x00); + + /* set up MCLK) */ + #ifdef FUNC_GPIO0_CLK_OUT1 + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + #endif + WRITE_PERI_REG(PIN_CTRL, 0xFFF0); + } + return res; +} + +/** + * @brief (un)mute one of the two outputs or main dac output of the ES8388 by switching of the output register bits. Does not really mute the selected output, causes an attenuation. + * hence should be used in conjunction with appropriate volume setting. Main dac output mute does mute both outputs + * + * @param out + * @param muted + */ +void ES8388::mute(const ES8388_OUT out, const bool muted) +{ + uint8_t reg_addr; + uint8_t mask_mute; + uint8_t mask_val; + + switch (out) + { + case ES_OUT1: + reg_addr = ES8388_DACPOWER; + mask_mute = (3 << 4); + mask_val = muted ? 0 : mask_mute; + break; + case ES_OUT2: + reg_addr = ES8388_DACPOWER; + mask_mute = (3 << 2); + mask_val = muted ? 0 : mask_mute; + break; + case ES_MAIN: + default: + reg_addr = ES8388_DACCONTROL3; + mask_mute = 1 << 2; + mask_val = muted ? mask_mute : 0; + break; + } + + uint8_t reg; + if (read_reg(ES8388_ADDR, reg_addr, reg)) + { + reg = (reg & ~mask_mute) | (mask_val & mask_mute); + write_reg(ES8388_ADDR, reg_addr, reg); + } +} + +/** + * @brief Set volume gain for the main dac, or for one of the two output channels. Final gain = main gain + out channel gain + * + * @param out which gain setting to control + * @param vol 0-100 (100 is max) + */ +void ES8388::volume(const ES8388_OUT out, const uint8_t vol) +{ + const uint32_t max_vol = 100; // max input volume value + + const int32_t max_vol_val = out == ES8388_OUT::ES_MAIN ? 96 : 0x21; // max register value for ES8388 out volume + + uint8_t lreg = 0, rreg = 0; + + switch (out) + { + case ES_MAIN: + lreg = ES8388_DACCONTROL4; + rreg = ES8388_DACCONTROL5; + break; + case ES_OUT1: + lreg = ES8388_DACCONTROL24; + rreg = ES8388_DACCONTROL25; + break; + case ES_OUT2: + lreg = ES8388_DACCONTROL26; + rreg = ES8388_DACCONTROL27; + break; + } + + uint8_t vol_val = vol > max_vol ? max_vol_val : (max_vol_val * vol) / max_vol; + + // main dac volume control is reverse scale (lowest value is loudest) + // hence we reverse the calculated value + if (out == ES_MAIN) + { + vol_val = max_vol_val - vol_val; + } + + write_reg(ES8388_ADDR, lreg, vol_val); + write_reg(ES8388_ADDR, rreg, vol_val); +} + +void ES8388::SetVolumeSpeaker(uint8_t vol) { + vol = vol * 1.6; + volume(ES_OUT1, vol); + volume(ES_MAIN, 100); +} + +void ES8388::SetVolumeHeadphone(uint8_t vol){ + vol = vol * 1.6; + volume(ES_OUT2, vol); + volume(ES_MAIN, 100); +} + +/** + * @brief Test if device with I2C address for ES8388 is connected to the I2C bus + * + * @param sda which pin to use for I2C SDA + * @param scl which pin to use for I2C SCL + * @param frequency which frequency to use as I2C bus frequency + * @return true device was found + * @return false device was not found + */ +bool ES8388::identify(int32_t sda, int32_t scl, uint32_t frequency) +{ + Wire.begin(sda, scl, frequency); + Wire.beginTransmission(ES8388_ADDR); + return Wire.endTransmission() == 0; +} + diff --git a/libraries/ESP32-audioI2S/examples/ES8388/ES8388.h b/libraries/ESP32-audioI2S/examples/ES8388/ES8388.h new file mode 100644 index 0000000..991e443 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8388/ES8388.h @@ -0,0 +1,27 @@ +#pragma once +#include + +class ES8388 +{ + + bool write_reg(uint8_t slave_add, uint8_t reg_add, uint8_t data); + bool read_reg(uint8_t slave_add, uint8_t reg_add, uint8_t &data); + bool identify(int32_t sda, int32_t scl, uint32_t frequency); + +public: + bool begin(int32_t sda = -1, int32_t scl = -1, uint32_t frequency = 400000U); + + enum ES8388_OUT + { + ES_MAIN, // this is the DAC output volume (both outputs) + ES_OUT1, // this is the additional gain for OUT1 + ES_OUT2 // this is the additional gain for OUT2 + }; + + void SetVolumeSpeaker(uint8_t vol); + void SetVolumeHeadphone(uint8_t vol); + + void mute(const ES8388_OUT out, const bool muted); + void volume(const ES8388_OUT out, const uint8_t vol); +}; + diff --git a/libraries/ESP32-audioI2S/examples/ES8388/main.cpp b/libraries/ESP32-audioI2S/examples/ES8388/main.cpp new file mode 100644 index 0000000..ec8f4f0 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES8388/main.cpp @@ -0,0 +1,109 @@ +#include "Arduino.h" +#include "WiFi.h" +#include "SPI.h" +#include "SD.h" +#include "FS.h" +#include "Wire.h" +#include "ES8388.h" +#include "Audio.h" + + +// SPI GPIOs +#define SD_CS 13 +#define SPI_MOSI 15 +#define SPI_MISO 2 +#define SPI_SCK 14 + +// I2S GPIOs, the names refer on ES8388, AS1 Audio Kit V2.2 3378 +#define I2S_DSIN 35 // pin not used +#define I2S_BCLK 27 +#define I2S_LRC 25 +#define I2S_MCLK 0 +#define I2S_DOUT 26 + +// I2C GPIOs +#define IIC_CLK 32 +#define IIC_DATA 33 + +// buttons +// #define BUTTON_2_PIN 13 // shared mit SPI_CS +#define BUTTON_3_PIN 19 +#define BUTTON_4_PIN 23 +#define BUTTON_5_PIN 18 // Stop +#define BUTTON_6_PIN 5 // Play + +// amplifier enable +#define GPIO_PA_EN 21 + +//Switch S1: 1-OFF, 2-ON, 3-ON, 4-OFF, 5-OFF + +String ssid = "*****"; +String password = "*****"; + +ES8388 dac; // ES8388 (new board) +int volume = 40; // 0...100 + +Audio audio; + +//##################################################################### + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + Serial.println("\r\nReset"); + Serial.printf_P(PSTR("Free mem=%l\n"), ESP.getFreeHeap()); + + pinMode(SD_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); + SPI.setFrequency(1000000); + + SD.begin(SD_CS); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + + while (WiFi.status() != WL_CONNECTED){ + Serial.print("."); + delay(100); + } + + Serial.printf_P(PSTR("Connected\r\nRSSI: ")); + Serial.print(WiFi.RSSI()); + Serial.print(" IP: "); + Serial.println(WiFi.localIP()); + + Serial.printf("Connect to DAC codec... "); + while (not dac.begin(IIC_DATA, IIC_CLK)){ + Serial.printf("Failed!\n"); + delay(1000); + } + Serial.printf("OK\n"); + + dac.SetVolumeSpeaker(volume); + dac.SetVolumeHeadphone(volume); +// ac.DumpRegisters(); + + // Enable amplifier + pinMode(GPIO_PA_EN, OUTPUT); + digitalWrite(GPIO_PA_EN, HIGH); + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT, I2S_MCLK); + audio.setVolume(10); // 0...21 + + audio.connecttohost("http://mp3channels.webradio.antenne.de:80/oldies-but-goldies"); +// audio.connecttohost("http://dg-rbb-http-dus-dtag-cdn.cast.addradio.de/rbb/antennebrandenburg/live/mp3/128/stream.mp3"); +// audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de"); + +} + +//----------------------------------------------------------------------- + +void loop(){ + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/ES9038/Readme.md b/libraries/ESP32-audioI2S/examples/ES9038/Readme.md new file mode 100644 index 0000000..1281c99 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ES9038/Readme.md @@ -0,0 +1,19 @@ +# 32 bit ES9038 + +For those who have a board with a 32bit DAC +[DJ202](https://github.com/dj202) sent us a solution: + + +There are some great sounding and cheap 32 bit decoders available like boards with the ES9038Q2M that don't work because the library outputs 16 bits data. +You only need to change 3 lines lines of code to change it to 32bit: +## Audio.cpp +in Audio::Audio +````c++ +m_i2s_std_cfg.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO); +in Audio::resampleTo48kStereo: + +m_samplesBuff48K[outputIndex * 2] = clipToInt16(outLeft); +m_samplesBuff48K[outputIndex * 2 + 1] = 0x00; +m_samplesBuff48K[outputIndex * 2 + 2] = clipToInt16(outRight); +m_samplesBuff48K[outputIndex * 2 + 3] = 0x00; +```` diff --git a/libraries/ESP32-audioI2S/examples/ESP32_A1S/AI-Thinker ESP32-Audio-Kit.jpg b/libraries/ESP32-audioI2S/examples/ESP32_A1S/AI-Thinker ESP32-Audio-Kit.jpg new file mode 100644 index 0000000..ad858f4 Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ESP32_A1S/AI-Thinker ESP32-Audio-Kit.jpg differ diff --git a/libraries/ESP32-audioI2S/examples/ESP32_A1S/ESP32-A1S Product Specification.pdf b/libraries/ESP32-audioI2S/examples/ESP32_A1S/ESP32-A1S Product Specification.pdf new file mode 100644 index 0000000..19421ca Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ESP32_A1S/ESP32-A1S Product Specification.pdf differ diff --git a/libraries/ESP32-audioI2S/examples/ESP32_A1S/esp32-a1s_v2.3_specification.pdf b/libraries/ESP32-audioI2S/examples/ESP32_A1S/esp32-a1s_v2.3_specification.pdf new file mode 100644 index 0000000..762ab33 Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ESP32_A1S/esp32-a1s_v2.3_specification.pdf differ diff --git a/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/ESP32_TTGO-TAudio.ino b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/ESP32_TTGO-TAudio.ino new file mode 100644 index 0000000..0d0a766 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/ESP32_TTGO-TAudio.ino @@ -0,0 +1,59 @@ +// Copied from https://github.com/LilyGO/TTGO-TAudio/issues/12 + + +// Required Libraries (Download zips and add to the Arduino IDE library). +#include "Arduino.h" +#include // https://github.com/CelliesProjects/wm8978-esp32 +#include // https://github.com/schreibfaul1/ESP32-audioI2S + +// T-Audio 1.6 WM8978 I2C pins. +#define I2C_SDA 19 +#define I2C_SCL 18 + +// T-Audio 1.6 WM8978 I2S pins. +#define I2S_BCK 33 +#define I2S_WS 25 +#define I2S_DOUT 26 + +// T-Audio 1.6 WM8978 MCLK gpio number +#define I2S_MCLKPIN 0 + +Audio audio; +WM8978 dac; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + + // Setup wm8978 I2C interface. + if (!dac.begin(I2C_SDA, I2C_SCL)) { + ESP_LOGE(TAG, "Error setting up dac: System halted."); + while (1) delay(100); + } + + // Select I2S pins + audio.setPinout(I2S_BCK, I2S_WS, I2S_DOUT); + audio.i2s_mclk_pin_select(I2S_MCLKPIN); + + // WiFi Settings here. + WiFi.begin("EnterSSIDHere", "EnterPasswordHere"); + while (!WiFi.isConnected()) { + delay(10); + } + ESP_LOGI(TAG, "Connected. Starting MP3..."); + // Enter your Icecast station URL here. + audio.setVolume(21); + audio.connecttohost("http://hestia2.cdnstream.com/1458_128"); + // Volume control. + dac.setSPKvol(63); // Change volume here for board speaker output (Max 63). + dac.setHPvol(63, 63); // Change volume here for headphone jack left, right channel. +} + +void loop() { + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/T9V1.5.jpg b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/T9V1.5.jpg new file mode 100644 index 0000000..5ccb726 Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/T9V1.5.jpg differ diff --git a/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/schematic.pdf b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/schematic.pdf new file mode 100644 index 0000000..f5b444d Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/ESP32_TTGO-TAudio/schematic.pdf differ diff --git a/libraries/ESP32-audioI2S/examples/Ethernet/ETH_IP101.ino b/libraries/ESP32-audioI2S/examples/Ethernet/ETH_IP101.ino new file mode 100644 index 0000000..5144d52 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/Ethernet/ETH_IP101.ino @@ -0,0 +1,92 @@ +#include "Arduino.h" +#include "Audio.h" +#include "ETH.h" + +#ifdef CONFIG_IDF_TARGET_ESP32 +#define I2S_DOUT 25 +#define I2S_BCLK 27 +#define I2S_LRC 26 +#define ETH_PHY_TYPE ETH_PHY_TLK110 +#define ETH_PHY_MDC 23 +#define ETH_PHY_MDIO 18 +#define ETH_PHY_POWER -1 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#endif + +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#define I2S_DOUT 22 +#define I2S_BCLK 20 +#define I2S_LRC 21 +#define ETH_PHY_TYPE ETH_PHY_TLK110 +#define ETH_PHY_MDC 31 +#define ETH_PHY_MDIO 52 +#define ETH_PHY_POWER 51 +#define ETH_CLK_MODE EMAC_CLK_EXT_IN +#endif + +Audio audio; + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event) { + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + // The hostname must be set after the interface is started, but needs + // to be set before DHCP, so set it from the event handler thread. + ETH.setHostname("esp32-ethernet"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.println("ETH Got IP"); + Serial.println(ETH); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: break; + } +} + + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + Serial.print("A\n\n"); + Serial.println("----------------------------------"); + Serial.printf("ESP32 Chip: %s\n", ESP.getChipModel()); + Serial.printf("Arduino Version: %d.%d.%d\n", ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH); + Serial.printf("ESP-IDF Version: %d.%d.%d\n", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR, ESP_IDF_VERSION_PATCH); + Serial.printf("ARDUINO_LOOP_STACK_SIZE %d words (32 bit)\n", CONFIG_ARDUINO_LOOP_STACK_SIZE); + Serial.println("----------------------------------"); + Serial.print("\n\n"); + Network.onEvent(onEvent); + ETH.begin(); + while (!eth_connected) delay(100); + Serial.println("ETH Connected"); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(21); // default 0...21 + audio.connecttohost("http://stream.antennethueringen.de/live/aac-64/stream.antennethueringen.de/"); // aac + pinMode(53, OUTPUT); + digitalWrite(53, HIGH); +} + +void loop() { + audio.loop(); + vTaskDelay(1); +} + diff --git a/libraries/ESP32-audioI2S/examples/Ethernet/ETH_W5500.ino b/libraries/ESP32-audioI2S/examples/Ethernet/ETH_W5500.ino new file mode 100644 index 0000000..0c77277 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/Ethernet/ETH_W5500.ino @@ -0,0 +1,74 @@ +#include "Arduino.h" // >= Arduino V3 +#include +#include +#include "Audio.h" + +Audio audio; + +#define USE_TWO_ETH_PORTS 0 +#define ETH_PHY_TYPE ETH_PHY_W5500 + +// GPIOs +#define ETH_PHY_ADDR 1 +#define ETH_PHY_CS 3 +#define ETH_PHY_IRQ 8 +#define ETH_PHY_RST 4 +#define ETH_SPI_SCK 7 +#define ETH_SPI_MISO 6 +#define ETH_SPI_MOSI 5 +#define I2S_DOUT 12 +#define I2S_BCLK 13 +#define I2S_LRC 14 + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) { + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + ETH.setHostname("esp32-eth0"); //set eth hostname here + break; + case ARDUINO_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; + case ARDUINO_EVENT_ETH_GOT_IP: Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); Serial.println(ETH); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: break; + } +} + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + Serial.print("\n\n"); + + Network.onEvent(onEvent); + + SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); + ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI); + while (!eth_connected) delay(100); + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(21); // default 0...21 + audio.connecttohost("https://wdr-wdr2-ruhrgebiet.icecastssl.wdr.de/wdr/wdr2/ruhrgebiet/mp3/128/stream.mp3"); // mp3 +} + +void loop(){ + audio.loop(); + vTaskDelay(5 /portTICK_PERIOD_MS); +} diff --git a/libraries/ESP32-audioI2S/examples/Ethernet/WT32-ETH01.ino b/libraries/ESP32-audioI2S/examples/Ethernet/WT32-ETH01.ino new file mode 100644 index 0000000..3c7eb84 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/Ethernet/WT32-ETH01.ino @@ -0,0 +1,88 @@ + +#include "Arduino.h" +#include "Audio.h" +#include "SD.h" +#include "FS.h" + +// Digital I/O used +#define SD_CS 5 +#define SPI_MOSI 2 +#define SPI_MISO 4 +#define SPI_SCK 17 +#define I2S_DOUT 12 +#define I2S_BCLK 14 +#define I2S_LRC 15 + +#define ETH_PHY_TYPE ETH_PHY_LAN8720 +#define ETH_PHY_MDC 23 +#define ETH_PHY_MDIO 18 + +#ifdef CONFIG_IDF_TARGET_ESP32 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN +#endif + +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#define ETH_CLK_MODE EMAC_CLK_EXT_IN +#endif + +#include "ETH.h" + +Audio audio; + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event) { + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + // The hostname must be set after the interface is started, but needs + // to be set before DHCP, so set it from the event handler thread. + ETH.setHostname("esp32-ethernet"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.println("ETH Got IP"); + Serial.println(ETH); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: break; + } +} + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH); + SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); + Serial.begin(115200); + SD.begin(SD_CS); + + Network.onEvent(onEvent); + ETH.begin(); + while (!eth_connected) delay(100); + // Eth Connected, + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(21); // default 0...21 + audio.connecttohost("https://wdr-wdr2-ruhrgebiet.icecastssl.wdr.de/wdr/wdr2/ruhrgebiet/mp3/128/stream.mp3"); // mp3 +} + +void loop(){ + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/AudioResampler.hpp b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/AudioResampler.hpp new file mode 100644 index 0000000..20dfa75 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/AudioResampler.hpp @@ -0,0 +1,159 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "esp_log.h" + + +class AudioResampleBuffer { +public: + static constexpr size_t FIFO_SIZE_BYTES = 16384; // Muss Vielfaches von 4 sein (Stereo, 16 Bit) + static constexpr size_t I2S_BLOCK_SIZE = 512; // DMA Blockgröße + + + AudioResampleBuffer() + :fifoWrite(0), fifoRead(0), m_resampleCursor(0.0f) { + memset(fifo, 0, sizeof(fifo)); + memset(m_inputHistory, 0, sizeof(m_inputHistory)); + } + void setChannelHandle(i2s_chan_handle_t i2sHandle){ + m_i2s = i2sHandle; + } + + // Set the input samplerates (updated by the LRCK monitoring) + void setInputSamplerate(uint32_t samplerate) { + if (samplerate == 8000 || samplerate == 22050 || samplerate == 44100 || samplerate == 48000) { + m_sampleRate = samplerate; + ESP_LOGI("ResampleBuffer", "Input samplerate set to %u Hz", samplerate); + } else { + ESP_LOGW("ResampleBuffer", "Invalid samplerate %u Hz, defaulting to 44100 Hz", samplerate); + m_sampleRate = 44100; + } + } + + // Muss zyklisch aufgerufen werden (z. B. aus Task) + void loopResample() { + alignas(4) uint8_t i2sBuf[I2S_BLOCK_SIZE]; + size_t bytesRead = 0; + if (i2s_channel_read(m_i2s, i2sBuf, I2S_BLOCK_SIZE, &bytesRead, 50) != ESP_OK || bytesRead == 0) + return; + + size_t inSamples = bytesRead / 4; // Stereo, 16 Bit + int16_t* inData = reinterpret_cast(i2sBuf); + + int16_t resampled[1024]; + size_t outSamples = resampleTo441Stereo(inData, inSamples, resampled); + size_t outBytes = outSamples * 4; + + if (fifoFree() >= outBytes) { + fifoWriteBytes(reinterpret_cast(resampled), outBytes); + } else { + vTaskDelay(100); + // ESP_LOGW("ResampleBuffer", "FIFO voll, Daten verworfen %i Bytes", outBytes - fifoFree()); + } + } + + // Bluetooth Callback: muss exakt "bytes" liefern + int32_t getData(uint8_t* data, int32_t bytes) { + while (fifoAvailable() < static_cast(bytes)) { + vTaskDelay(1); + } + fifoReadBytes(data, bytes); + return bytes; + } + +private: +private: + i2s_chan_handle_t m_i2s; + uint8_t fifo[FIFO_SIZE_BYTES]; + size_t fifoWrite; + size_t fifoRead; + float m_sampleRate = 44100.0f; + + float m_resampleCursor; + int16_t m_inputHistory[6]; // 3 Stereo-Samples + + size_t fifoAvailable() const { + return (fifoWrite + FIFO_SIZE_BYTES - fifoRead) % FIFO_SIZE_BYTES; + } + + size_t fifoFree() const { + return FIFO_SIZE_BYTES - fifoAvailable() - 1; + } + + void fifoWriteBytes(const uint8_t* data, size_t len) { + for (size_t i = 0; i < len; ++i) { + fifo[fifoWrite] = data[i]; + fifoWrite = (fifoWrite + 1) % FIFO_SIZE_BYTES; + } + } + + void fifoReadBytes(uint8_t* out, size_t len) { + for (size_t i = 0; i < len; ++i) { + out[i] = fifo[fifoRead]; + fifoRead = (fifoRead + 1) % FIFO_SIZE_BYTES; + } + } + + // Catmull-Rom Spline Resampling von 48 kHz auf 44,1 kHz + size_t resampleTo441Stereo(const int16_t* input, size_t inputSamples, int16_t* output) { + float ratio = m_sampleRate / 44100.0f; + float cursor = m_resampleCursor; + + size_t extendedSamples = inputSamples + 3; + std::vector extendedInput(extendedSamples * 2); + + memcpy(&extendedInput[0], m_inputHistory, 6 * sizeof(int16_t)); + memcpy(&extendedInput[6], input, inputSamples * 2 * sizeof(int16_t)); + + size_t outputIndex = 0; + + auto catmullRom = [](float t, float xm1, float x0, float x1, float x2) { + return 0.5f * ( + (2.0f * x0) + + (-xm1 + x1) * t + + (2.0f * xm1 - 5.0f * x0 + 4.0f * x1 - x2) * t * t + + (-xm1 + 3.0f * x0 - 3.0f * x1 + x2) * t * t * t + ); + }; + + auto clip = [](float v) -> int16_t { + return v > 32767.0f ? 32767 : (v < -32768.0f ? -32768 : static_cast(v)); + }; + + for (size_t inIdx = 1; inIdx < extendedSamples - 2; ++inIdx) { + int16_t xm1_l = extendedInput[(inIdx - 1) * 2]; + int16_t x0_l = extendedInput[(inIdx + 0) * 2]; + int16_t x1_l = extendedInput[(inIdx + 1) * 2]; + int16_t x2_l = extendedInput[(inIdx + 2) * 2]; + + int16_t xm1_r = extendedInput[(inIdx - 1) * 2 + 1]; + int16_t x0_r = extendedInput[(inIdx + 0) * 2 + 1]; + int16_t x1_r = extendedInput[(inIdx + 1) * 2 + 1]; + int16_t x2_r = extendedInput[(inIdx + 2) * 2 + 1]; + + while (cursor < 1.0f) { + float t = cursor; + output[outputIndex * 2] = clip(catmullRom(t, xm1_l, x0_l, x1_l, x2_l)); + output[outputIndex * 2 + 1] = clip(catmullRom(t, xm1_r, x0_r, x1_r, x2_r)); + ++outputIndex; + cursor += ratio; + } + cursor -= 1.0f; + } + + // Historie sichern + for (int i = 0; i < 3; ++i) { + size_t idx = inputSamples - 3 + i; + m_inputHistory[i * 2] = input[idx * 2]; + m_inputHistory[i * 2 + 1] = input[idx * 2 + 1]; + } + + m_resampleCursor = cursor; + return outputIndex; + } +}; diff --git a/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/README.md b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/README.md new file mode 100644 index 0000000..0d461f8 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/README.md @@ -0,0 +1,26 @@ + +**I2S Bluetooth Transmitter** + +Such boards can be connected directly to the I2S output:
+But to do this, `#define SR_48K` must be activated in Audio.h so that the I2S frequency is always 48KHz. + +![image](https://github.com/user-attachments/assets/9e2d8066-f41e-41eb-9db5-e7b7a6e554e8) + +If you still have an old ESP32 in your box, you can use it to simulate this board. PSRAM is not required. + +The BT transmitter is the slave and is connected in this way, the DAC serves as an analogue output, but is not necessary. + +![image](https://github.com/user-attachments/assets/ac17cfa3-e473-4750-94ce-ee218827b3c3) + + +The ESP32-A2DP library is used by P. Schatzmann, https://github.com/pschatzmann/ESP32-A2DP.git + +As the I2S output of the audioI2S library not always outputs 44.1KHz, it is scaled internally to 44.1KHz for compatibility. 8000Hz, 22050Hz, 44100Hz and 48000Hz are possible. +This is necessary because the ESP32 BT library expects this sample rate. This means that old BT devices can also be used. +It doesn't matter what sample rate the audio source has. + +![image](https://github.com/user-attachments/assets/0009dd9d-96b2-48b7-a6cc-bfc45dbc94d0) + +Test circuit: the audioI2S library is running on the left, the BT transmitter on the right + + diff --git a/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/main.cpp b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/main.cpp new file mode 100644 index 0000000..0c0f807 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2S Bluetooth Transmitter/main.cpp @@ -0,0 +1,168 @@ +#include "Arduino.h" +/* + I2S Bluetooth Transmitter + Can be connected to an I2S Master.Sampling rate must be 48KHz + Include PSchatzmann /ESP32-A2DP https://github.com/pschatzmann/ESP32-A2DP.git +*/ + +#include "Arduino.h" +#include "esp_bt.h" +#include "BluetoothA2DPCommon.h" +#include "BluetoothA2DPSource.h" +#include +#include "AudioResampler.hpp" + +#define RX_I2S_DIN 25 // connect with I2S Master (signal dout) +#define RX_I2S_BCLK 27 // connect with I2S Master (bit clock) +#define RX_I2S_LRC 26 // connect with I2S Master (word select) + +#define MEASUREMENT_INTERVAL_MS 100 // Messintervall in ms +#define TOLERANCE_PERCENT 5 // Toleranz für Schwankungen in % +static volatile uint32_t lrck_count = 0; +static uint32_t current_samplerate = 0; + +BluetoothA2DPSource a2dp_source; +AudioResampleBuffer resampler; + +char BT_SINK_NAME[] = " Pebble V3\r\n"; // set your sink devicename here +//char BT_SINK_NAME[] = "Manhattan-165327"; + +i2s_chan_handle_t i2s_rx_handle = {}; +i2s_chan_config_t i2s_chan_cfg = {}; // stores I2S channel values +i2s_std_config_t i2s_std_cfg = {}; // stores I2S driver values + +const i2s_port_t i2s_num = I2S_NUM_0; + +//--------------------------------Recognise Host Samplerate------------------------------------------------------------------------------------- +// Interrupt-Handler for LRCK-Pulse +void IRAM_ATTR lrck_interrupt_handler(void *arg) { + lrck_count+=1; +} + +// Initialize GPIO interrupt for LRCK +void init_lrck_monitor() { + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << RX_I2S_LRC), + .mode = GPIO_MODE_INPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_POSEDGE // Interrupt bei steigender Flanke + }; + gpio_config(&io_conf); + gpio_install_isr_service(0); + gpio_isr_handler_add((gpio_num_t)RX_I2S_LRC, lrck_interrupt_handler, NULL); +} + +// calculate samplerates based on LRCK counter +uint32_t measure_samplerate() { + lrck_count = 0; + vTaskDelay(MEASUREMENT_INTERVAL_MS / portTICK_PERIOD_MS); + uint32_t samplerate = (lrck_count * 1000) / MEASUREMENT_INTERVAL_MS; // Hz + return samplerate; +} + +// check whether samplerates are one of the expected values +uint32_t map_to_valid_samplerate(uint32_t measured) { + const uint32_t valid_rates[] = {8000, 22050, 44100, 48000}; + const uint32_t num_rates = sizeof(valid_rates) / sizeof(valid_rates[0]); + uint32_t closest_rate = valid_rates[0]; + int min_diff = abs((int)measured - (int)valid_rates[0]); + + for (int i = 1; i < num_rates; i++) { + int diff = abs((int)measured - (int)valid_rates[i]); + if (diff < min_diff) { + min_diff = diff; + closest_rate = valid_rates[i]; + } + } + + // check tolerance + if (min_diff <= (closest_rate * TOLERANCE_PERCENT / 100)) { + return closest_rate; + } + return 0; // Invalid samplerates +} + +// task to monitor the samplerates +void samplerate_monitor_task(void *pvParameters) { + init_lrck_monitor(); + + while (1) { + uint32_t new_samplerate = map_to_valid_samplerate(measure_samplerate()); + + if (new_samplerate != 0 && new_samplerate != current_samplerate) { + log_w("Samplerate changed to %u Hz", new_samplerate); + resampler.setInputSamplerate(new_samplerate); + // response to samplerates change + if (new_samplerate == 48000) { + log_w("Activating resampling to 44100 Hz"); + // activate resampling logic here + } else if (new_samplerate == 44100) { + log_w("No resampling needed"); + // deactivate Resampling, direct transmission + } else { + log_w("Unsupported samplerate: %u Hz", new_samplerate); + // treat 8000 or 22050 Hz, if necessary + } + current_samplerate = new_samplerate; + } + + vTaskDelay(500 / portTICK_PERIOD_MS); // Prüfe alle 500 ms + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void i2s_install(){ + + i2s_chan_cfg.id = (i2s_port_t)i2s_num; // I2S_NUM_AUTO, I2S_NUM_0, I2S_NUM_1 + i2s_chan_cfg.role = I2S_ROLE_SLAVE; // I2S controller slave role, bclk and lrc signal will be set to input + i2s_chan_cfg.dma_desc_num = 8; // number of DMA buffer + i2s_chan_cfg.dma_frame_num = 512; // I2S frame number in one DMA buffer. + i2s_chan_cfg.auto_clear = true; // i2s will always send zero automatically if no data to send + i2s_new_channel(&i2s_chan_cfg, NULL, &i2s_rx_handle); + + i2s_std_cfg.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO); // Set to enable bit shift in Philips mode + i2s_std_cfg.gpio_cfg.bclk = (gpio_num_t)RX_I2S_BCLK; // BCLK Assignment + i2s_std_cfg.gpio_cfg.din = (gpio_num_t)RX_I2S_DIN; // DIN Assignment + i2s_std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED; // + i2s_std_cfg.gpio_cfg.mclk = I2S_GPIO_UNUSED; // + i2s_std_cfg.gpio_cfg.ws = (gpio_num_t)RX_I2S_LRC; // LRC Assignment + i2s_std_cfg.gpio_cfg.invert_flags.mclk_inv = false; + i2s_std_cfg.gpio_cfg.invert_flags.bclk_inv = false; + i2s_std_cfg.gpio_cfg.invert_flags.ws_inv = false; + i2s_std_cfg.clk_cfg.sample_rate_hz = 44800; + i2s_std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_DEFAULT; // Select PLL_F160M as the default source clock + i2s_std_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_128; // + i2s_channel_init_std_mode(i2s_rx_handle, &i2s_std_cfg); + i2s_channel_enable(i2s_rx_handle); +} + +//---------------------------------------------CallBacks-------------------------------------------------------------------- + +int32_t get_data(uint8_t *data, int32_t bytes) { + return resampler.getData(data, bytes); // Holt exakt die benötigten Daten +} + +// gets called when button on bluetooth speaker is pressed +void button_handler(uint8_t id, bool isReleased){ + if (isReleased) { + Serial.print("button id "); + Serial.print(id); + Serial.println(" released"); + } +} +//---------------------------------------------SETUP-------------------------------------------------------------------- +void setup(){ + Serial.begin(115200); + i2s_install(); + a2dp_source.set_data_callback(get_data); + a2dp_source.set_avrc_passthru_command_callback(button_handler); + a2dp_source.start(BT_SINK_NAME); + resampler.setChannelHandle(i2s_rx_handle); + xTaskCreate(samplerate_monitor_task, "samplerate_monitor", 2048, NULL, 5, NULL); +} +//----------------------------------------------LOOP-------------------------------------------------------------------- +void loop() { + vTaskDelay(1); + resampler.loopResample(); +} \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/examples/I2Saudio_GoogleTTS/I2Saudio_GoogleTTS.cpp b/libraries/ESP32-audioI2S/examples/I2Saudio_GoogleTTS/I2Saudio_GoogleTTS.cpp new file mode 100644 index 0000000..1132856 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2Saudio_GoogleTTS/I2Saudio_GoogleTTS.cpp @@ -0,0 +1,31 @@ +#include "Arduino.h" +#include "Audio.h" +#include "WiFi.h" + +#define I2S_DOUT 9 +#define I2S_BCLK 3 +#define I2S_LRC 1 + +Audio audio; + +String ssid = "*****"; +String password = "*****"; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + WiFi.begin(ssid.c_str(), password.c_str()); + while (WiFi.status() != WL_CONNECTED) delay(1500); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(12); // default 0...21 + audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de"); // Google TTS +} + +void loop() { + audio.loop(); + vTaskDelay(1); +} diff --git a/libraries/ESP32-audioI2S/examples/I2Saudio_OpenAI/I2Saudio_OpenAI.cpp b/libraries/ESP32-audioI2S/examples/I2Saudio_OpenAI/I2Saudio_OpenAI.cpp new file mode 100644 index 0000000..2f9c7a6 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2Saudio_OpenAI/I2Saudio_OpenAI.cpp @@ -0,0 +1,30 @@ +#include "Arduino.h" +#include "Audio.h" +#include "WiFi.h" + +#define I2S_DOUT 9 +#define I2S_BCLK 3 +#define I2S_LRC 1 + +Audio audio; + +String ssid = "*****"; +String password = "*****"; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + WiFi.begin(ssid.c_str(), password.c_str()); + while (WiFi.status() != WL_CONNECTED) delay(1500); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(12); // default 0...21 + audio.openai_speech("openAI-key", "tts-1", "Today is a wonderful day to build something people love!", "", "shimer", "mp3", "1");} + +void loop() { + audio.loop(); + vTaskDelay(1); +} diff --git a/libraries/ESP32-audioI2S/examples/I2Saudio_SD/I2Saudio_SD.cpp b/libraries/ESP32-audioI2S/examples/I2Saudio_SD/I2Saudio_SD.cpp new file mode 100644 index 0000000..6215a43 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2Saudio_SD/I2Saudio_SD.cpp @@ -0,0 +1,53 @@ +//********************************************************************************************************** +//* audioI2S-- I2S audiodecoder for ESP32, * +//********************************************************************************************************** +// +// first release on 11/2018 +// Version 4 , Aug.22/2025 +// +// +// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. +// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR +// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +// + +#include "Arduino.h" +#include "Audio.h" +#include "SPI.h" +#include "SD.h" +#include "FS.h" + +// Digital I/O used +#define SD_CS 5 +#define SPI_MOSI 23 +#define SPI_MISO 19 +#define SPI_SCK 18 +#define I2S_DOUT 25 +#define I2S_BCLK 27 +#define I2S_LRC 26 + +Audio audio; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + pinMode(SD_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); + SPI.setFrequency(1000000); + Serial.begin(115200); + SD.begin(SD_CS); + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(12); // 0...21 + audio.connecttoFS(SD, "test.wav"); +} + +void loop(){ + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/I2Saudio_SD_MMC/I2Saudio_SD_MMC.cpp b/libraries/ESP32-audioI2S/examples/I2Saudio_SD_MMC/I2Saudio_SD_MMC.cpp new file mode 100644 index 0000000..b1b2d3b --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/I2Saudio_SD_MMC/I2Saudio_SD_MMC.cpp @@ -0,0 +1,38 @@ +#include "Arduino.h" +#include "Audio.h" +#include "SD_MMC.h" + +#define I2S_DOUT 9 +#define I2S_BCLK 3 +#define I2S_LRC 1 +#define SD_MMC_D0 11 +#define SD_MMC_CLK 13 +#define SD_MMC_CMD 14 + +Audio audio; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + pinMode(SD_MMC_D0, INPUT_PULLUP); + SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0); + SD_MMC.begin("/sdcard", true); + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(12); // default 0...21 + audio.connecttoFS(SD_MMC, "/test.wav"); +} + +void loop() { + audio.loop(); + vTaskDelay(1); +} + +// optional +void audio_info(const char *info){ + Serial.print("info "); Serial.println(info); +} \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/examples/M5Core2/M5Core2.ino b/libraries/ESP32-audioI2S/examples/M5Core2/M5Core2.ino new file mode 100644 index 0000000..d69b564 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/M5Core2/M5Core2.ino @@ -0,0 +1,77 @@ +//********************************************************************************************************** +//* audioI2S-- I2S audiodecoder for M5Stack Core2 * +//********************************************************************************************************** +// +// first release on May.12/2021 +// +// +// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. +// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR +// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +// + +#include +#include "Audio.h" + +// Digital I/O used +#define SD_CS 4 +#define SD_MOSI 23 +#define SD_MISO 38 +#define SD_SCK 18 +#define I2S_DOUT 2 +#define I2S_BCLK 12 +#define I2S_LRC 0 + +Audio audio; +String ssid = "xxxxxx"; +String password = "xxxxxx"; + + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + M5.begin(true, true, true, true); + M5.Axp.SetSpkEnable(true); + M5.Lcd.fillScreen(BLACK); + M5.Lcd.setTextColor(WHITE); + M5.Lcd.setTextSize(2); + + pinMode(SD_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + SPI.begin(SD_SCK, SD_MISO, SD_MOSI); + SPI.setFrequency(1000000); + SD.begin(SD_CS); + + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(15); // 0...21 + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + while (!WiFi.isConnected()) { + delay(10); + } + ESP_LOGI(TAG, "Connected"); + ESP_LOGI(TAG, "Starting MP3...\n"); + +// audio.connecttoFS(SD, "/320k_test.mp3"); +// audio.connecttoFS(SD, "test.wav"); + audio.connecttohost("http://air.ofr.fm:8008/jazz/mp3/128"); +// audio.connecttospeech("Миска вареників з картоплею та шкварками, змащених салом!", "uk-UA"); +} + +void loop() { + vTaskDelay(1); + audio.loop(); + if(Serial.available()){ // put streamURL in serial monitor + audio.stopSong(); + String r=Serial.readString(); + r.trim(); + if(r.length()>5) audio.connecttohost(r.c_str()); + log_i("free heap=%i", ESP.getFreeHeap()); + } +} diff --git a/libraries/ESP32-audioI2S/examples/M5StackNode/M5StackNode.ino b/libraries/ESP32-audioI2S/examples/M5StackNode/M5StackNode.ino new file mode 100644 index 0000000..3d9ec8d --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/M5StackNode/M5StackNode.ino @@ -0,0 +1,53 @@ + +// M5Stack Node support +// thanks to Cellie - issue #35 25.Apr.2020 +// M5Stack board with Node base also need a MCLK signal on GPIO0. + +#include /* https://github.com/CelliesProjects/wm8978-esp32 */ +#include /* https://github.com/schreibfaul1/ESP32-audioI2S */ + +/* M5Stack Node WM8978 I2C pins */ +#define I2C_SDA 21 +#define I2C_SCL 22 + +/* M5Stack Node I2S pins */ +#define I2S_BCK 5 +#define I2S_WS 13 +#define I2S_DOUT 2 +#define I2S_DIN 34 + +/* M5Stack WM8978 MCLK gpio number */ +#define I2S_MCLKPIN 0 + +WM8978 dac; +Audio audio; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + /* Setup wm8978 I2C interface */ + if (!dac.begin(I2C_SDA, I2C_SCL)) { + log_e("Error setting up dac. System halted"); + while (1) delay(100); + } + + dac.setSPKvol(40); /* max 63 */ + dac.setHPvol(32, 32); + + /* Setup wm8978 I2S interface */ + audio.setPinout(I2S_BCK, I2S_WS, I2S_DOUT, I2S_MCLKPIN); + + WiFi.begin("xxx", "xxx"); + while (!WiFi.isConnected()) { delay(10); } + + log_i("Connected\nStarting MP3...\n"); + audio.connecttohost("http://icecast.omroep.nl/3fm-bb-mp3"); +} + +void loop() { + vTaskDelay(1); + audio.loop(); +} diff --git a/libraries/ESP32-audioI2S/examples/M5StickCPlus/M5StickCPlus.ino b/libraries/ESP32-audioI2S/examples/M5StickCPlus/M5StickCPlus.ino new file mode 100644 index 0000000..4f98f84 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/M5StickCPlus/M5StickCPlus.ino @@ -0,0 +1,59 @@ +//********************************************************************************************************** +//* audioI2S-- I2S audiodecoder for M5StickC Plus and SPK HAT * +//********************************************************************************************************** +// +// first release on May.12/2021 +// +// +// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. +// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR +// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +// + +#include +#include "Audio.h" + +Audio audio = Audio(true); + +String ssid = "xxxxxxxx"; +String password = "xxxxxxxx"; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + M5.begin(false); // Lcd disabled to reduce noise + M5.Axp.ScreenBreath(1); // Lower Lcd backlight + pinMode(36, INPUT); + gpio_pulldown_dis(GPIO_NUM_25); + gpio_pullup_dis(GPIO_NUM_25); + M5.Beep.tone(44100); // Built-in buzzer tone + M5.Beep.end(); // disabled + + audio.setVolume(15); // 0...21 + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + while (!WiFi.isConnected()) { delay(10); } + ESP_LOGI(TAG, "Connected"); + ESP_LOGI(TAG, "Starting MP3...\n"); + + audio.connecttohost("http://air.ofr.fm:8008/jazz/mp3/128"); + // audio.connecttospeech("Миска вареників з картоплею та шкварками, змащених салом!", "uk-UA"); +} + +void loop() { + vTaskDelay(1); + audio.loop(); + if(Serial.available()){ // put streamURL in serial monitor + audio.stopSong(); + String r=Serial.readString(); + r.trim(); + if(r.length()>5) audio.connecttohost(r.c_str()); + log_i("free heap=%i", ESP.getFreeHeap()); + } +} diff --git a/libraries/ESP32-audioI2S/examples/biquad/biquad.py b/libraries/ESP32-audioI2S/examples/biquad/biquad.py new file mode 100644 index 0000000..7564916 --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/biquad/biquad.py @@ -0,0 +1,44 @@ +import numpy as np +# import matplotlib +# matplotlib.use("TkAgg") # oder "QtAgg", falls Qt installiert ist +import matplotlib.pyplot as plt +from scipy.signal import freqz + +# ========================= +# PARAMETER +# ========================= +fs = 44100 # Samplerate +N = 8192 # FFT-Auflösung + +# Liste von Biquads (Reihenfolge = Signalfluss) +biquads = [ +([1.026721, -1.919612, 0.901093], [1.0, -1.922258, 0.925168]), # LOWSHELF +([0.802626, -1.424665, 0.670208 ], [1.0, -1.424665, 0.472834 ]), # PEAKINGEQ +([2.092489, -2.262849, 0.808592], [1.0, -0.597000, 0.235232]), # HIGHSHELF +] + +w = np.linspace(0, np.pi, N) +H = np.ones_like(w, dtype=complex) + +for b, a in biquads: + _, h = freqz(b, a, worN=w) + H *= h + +f = w * fs / (2*np.pi) +mag_db = 20 * np.log10(np.abs(H) + 1e-12) + +# ========================= +# PLOT +# ========================= +plt.figure(figsize=(9,5)) +plt.semilogx(f, mag_db) +plt.xlim(20, fs/2) +plt.ylim(-15, 15) +plt.grid(True, which='both') +plt.xlabel("Frequency (Hz)") +plt.ylabel("Amplitude (dB)") +plt.title("Biquad frequency response") +plt.tight_layout() +# plt.show() +plt.savefig("biquad_response.png", dpi=150) +print("Plot gespeichert als biquad_response.png") \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/examples/biquad/biquad_response.png b/libraries/ESP32-audioI2S/examples/biquad/biquad_response.png new file mode 100644 index 0000000..2dd5458 Binary files /dev/null and b/libraries/ESP32-audioI2S/examples/biquad/biquad_response.png differ diff --git a/libraries/ESP32-audioI2S/examples/plays all files in a directory/plays_all_files_in_a_directory.ino b/libraries/ESP32-audioI2S/examples/plays all files in a directory/plays_all_files_in_a_directory.ino new file mode 100644 index 0000000..0f4a8fd --- /dev/null +++ b/libraries/ESP32-audioI2S/examples/plays all files in a directory/plays_all_files_in_a_directory.ino @@ -0,0 +1,98 @@ +#include "Arduino.h" +#include "Audio.h" +#include "SD_MMC.h" +#include "FS.h" +#include + +#define I2S_LRC 26 +#define I2S_DOUT 25 +#define I2S_BCLK 27 + +#define SD_MMC_D0 2 +#define SD_MMC_CLK 14 +#define SD_MMC_CMD 15 + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels); //proto +std::vector v_audioContent; +int pirPin = 4; +Audio audio; + +File dir; +const char audioDir[] = "/mp3"; + +void my_audio_info(Audio::msg_t m) { + Serial.printf("%s: %s\n", m.s, m.msg); +} + +void setup() { + Audio::audio_info_callback = my_audio_info; + Serial.begin(115200); + pinMode(SD_MMC_D0, INPUT_PULLUP); + SD_MMC.setPins(SD_MMC_CLK,SD_MMC_CMD, SD_MMC_D0); + if(!SD_MMC.begin( "/sdmmc", true, false, 20000)){ + Serial.println("Card Mount Failed"); + return; + } + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(17); // 0...21 Will need to add a volume setting in the app + dir = SD_MMC.open(audioDir); + listDir(SD_MMC, audioDir, 1); + if(v_audioContent.size() > 0){ + const char* s = (const char*)v_audioContent[v_audioContent.size() -1]; + Serial.printf("playing %s\n", s); + audio.connecttoFS(SD_MMC, s); + v_audioContent.pop_back(); + } +} + +void loop(){ + audio.loop(); + vTaskDelay(1); // Audio is distoreted without this +} + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.println(file.size()); + v_audioContent.insert(v_audioContent.begin(), strdup(file.path())); + } + file = root.openNextFile(); + } + Serial.printf("num files %i", v_audioContent.size()); + root.close(); + file.close(); +} + +void vector_clear_and_shrink(vector&vec){ + uint size = vec.size(); + for (int i = 0; i < size; i++) { + if(vec[i]){ + free(vec[i]); + vec[i] = NULL; + } + } + vec.clear(); + vec.shrink_to_fit(); +} diff --git a/libraries/ESP32-audioI2S/library.json b/libraries/ESP32-audioI2S/library.json new file mode 100644 index 0000000..aaa9fc6 --- /dev/null +++ b/libraries/ESP32-audioI2S/library.json @@ -0,0 +1,23 @@ +{ + "name": "ESP32-audioI2S", + "version": "3.4.6", + "description": "With this library You can easily build a WebRadio with a ESP32 board and a I2S-module", + "keywords": "audio, i2s, esp32, esp32-s3, esp32-p4", + "repository": { + "type": "git", + "url": "https://github.com/schreibfaul1/ESP32-audioI2S.git" + }, + "authors": [ + { + "name": "schreibfaul1" + } + ], + "license": "GPL-3.0", + "homepage": "https://github.com/schreibfaul1/ESP32-audioI2S", + "dependencies": {}, + "frameworks": [ + "arduino", + "espidf" + ], + "platforms": "espressif32" +} diff --git a/libraries/ESP32-audioI2S/library.properties b/libraries/ESP32-audioI2S/library.properties new file mode 100644 index 0000000..307fe9c --- /dev/null +++ b/libraries/ESP32-audioI2S/library.properties @@ -0,0 +1,9 @@ +name=ESP32-audioI2S-master +version=3.4.6 +author=schreibfaul1 +maintainer=schreibfaul1 +sentence=With this library You can easily build a audio app with a ESP32, ESP32-S3, ESP32-P4 board with PSRAM and a external DAC or I2S-BT-module. +paragraph=Data format can be only mp3, aac, flac, opus, vorbis or m4a. +category=Device Control +url=https://github.com/schreibfaul1/ESP32-audioI2S +architectures=esp32 diff --git a/libraries/ESP32-audioI2S/src/Audio.cpp b/libraries/ESP32-audioI2S/src/Audio.cpp new file mode 100644 index 0000000..36ebc42 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/Audio.cpp @@ -0,0 +1,7821 @@ + +/***************************************************************************************************************************************************** + audio.cpp + + Created on: 28.10.2018 */ +char audioI2SVers[] = "\ + Version 3.4.6z "; +/* Updated on: Jun 26, 2026 + + Author: Wolle (schreibfaul1) + Audio library for ESP32, ESP32-S3 or ESP32-P4 + Arduino Vers. V3 is mandatory + PSRAM is mandatory + external DAC is mandatory + +*****************************************************************************************************************************************************/ + +#include "Audio.h" +#include "aac_decoder/aac_decoder.h" +#include "flac_decoder/flac_decoder.h" +#include "mp3_decoder/mp3_decoder.h" +#include "opus_decoder/opus_decoder.h" +#include "psram_unique_ptr.hpp" +#include "vorbis_decoder/vorbis_decoder.h" +#include "wav_decoder/wav_decoder.h" + +// constants +constexpr size_t m_frameSizeWav = 4096; +constexpr size_t m_frameSizeMP3 = 18000; // more than one icy-metaint +constexpr size_t m_frameSizeAAC = 18000; // more than one icy-metaint +constexpr size_t m_frameSizeFLAC = UINT16_MAX; // max ogg size +constexpr size_t m_frameSizeOPUS = UINT16_MAX; // max ogg size +constexpr size_t m_frameSizeVORBIS = UINT16_MAX; // OGG length is normally 4080 bytes, but can be reach 64KB in the metadata block +constexpr size_t m_outbuffSize = 4608 * 2; +constexpr size_t m_resamplesBuffSize = m_outbuffSize * 8; // SRmin: 6KHz -> SRmax: 48K + +constexpr size_t AUDIO_STACK_SIZE = 3500; + +// static allocations for Audio task +StaticTask_t __attribute__((unused)) xAudioTaskBuffer; +StackType_t __attribute__((unused)) xAudioStack[AUDIO_STACK_SIZE]; + +// weak default implementation - can be overridden by user +__attribute__((weak)) void audio_process_i2s(int32_t* outBuff, int16_t validSamples, bool* continueI2S) { + // Default: do nothing. User can provide their own implementation to process audio data. +} +__attribute__((weak)) void audio_process_raw_samples(int32_t* outBuff, int16_t validSamples) { + // Default: do nothing. User can provide their own implementation to process audio data. +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 A U D I O B U F F E R 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +// AudioBuffer will be allocated in PSRAM +// +// m_startPtr m_readPtr m_writePtr m_endPtr +// | |<------maxAvailableBytes----->|<--------------------- writeSpace ----------------------->| +// ▼ ▼ ▼ ▼ +// --------------------------------------------------------------------------------------------------------------- +// | <--m_mainBuffSize--> | <--m_resBuffSize --> | +// --------------------------------------------------------------------------------------------------------------- +// |<---freeSpace---->|<------------filled---------->|<-------freeSpace-------->| +// ▲ +// | +// m_buffEnd +// if resBuff is full copy data from resBuff to the beginning +// if m_readPtr >= m_buff|<---------------maxAvailableBytes-------------->| +// ▼ ▼ ▼ ▼ ▼ +// --------------------------------------------------------------------------------------------------------------- +// | <--m_mainBuffSize--> | <--m_resBuffSize --> | +// --------------------------------------------------------------------------------------------------------------- +// |<------------filled------------->|<-------freeSpace------->|<----filled---->▲ +// | +// m_buffEnd +// + +AudioBuffer::AudioBuffer() { + m_mainBuffSize = UINT16_MAX * 10; + m_resBuffSize = UINT16_MAX; +} + +AudioBuffer::~AudioBuffer() { + ; +} + +size_t AudioBuffer::getBufsize() { + return m_mainBuffSize; +} + +size_t AudioBuffer::init() { + m_buffer.alloc(m_mainBuffSize + m_resBuffSize, "AudioBuffer"); + m_log.set_name("\nAudiobuffer_Log"); + m_mutex = xSemaphoreCreateBinary(); + xSemaphoreGive(m_mutex); + m_init = true; + m_startPtr = m_buffer.get(); + m_endPtr = m_buffer.get() + m_mainBuffSize; + m_buffEnd = m_endPtr + m_resBuffSize; + reset(); + return m_mainBuffSize; +} + +void AudioBuffer::setMaxBlocksize(uint32_t mbs) { + m_maxBlockSize = mbs; +} + +size_t AudioBuffer::getMaxBlockSize() { + return m_maxBlockSize; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +size_t AudioBuffer::freeSpace() { + if (!m_init) return 0; + if (m_readPtr == m_writePtr) { + if (m_isEmpty) { return m_mainBuffSize; } + if (m_isFull) { return 0; } + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr == readPtr, writePtr {}, readPtr {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_readPtr - m_startPtr); + m_log.println(); + } + if (m_readPtr < m_writePtr) { + if (m_writePtr > m_endPtr) { + return (m_readPtr - m_startPtr); + } else { + return (m_endPtr - m_writePtr) + (m_readPtr - m_startPtr); + } + } + return m_readPtr - m_writePtr; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +size_t AudioBuffer::bufferFilled() { + if (!m_init) return 0; + xSemaphoreTake(m_mutex, portMAX_DELAY); + size_t bufferFilled = 0; + if (m_readPtr == m_writePtr) { + if (m_isEmpty) { + bufferFilled = 0; + goto end; + } + if (m_isFull) { + bufferFilled = m_mainBuffSize; + goto end; + } + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr == readPtr, writePtr {}, readPtr {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_readPtr - m_startPtr); + m_log.println(); + } + if (m_readPtr < m_writePtr) { + bufferFilled = (size_t)(m_writePtr - m_readPtr); + goto end; + } + bufferFilled = (m_endPtr - m_readPtr) + (m_writePtr - m_startPtr); +end: + xSemaphoreGive(m_mutex); + return bufferFilled; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +size_t AudioBuffer::writeSpace() { + if (!m_init) return 0; + xSemaphoreTake(m_mutex, portMAX_DELAY); + m_writeSpace = 0; + + // Check whether a complete block still fits in at the end + size_t spaceToEnd = m_buffEnd - m_writePtr; + + if (m_isFull) { + m_writeSpace = 0; + goto end; + } + + if (m_isEmpty) { + m_writeSpace = min(m_maxRet, spaceToEnd); + goto end; + } + + if (spaceToEnd == 0) { // be sure that the resBuff is full + // Only copy if the read pointer is not in the way + if (m_readPtr > m_startPtr + m_resBuffSize) { + memcpy(m_startPtr, m_endPtr, m_resBuffSize); + m_writePtr = m_startPtr + m_resBuffSize; + } + } + + if (m_writePtr < m_readPtr) { + if (m_readPtr >= m_endPtr) { // readPtr is in resBuff? + m_writeSpace = min(m_maxRet, (size_t)(m_endPtr - m_writePtr)); // writePtr does not enter resbuff, wait for copy im readspace + } else { + m_writeSpace = min(m_maxRet, (size_t)(m_readPtr - m_writePtr)); + } + goto end; + } + if (m_writePtr > m_readPtr) { + m_writeSpace = min(m_maxRet, spaceToEnd); + goto end; + } + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr == readPtr, writePtr {}, readPtr {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_readPtr - m_startPtr); + m_log.println(); + +end: + xSemaphoreGive(m_mutex); + return m_writeSpace; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +void AudioBuffer::bytesWritten(size_t bw) { + if (!m_init) return; + xSemaphoreTake(m_mutex, portMAX_DELAY); + if (!bw) goto end; + + if (bw > m_writeSpace) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writeSpace < bw, writeSpace {}, bw {}", __FILE__, __LINE__, m_writeSpace, bw); // bw must not be larger than the queried m_writeSpace + m_log.println(); + } + if (m_writePtr < m_readPtr && m_writePtr + bw > m_readPtr) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr overrruns readPtr, writePtr {}, readPtr {}, bw {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_readPtr - m_startPtr, bw); + m_log.println(); + m_writePtr = m_readPtr; + goto end; + } + if (m_writePtr + bw > m_buffEnd) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr overrruns buffEnd, writePtr {}, buffEnd {}, bw {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_buffEnd - m_startPtr, bw); + m_log.println(); + m_writePtr = m_buffEnd; + goto end; + } + + m_writePtr += bw; + if (bw) { + if (m_writePtr == m_readPtr) m_isFull = true; + m_isEmpty = false; + } + +end: + xSemaphoreGive(m_mutex); + return; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +size_t AudioBuffer::readSpace() { + if (!m_init) return 0; + xSemaphoreTake(m_mutex, portMAX_DELAY); + + if (m_readPtr >= m_endPtr && m_writePtr <= m_endPtr) { + size_t len = m_readPtr - m_endPtr; + if (m_writePtr > m_startPtr + len) { + // set new readptr + m_readPtr = m_startPtr + len; + } + } + + m_readSpace = 0; + if (m_isEmpty) { goto end; } + + if (m_isFull) { + m_readSpace = min(m_maxRet, (size_t)(m_buffEnd - m_readPtr)); + goto end; + } + + if (m_readPtr < m_writePtr) { + m_readSpace = min(m_maxRet, (size_t)(m_writePtr - m_readPtr)); + goto end; + } + + if (m_readPtr > m_writePtr) { + m_readSpace = min(m_maxRet, (size_t)(m_buffEnd - m_readPtr)); + goto end; + } + m_log.assignf("[{}:{}]" ANSI_ESC_RED " writePtr == readPtr, writePtr {}, readPtr {}", __FILE__, __LINE__, m_writePtr - m_startPtr, m_readPtr - m_startPtr); + m_log.println(); +end: + xSemaphoreGive(m_mutex); + return m_readSpace; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +void AudioBuffer::bytesWasRead(size_t br) { + if (!m_init) return; + xSemaphoreTake(m_mutex, portMAX_DELAY); + + if (!br) goto end; + + if (m_readSpace < br) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " readSpace < br, rspc {}, br {}", __FILE__, __LINE__, m_readSpace, br); // br must not be larger than the queried m_readSpace + m_log.println(); + vTaskDelay(100); + goto end; + } + + if (m_readPtr < m_writePtr && m_readPtr + br > m_writePtr) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " readPtr overrruns writePtr, readPtr {}, writePtr {}, br {}", __FILE__, __LINE__, m_readPtr - m_startPtr, m_writePtr - m_startPtr, br); + m_log.println(); + m_readPtr = m_writePtr; + vTaskDelay(100); + goto end; + } + if (m_readPtr + br > m_buffEnd) { + m_log.assignf("[{}:{}]" ANSI_ESC_RED " readPtr overrruns buffEnd, readPtr {}, buffEnd {}, bw {}", __FILE__, __LINE__, m_readPtr - m_startPtr, m_buffEnd - m_startPtr, br); + m_log.println(); + m_readPtr = m_buffEnd; + vTaskDelay(100); + goto end; + } + + m_readPtr += br; + + if (br) { + if (m_readPtr == m_writePtr) { + m_isEmpty = true; + // m_log.assignf("readPtr {}, writePtr {}, br {}", m_readPtr - m_startPtr, m_writePtr - m_startPtr, br); m_log.println(); + } + m_isFull = false; + } + +end: + xSemaphoreGive(m_mutex); + return; +} +//---------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t* AudioBuffer::getWritePtr() { + return m_writePtr; +} + +uint8_t* AudioBuffer::getReadPtr() { + return m_readPtr; +} + +void AudioBuffer::reset() { + m_writePtr = m_buffer.get(); + m_readPtr = m_buffer.get(); + m_isEmpty = true; + m_isFull = false; + m_readSpace = 0; + m_writeSpace = min(m_maxRet, (size_t)(m_buffEnd - m_writePtr)); +} + +void AudioBuffer::showStatus() { + m_log.assignf("\nfilled {}, free {}\n", bufferFilled(), freeSpace()); + m_log.appendf("writeSpace {}, readSpace {}\n", writeSpace(), readSpace()); + m_log.appendf("writePtr {}, readPtr {}\n", m_writePtr - m_startPtr, m_readPtr - m_startPtr); + m_log.appendf("isEmpty {}, isFull {}\n\n", m_isEmpty, m_isFull); + m_log.print(); +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 A U D I O 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +Audio::Audio(uint8_t i2sPort) { + + m_f_I2S_init = false; + mutex_playAudioData = xSemaphoreCreateMutex(); + mutex_audioTask = xSemaphoreCreateMutex(); + mutex_audioTaskIsDecoding = xSemaphoreCreateMutex(); + + clientsecure.setInsecure(); + m_i2s_items.i2s_num = i2sPort; // i2s port number +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +Audio::~Audio() { + stopSong(); + setDefaults(); + + i2s_channel_disable(m_i2s_tx_handle); + i2s_del_channel(m_i2s_tx_handle); + stopAudioTask(); + vSemaphoreDelete(mutex_playAudioData); + vSemaphoreDelete(mutex_audioTask); + vSemaphoreDelete(mutex_audioTaskIsDecoding); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::destroy_decoder() { + if (m_decoder && m_decoder->isValid()) { + info(*this, evt_info, "{}Decoder has been destroyed", m_decoder->whoIsIt()); + m_decoder->reset(); + m_decoder.reset(); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::unique_ptr Audio::createDecoder(const std::string& type) { + destroy_decoder(); + if (type == "MP3") return std::make_unique(*this); + if (type == "FLAC") return std::make_unique(*this); + if (type == "OPUS") return std::make_unique(*this); + if (type == "AAC") return std::make_unique(*this); + if (type == "VORBIS") return std::make_unique(*this); + if (type == "WAV") return std::make_unique(*this); + return nullptr; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::initInBuff() { + if (!InBuff.isInitialized()) { + size_t size = InBuff.init(); + if (size > 0) { info(*this, evt_info, "inputBufferSize: {} bytes", size - 1); } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +esp_err_t Audio::I2Sstart() { + zeroI2Sbuff(); + esp_err_t err = ESP_FAIL; + if (!m_f_i2s_channel_enabled) { + err = i2s_channel_enable(m_i2s_tx_handle); + if (err == ESP_OK) m_f_i2s_channel_enabled = true; + } + return err; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +esp_err_t Audio::I2Sstop() { + m_outBuff.clear(); // Clear OutputBuffer + m_resamplesBuff.clear(); // Clear m_resamplesBuff + esp_err_t err = ESP_FAIL; + if (m_f_i2s_channel_enabled) err = i2s_channel_disable(m_i2s_tx_handle); + m_f_i2s_channel_enabled = false; + return err; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::zeroI2Sbuff() { + uint8_t buff[2] = {0, 0}; // From IDF V5 there is no longer the zero_dma_buff() function. + size_t bytes_loaded = 0; // As a replacement, we write a small amount of zeros in the buffer and thus reset the entire buffer. + i2s_channel_preload_data(m_i2s_tx_handle, buff, 2, &bytes_loaded); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setDefaults() { + stopSong(); + initInBuff(); // initialize InputBuffer if not already done + + InBuff.reset(); + m_streamTitle.reset(); + m_streamURL.reset(); + m_playlistBuff.reset(); + m_m3u8_host.reset(); + + m_outBuff.clear(); // Clear OutputBuffer + m_resamplesBuff.clear(); // Clear m_resamplesBuff + m_syltTimeStamp.clear(); + + vector_clear_and_shrink(m_playlistURL); + vector_clear_and_shrink(m_playlistContent); + vector_clear_and_shrink(m_syltLines); + + client.stop(); + clientsecure.stop(); + m_client = static_cast(&client); /* default to *something* so that no NULL deref can happen */ + + m_f_timeout = false; + m_f_chunked = false; // Assume not chunked + m_f_firstmetabyte = false; + m_f_playing = false; + m_f_tts = false; + m_f_firstCall = true; // InitSequence for processWebstream and processLocalFile + m_cat.firstCall = true; // InitSequence for calculateAudioTime + m_pplM3U8.firstCall = true; // InitSequence for parsePlaylist_M3U8 + m_f_firstPlayCall = true; // InitSequence for playAudioData + m_f_firstLoop = true; + m_f_unsync = false; // set within ID3 tag but not used + m_f_exthdr = false; // ID3 extended header + m_f_rtsp = false; // RTSP (m3u8)stream + m_f_m3u8data = false; // set again in processM3U8entries() if necessary + m_f_continue = false; + m_f_ts = false; + m_f_ogg = false; + m_f_m4aID3dataAreRead = false; + m_f_stream = false; + m_f_decode_ready = false; + m_f_eof = false; + m_f_ID3v1TagFound = false; + m_f_lockInBuffer = false; + m_f_acceptRanges = false; + m_f_connectionClose = false; + m_f_allDataReceived = false; + + m_codec = CODEC_NONE; + m_dataMode = AUDIO_NONE; + m_streamType = ST_NONE; + m_playlistFormat = FORMAT_NONE; + m_m3u8Codec = CODEC_AAC; + + m_validSamples = 0; + m_audioCurrentTime = 0; + m_audioFileDuration = 0; + m_resumeFilePos = -1; + m_audioDataStart = 0; + m_audioDataSize = 0; + m_audioFileSize = 0; + m_avr_bitrate = 0; + m_nominal_bitrate = 0; + m_bytesNotConsumed = 0; // counts all not decodable bytes + m_chunkcount = 0; // for chunked streams + m_curSample = 0; + m_LFcount = 0; // For end of header detection + m_controlCounter = 0; // Status within readID3data() and readWaveHeader() + m_channels = 2; // assume stereo #209 + m_ID3Size = 0; + m_haveNewFilePos = 0; + m_validSamples = 0; + m_M4A_chConfig = 0; + m_M4A_objectType = 0; + m_M4A_sampleRate = 0; + m_lastGranulePosition = 0; + m_validSamples = 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl) { + if (timeout_ms) m_timeout_ms = timeout_ms; + if (timeout_ms_ssl) m_timeout_ms_ssl = timeout_ms_ssl; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* + Text to speech API provides a speech endpoint based on our TTS (text-to-speech) model. + More info: https://platform.openai.com/docs/guides/text-to-speech/text-to-speech + + Request body: + model (string) [Required] - One of the available TTS models: tts-1 or tts-1-hd + input (string) [Required] - The text to generate audio for. The maximum length is 4096 characters. + instructions (string) [Optional] - A description of the desired characteristics of the generated audio. + voice (string) [Required] - The voice to use when generating the audio. Supported voices are alloy, echo, fable, onyx, nova, and shimmer. + response_format (string) [Optional] - Defaults to mp3. The format to audio in. Supported formats are mp3, opus, aac, and flac. + speed (number) [Optional] - Defaults to 1. The speed of the generated audio. Select a value from 0.25 to 4.0. 1.0 is the default. + + Usage: audio.openai_speech(OPENAI_API_KEY, "tts-1", input, instructions, "shimmer", "mp3", "1"); +*/ +bool Audio::openai_speech(const String& api_key, const String& model, const String& input, const String& instructions, const String& voice, const String& response_format, const String& speed) { + ps_ptr host; + host.assign("api.openai.com"); + char path[] = "/v1/audio/speech"; + + if (input == "") { + AUDIO_LOG_WARN("input text is empty"); + stopSong(); + return false; + } + xSemaphoreTakeRecursive(mutex_playAudioData, 0.3 * configTICK_RATE_HZ); + + setDefaults(); + m_f_ssl = true; + + m_speechtxt.assign(input.c_str()); + + // Escape special characters in input + String input_clean = ""; + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c == '\"') { + input_clean += "\\\""; + } else if (c == '\n') { + input_clean += "\\n"; + } else if (c == '\r') { + input_clean += "\\r"; + } else if (c == '\t') { + input_clean += "\\t"; + } else if (c == '\\') { + input_clean += "\\\\"; + } else if (c == '\b') { + input_clean += "\\b"; + } else if (c == '\f') { + input_clean += "\\f"; + } else { + input_clean += c; + } + } + + // Escape special characters in instructions + String instructions_clean = ""; + for (int i = 0; i < instructions.length(); i++) { + char c = instructions.charAt(i); + if (c == '\"') { + instructions_clean += "\\\""; + } else if (c == '\n') { + instructions_clean += "\\n"; + } else if (c == '\r') { + instructions_clean += "\\r"; + } else if (c == '\t') { + instructions_clean += "\\t"; + } else if (c == '\\') { + instructions_clean += "\\\\"; + } else if (c == '\b') { + instructions_clean += "\\b"; + } else if (c == '\f') { + instructions_clean += "\\f"; + } else { + instructions_clean += c; + } + } + + String post_body = "{" + "\"model\": \"" + + model + "\"," + "\"stream\": true," + // add + "\"input\": \"" + input_clean + "\"," + "\"instructions\": \"" + instructions_clean + "\"," + "\"voice\": \"" + voice + "\"," + "\"response_format\": \"" + response_format + + "\"," + "\"speed\": " + speed + "}"; + + String http_request = + // "POST " + String(path) + " HTTP/1.0\r\n" // UNKNOWN ERROR CODE (0050) - crashing on HTTP/1.1 need to use HTTP/1.0 + "POST " + String(path) + " HTTP/1.1\r\n" + "Host: " + host.get() + "\r\n" + "Authorization: Bearer " + api_key + "\r\n" + "Accept-Encoding: identity;q=1,*;q=0\r\n" + + "User-Agent: nArija/1.0\r\n" + "Content-Type: application/json; charset=utf-8\r\n" + "Content-Length: " + post_body.length() + + "\r\n" + // + "Connection: close\r\n" + "\r\n" + + "\r\n" + post_body + "\r\n"; + + bool res = true; + int port = 443; + m_client = static_cast(&clientsecure); + + uint32_t t = millis(); + info(*this, evt_info, "Connect to: \"{}\"", host.get()); + res = m_client->connect(host.get(), port, m_timeout_ms_ssl); + if (res) { + uint32_t dt = millis() - t; + m_lastHost.assign(host.get()); + m_currentHost.clone_from(host); + info(*this, evt_info, "{} has been established in {} ms", m_f_ssl ? "SSL" : "Connection", dt); + m_f_running = true; + } + + m_expectedCodec = CODEC_NONE; + m_expectedPlsFmt = FORMAT_NONE; + + if (res) { + m_client->print(http_request); + if (response_format == "mp3") m_expectedCodec = CODEC_MP3; + if (response_format == "opus") m_expectedCodec = CODEC_OPUS; + if (response_format == "aac") m_expectedCodec = CODEC_AAC; + if (response_format == "flac") m_expectedCodec = CODEC_FLAC; + + m_dataMode = HTTP_RESPONSE_HEADER; + m_f_tts = true; + } else { + AUDIO_LOG_WARN("Request {} failed!", host.get()); + } + xSemaphoreGiveRecursive(mutex_playAudioData); + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +audiolib::hwoe_t Audio::dismantle_host(const char* host) { + if (!host) return {}; + + audiolib::hwoe_t result; + + const char* p = host; + + // 🔐 1. SSL check + if (strncmp(p, "https://", 8) == 0) { + result.ssl = true; + p += 8; + } else if (strncmp(p, "http://", 7) == 0) { + result.ssl = false; + p += 7; + } else { // No valid scheme -> error or acceptance http + result.ssl = false; + } + + // ❓ 2. extract host (from p to ':' or '/' or '?') + const char* host_start = p; + const char* port_sep = strchr(p, ':'); + const char* path_sep = strchr(p, '/'); + const char* query_sep = strchr(p, '?'); + + const char* host_end = p + strlen(p); // default: end of string + if (port_sep && port_sep < host_end) host_end = port_sep; + if (path_sep && path_sep < host_end) host_end = path_sep; + if (query_sep && query_sep < host_end) host_end = query_sep; + result.hwoe.copy_from(host_start, host_end - host_start); + result.rqh_host.clone_from(result.hwoe); + + // ❓ 3. extract port + result.port = result.ssl ? 443 : 80; // default + if (port_sep && (!path_sep || port_sep < path_sep)) { + result.port = atoi(port_sep + 1); + result.rqh_host.appendf(":{}", result.port); + } + + // ❓ 4. extract extension (path) + if (path_sep) { + const char* path_start = path_sep + 1; + const char* path_end = query_sep ? query_sep : host + strlen(host); + result.extension.copy_from(path_start, path_end - path_start); + } + + // ❓ 5. extract query string + if (query_sep) { result.query_string.assign(query_sep + 1); } + + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::connecttohost(const char* host, const char* user, const char* pwd) { // user and pwd for authentification only, can be empty + + ps_ptr c_host = host; // copy of host + ps_ptr c_user = user; // copy of user + ps_ptr c_pwd = pwd; // copy of password + + if (!c_host.valid()) { + AUDIO_LOG_ERROR("Hostaddress is empty"); + stopSong(); + return false; + } + + c_host.trim(); + + if (c_host.strlen() < 8) { + AUDIO_LOG_ERROR("Hostaddress is too short"); + stopSong(); + return false; + } + + if (c_host.strlen() > 2048) { + AUDIO_LOG_ERROR("Hostaddress is too long"); + stopSong(); + return false; + } // max length in Chrome DevTools + + const char* user_agent_0 = "Mozilla/5.0 (X11; Linux x86_64) Chrome/146.0.0.0 Safari/537.36"; + const char* user_agent_1 = "VLC/3.0.21 LibVLC/3.0.21 AppleWebKit/537.36 (KHTML, like Gecko)"; + + bool res = false; // return value + uint16_t port = 0; // port number + uint16_t authLen = 0; // length of authorization + uint32_t timestamp = 0; // timeout surveillance + + ps_ptr hwoe; // host without extension + ps_ptr rqh_host; // host for request header + ps_ptr extension; // extension + ps_ptr query_string; // parameter + ps_ptr path; // extension + '?' + parameter + ps_ptr rqh; // request header + + xSemaphoreTakeRecursive(mutex_playAudioData, 0.3 * configTICK_RATE_HZ); + + auto dismantledHost = dismantle_host(c_host.get()); + + // https://edge.live.mp3.mdn.newmedia.nacamar.net:8000/ps-charivariwb/livestream.mp3;?user=ps-charivariwb;&pwd=ps-charivariwb------- + // | | | | | + // | | | | | (query string) + // ssl?| |<-----host without extension-------->|port|<----- --extension----------->|<-first parameter->|<-second parameter->....... + // | + // |<-----------------------------path------------------------------------>...... + + m_f_ssl = dismantledHost.ssl; + port = dismantledHost.port; + hwoe = dismantledHost.hwoe.c_get(); + rqh_host = dismantledHost.rqh_host.c_get(); + extension = dismantledHost.extension.c_get(); + query_string = dismantledHost.query_string.c_get(); + + if (query_string.strlen()) extension.appendf("?{}", query_string); + path = urlencode(extension.get(), true); + + // optional basic authorization + if (c_user.valid() && c_pwd.valid()) authLen = c_user.strlen() + c_pwd.strlen(); + ps_ptr authorization; + ps_ptr toEncode; + authorization.calloc(base64_encode_expected_len(authLen + 1) + 1, "authorization"); + if (authLen > 0) { + toEncode.assignf("{}:{}", c_user, c_pwd); + b64encode((const char*)toEncode.get(), toEncode.strlen(), authorization.get()); + } + + setDefaults(); + + rqh.assignf("GET /{}", path); + rqh.append(" HTTP/1.1\r\n"); + rqh.appendf("Host: {}\r\n", rqh_host); + rqh.append("Icy-MetaData:1\r\n"); + rqh.append("Pragma: no-cache\r\n"); + rqh.append("Cache-Control: no-cache\r\n"); + rqh.append("Range: bytes=0-\r\n"); + rqh.append("Accept: */*\r\n"); + rqh.appendf("User-Agent: {}\r\n", m_f_alt_user_agent ? user_agent_0 : user_agent_1); + if (authLen > 0) { + rqh.append("Authorization: Basic "); + rqh.append(authorization); + rqh.append("\r\n"); + } + rqh.append("Accept-Encoding: identity;q=1,*;q=0\r\n"); + rqh.append("Connection: keep-alive\r\n\r\n"); + + if (m_f_ssl) { + m_client = static_cast(&clientsecure); + if (port == 80) port = 443; + } else { + m_client = static_cast(&client); + } + + timestamp = millis(); + m_client->setTimeout(m_f_ssl ? m_timeout_ms_ssl : m_timeout_ms); + + info(*this, evt_info, "connect to: \"{}\" on port {} path \"/{}\"", hwoe.get(), port, path.get()); + res = m_client->connect(hwoe.get(), port); + + m_expectedCodec = CODEC_NONE; + m_expectedPlsFmt = FORMAT_NONE; + + if (res) { + uint32_t dt = millis() - timestamp; + info(*this, evt_info, "{} has been established in {} ms", m_f_ssl ? "SSL" : "Connection", dt); + m_f_running = true; + m_client->print(rqh.get()); + if (extension.ends_with_icase(".mp3")) m_expectedCodec = CODEC_MP3; + if (extension.ends_with_icase(".aac")) m_expectedCodec = CODEC_AAC; + if (extension.ends_with_icase(".wav")) m_expectedCodec = CODEC_WAV; + if (extension.ends_with_icase(".m4a")) m_expectedCodec = CODEC_M4A; + if (extension.ends_with_icase(".ogg")) m_expectedCodec = CODEC_OGG; + if (extension.ends_with_icase(".flac")) m_expectedCodec = CODEC_FLAC; + if (extension.ends_with_icase("-flac")) m_expectedCodec = CODEC_FLAC; + if (extension.ends_with_icase(".opus")) m_expectedCodec = CODEC_OPUS; + if (extension.ends_with_icase("/opus")) m_expectedCodec = CODEC_OPUS; + if (extension.ends_with_icase(".asx")) m_expectedPlsFmt = FORMAT_ASX; + if (extension.ends_with_icase(".m3u")) m_expectedPlsFmt = FORMAT_M3U; + if (extension.ends_with_icase(".pls")) m_expectedPlsFmt = FORMAT_PLS; + if (extension.contains(".m3u8")) m_expectedPlsFmt = FORMAT_M3U8; + + m_currentHost = c_host; + m_lastHost = c_host; + info(*this, evt_lasthost, "{}", m_lastHost.c_get()); + m_dataMode = HTTP_RESPONSE_HEADER; // Handle header + m_streamType = ST_WEBSTREAM; + } else { + AUDIO_LOG_ERROR("Request \"{}\" failed!", c_host.get()); + m_f_running = false; + } + xSemaphoreGiveRecursive(mutex_playAudioData); + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::httpPrint(const char* host) { + + ps_ptr c_host = host; // copy of host + + if (!c_host.valid()) { + AUDIO_LOG_ERROR("Hostaddress is empty"); + stopSong(); + return false; + } + + uint16_t port = 0; // port number + ps_ptr hwoe; // host without extension + ps_ptr rqh_host; // host in request header + ps_ptr extension; // extension + ps_ptr query_string; // parameter + ps_ptr path; // extension + '?' + parameter + ps_ptr rqh; // request header + ps_ptr cur_hwoe; // m_currenthost without extension + + c_host.trim(); + auto dismantledHost = dismantle_host(c_host.get()); + + // https://edge.live.mp3.mdn.newmedia.nacamar.net:8000/ps-charivariwb/livestream.mp3;?user=ps-charivariwb;&pwd=ps-charivariwb------- + // | | | | | + // | | | | | (query string) + // ssl?| |<-----host without extension-------->|port|<----- --extension----------->|<-first parameter->|<-second parameter->....... + // | + // |<-----------------------------path-------------------------------------------> + + m_f_ssl = dismantledHost.ssl; + port = dismantledHost.port; + hwoe = dismantledHost.hwoe; + rqh_host = dismantledHost.rqh_host; + extension = dismantledHost.extension; + query_string = dismantledHost.query_string; + + if (query_string.strlen()) extension.appendf("?{}", query_string); + path = urlencode(extension.get(), true); + + if (!m_currentHost.valid()) m_currentHost.assign(""); + auto dismantledLastHost = dismantle_host(m_currentHost.get()); + cur_hwoe = dismantledLastHost.hwoe; + + bool f_equal = true; + if (hwoe == cur_hwoe && port == dismantledLastHost.port) { + f_equal = true; + } else { + f_equal = false; + } + + rqh.assignf("GET /{}", path); + rqh.append(" HTTP/1.1\r\n"); + rqh.appendf("Host: {}\r\n", rqh_host); + rqh.append("Icy-MetaData:1\r\n"); + rqh.append("Accept:*/*\r\n"); + rqh.append("User-Agent: VLC/3.0.21 LibVLC/3.0.21 AppleWebKit/537.36 (KHTML, like Gecko)\r\n"); + rqh.append("Accept-Encoding: identity;q=1,*;q=0\r\n"); + rqh.append("Connection: keep-alive\r\n\r\n"); + + info(*this, evt_info, "next URL: \"{}\"", c_host.get()); + + if (f_equal == false) { + if (m_client->connected()) m_client->stop(); + } + if (!m_client->connected()) { + if (m_f_ssl) { + m_client = static_cast(&clientsecure); + if (m_f_ssl && port == 80) port = 443; + } else { + m_client = static_cast(&client); + } + if (f_equal) info(*this, evt_info, "The host has disconnected, reconnecting"); + + if (!m_client->connect(hwoe.get(), port)) { + AUDIO_LOG_ERROR("connection lost {}", c_host.c_get()); + stopSong(); + return false; + } + } + m_currentHost = c_host; + m_client->print(rqh.get()); + + if (extension.ends_with_icase(".mp3")) + m_expectedCodec = CODEC_MP3; + else if (extension.ends_with_icase(".aac")) + m_expectedCodec = CODEC_AAC; + else if (extension.ends_with_icase(".wav")) + m_expectedCodec = CODEC_WAV; + else if (extension.ends_with_icase(".m4a")) + m_expectedCodec = CODEC_M4A; + else if (extension.ends_with_icase(".flac")) + m_expectedCodec = CODEC_FLAC; + else if (extension.ends_with_icase(".m4s")) { // is MP4-Container + stopSong(); + AUDIO_LOG_WARN("MP4-Container not supported"); + return false; + } else + m_expectedCodec = CODEC_NONE; + + if (extension.ends_with_icase(".asx")) + m_expectedPlsFmt = FORMAT_ASX; + else if (extension.ends_with_icase(".m3u")) + m_expectedPlsFmt = FORMAT_M3U; + else if (extension.contains(".m3u8")) + m_expectedPlsFmt = FORMAT_M3U8; + else if (extension.ends_with_icase(".pls")) + m_expectedPlsFmt = FORMAT_PLS; + else + m_expectedPlsFmt = FORMAT_NONE; + + m_audioFileSize = 0; + m_dataMode = HTTP_RESPONSE_HEADER; // Handle header + m_streamType = ST_WEBSTREAM; + m_f_chunked = false; + AUDIO_LOG_DEBUG("playlistFormat {}, dataMode {}, streamType: {}", plsFmtStr[m_playlistFormat], dataModeStr[m_dataMode], streamTypeStr[m_streamType]); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::httpRange(uint32_t seek, uint32_t length) { + + if (!m_f_running) return false; + + uint16_t port = 0; // port number + ps_ptr c_host; // copy of host + ps_ptr hwoe; // host without extension + ps_ptr rqh_host; // host in request header + ps_ptr extension; // extension + ps_ptr query_string; // parameter + ps_ptr path; // extension + '?' + parameter + ps_ptr rqh; // request header + ps_ptr cur_hwoe; // m_currenthost without extension + ps_ptr range; // e.g. "Range: bytes=124-" + + c_host.clone_from(m_currentHost); + c_host.trim(); + auto dismantledHost = dismantle_host(c_host.get()); + + // https://edge.live.mp3.mdn.newmedia.nacamar.net:8000/ps-charivariwb/livestream.mp3;?user=ps-charivariwb;&pwd=ps-charivariwb------- + // | | | | | + // | | | | | (query string) + // ssl?| |<-----host without extension-------->|port|<----- --extension----------->|<-first parameter->|<-second parameter->....... + // | + // |<-----------------------------path-------------------------------------------> + + m_f_ssl = dismantledHost.ssl; + port = dismantledHost.port; + if (dismantledHost.hwoe.valid()) hwoe.clone_from(dismantledHost.hwoe); + if (dismantledHost.rqh_host.valid()) rqh_host.clone_from(dismantledHost.rqh_host); + if (dismantledHost.extension.valid()) extension.clone_from(dismantledHost.extension); + if (dismantledHost.query_string.valid()) query_string.clone_from(dismantledHost.query_string); + + if (extension.valid()) path.assign(extension.get()); + if (query_string.valid()) { + path.append("?"); + path.append(query_string.get()); + } + if (!hwoe.valid()) hwoe.assign(""); + if (!extension.valid()) extension.assign(""); + if (!path.valid()) path.assign(""); + + path = urlencode(path.get(), true); + + if (!m_currentHost.valid()) m_currentHost.assign(""); + auto dismantledLastHost = dismantle_host(m_currentHost.get()); + cur_hwoe.clone_from(dismantledLastHost.hwoe); + + if (length == UINT32_MAX) + range.assignf("Range: bytes={}-\r\n", seek); + else + range.assignf("Range: bytes={}-{}\r\n", seek, seek + length); + + rqh.assignf("GET /{} HTTP/1.1\r\n", path.get()); + rqh.appendf("Host: {}\r\n", rqh_host.get()); + rqh.append("Accept: */*\r\n"); + rqh.append("Accept-Encoding: identity;q=1,*;q=0\r\n"); + rqh.append("Cache-Control: no-cache\r\n"); + rqh.append("Connection: keep-alive\r\n"); + rqh.appendf(range.c_get()); + rqh.appendf("Referer: {}\r\n", m_currentHost.c_get()); + rqh.append("Sec-GPC: 1\r\n"); + rqh.append("User-Agent: VLC/3.0.21 LibVLC/3.0.21 AppleWebKit/537.36 (KHTML, like Gecko)\r\n\r\n"); + + if (m_client->connected()) { m_client->stop(); } + if (m_f_ssl) { + m_client = static_cast(&clientsecure); + if (m_f_ssl && port == 80) port = 443; + } else { + m_client = static_cast(&client); + } + + if (!m_client->connect(hwoe.get(), port)) { + AUDIO_LOG_ERROR("connection lost {}", c_host.c_get()); + stopSong(); + return false; + } + + // AUDIO_LOG_INFO("rqh \n{}", rqh.get()); + + m_client->print(rqh.c_get()); + // m_resumeFilePos = seek; // used in processWebFile() + m_dataMode = HTTP_RANGE_HEADER; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::connecttoFS(fs::FS& fs, const char* path, int32_t fileStartTime) { + + xSemaphoreTakeRecursive(mutex_playAudioData, 0.3 * configTICK_RATE_HZ); + ps_ptr c_path; + ps_ptr audioPath; + bool res = false; + m_fileStartTime = fileStartTime; + m_codec = CODEC_NONE; + + if (!path) { + AUDIO_LOG_ERROR("file path is not set"); + goto exit; + } // guard + c_path.copy_from(path); // copy from path + c_path.trim(); + if (!c_path.contains(".")) { + AUDIO_LOG_ERROR("No file extension found"); + goto exit; + } // guard + setDefaults(); // free buffers an set defaults + + if (c_path.ends_with_icase(".mp3")) m_codec = CODEC_MP3; + if (c_path.ends_with_icase(".m4a")) m_codec = CODEC_M4A; + if (c_path.ends_with_icase(".aac")) m_codec = CODEC_AAC; + if (c_path.ends_with_icase(".wav")) m_codec = CODEC_WAV; + if (c_path.ends_with_icase(".flac")) m_codec = CODEC_FLAC; + if (c_path.ends_with_icase(".opus")) m_codec = CODEC_OGG; + if (c_path.ends_with_icase(".ogg")) m_codec = CODEC_OGG; + if (c_path.ends_with_icase(".oga")) m_codec = CODEC_OGG; + + if (m_codec == CODEC_OGG) m_f_ogg = true; + if (m_codec == CODEC_NONE) { // guard + int dotPos = c_path.last_index_of('.'); + AUDIO_LOG_WARN("The {} format is not supported", path + dotPos); + goto exit; + } + + if (!c_path.starts_with("/")) c_path.insert("/", 0); + + if (!fs.exists(c_path.get())) { + AUDIO_LOG_WARN("file not found: {}", c_path.get()); + goto exit; + } + info(*this, evt_info, "Reading file: \"{}\"", c_path.get()); + m_audiofile = fs.open(c_path.get()); + m_dataMode = AUDIO_LOCALFILE; + m_audioFileSize = m_audiofile.size(); + m_f_running = true; + res = true; + +exit: + xSemaphoreGiveRecursive(mutex_playAudioData); + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::connecttospeech(const char* speech, const char* lang) { + xSemaphoreTakeRecursive(mutex_playAudioData, 0.3 * configTICK_RATE_HZ); + + setDefaults(); + char host[] = "translate.google.com.vn"; + char path[] = "/translate_tts"; + + m_speechtxt.assign(speech); // unique pointer takes care of the memory management + auto urlStr = urlencode(speech, false); // percent encoding + + ps_ptr req; // request header + req.assign("GET "); + req.append(path); + req.append("?ie=UTF-8&tl="); + req.append(lang); + req.append("&client=tw-ob&q="); + req.append(urlStr.get()); + req.append(" HTTP/1.1\r\n"); + req.append("Host: "); + req.append(host); + req.append("\r\n"); + req.append("User-Agent: Mozilla/5.0 \r\n"); + req.append("Accept-Encoding: identity\r\n"); + req.append("Accept: text/html\r\n"); + req.append("Connection: close\r\n\r\n"); + + m_client = static_cast(&client); + info(*this, evt_info, "connect to \"{}\"", host); + if (!m_client->connect(host, 80)) { + AUDIO_LOG_ERROR("Connection failed"); + xSemaphoreGiveRecursive(mutex_playAudioData); + return false; + } + m_client->print(req.get()); + + m_f_running = true; + m_f_ssl = false; + m_f_tts = true; + m_dataMode = HTTP_RESPONSE_HEADER; + m_lastHost.assign(host); + m_currentHost.copy_from(host); + xSemaphoreGiveRecursive(mutex_playAudioData); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::showID3Tag(const char* tag, const char* value) { + ps_ptr id3tag; + id3tag.set_name("id3tag"); + // V2.2 + if (!strcmp(tag, "CNT")) id3tag.assignf("Play counter: {}", value); + if (!strcmp(tag, "COM")) id3tag.assignf("Comments: {}", value); + if (!strcmp(tag, "CRA")) id3tag.assignf("Audio encryption: {}", value); + if (!strcmp(tag, "CRM")) id3tag.assignf("Encrypted meta frame: {}", value); + if (!strcmp(tag, "ETC")) id3tag.assignf("Event timing codes: {}", value); + if (!strcmp(tag, "EQU")) id3tag.assignf("Equalization: {}", value); + if (!strcmp(tag, "IPL")) id3tag.assignf("Involved people list: {}", value); + if (!strcmp(tag, "PIC")) id3tag.assignf("Attached picture: {}", value); + if (!strcmp(tag, "SLT")) id3tag.assignf("Synchronized lyric/text: {}", value); + if (!strcmp(tag, "TAL")) id3tag.assignf("Album/Movie/Show title: {}", value); + if (!strcmp(tag, "TBP")) id3tag.assignf("BPM (Beats Per Minute): {}", value); + if (!strcmp(tag, "TCM")) id3tag.assignf("Composer: {}", value); + if (!strcmp(tag, "TCO")) id3tag.assignf("Content type: {}", value); + if (!strcmp(tag, "TCR")) id3tag.assignf("Copyright message: {}", value); + if (!strcmp(tag, "TDA")) id3tag.assignf("Date: {}", value); + if (!strcmp(tag, "TDY")) id3tag.assignf("Playlist delay: {}", value); + if (!strcmp(tag, "TEN")) id3tag.assignf("Encoded by: {}", value); + if (!strcmp(tag, "TFT")) id3tag.assignf("File type: {}", value); + if (!strcmp(tag, "TIM")) id3tag.assignf("Time: {}", value); + if (!strcmp(tag, "TKE")) id3tag.assignf("Initial key: {}", value); + if (!strcmp(tag, "TLA")) id3tag.assignf("Language(s): {}", value); + if (!strcmp(tag, "TLE")) id3tag.assignf("Length: {}", value); + if (!strcmp(tag, "TMT")) id3tag.assignf("Media type: {}", value); + if (!strcmp(tag, "TOA")) id3tag.assignf("Original artist(s)/performer(s): {}", value); + if (!strcmp(tag, "TOF")) id3tag.assignf("Original filename: {}", value); + if (!strcmp(tag, "TOL")) id3tag.assignf("Original Lyricist(s)/text writer(s): {}", value); + if (!strcmp(tag, "TOR")) id3tag.assignf("Original release year: {}", value); + if (!strcmp(tag, "TOT")) id3tag.assignf("Original album/Movie/Show title: {}", value); + if (!strcmp(tag, "TP1")) id3tag.assignf("Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group: {}", value); + if (!strcmp(tag, "TP2")) id3tag.assignf("Band/Orchestra/Accompaniment: {}", value); + if (!strcmp(tag, "TP3")) id3tag.assignf("Conductor/Performer refinement: {}", value); + if (!strcmp(tag, "TP4")) id3tag.assignf("Interpreted, remixed, or otherwise modified by: {}", value); + if (!strcmp(tag, "TPA")) id3tag.assignf("Part of a set: {}", value); + if (!strcmp(tag, "TPB")) id3tag.assignf("Publisher: {}", value); + if (!strcmp(tag, "TRC")) id3tag.assignf("ISRC (International Standard Recording Code): {}", value); + if (!strcmp(tag, "TRD")) id3tag.assignf("Recording dates: {}", value); + if (!strcmp(tag, "TRK")) id3tag.assignf("Track number/Position in set: {}", value); + if (!strcmp(tag, "TSI")) id3tag.assignf("Size: {}", value); + if (!strcmp(tag, "TSS")) id3tag.assignf("Software/hardware and settings used for encoding: {}", value); + if (!strcmp(tag, "TT1")) id3tag.assignf("Content group description: {}", value); + if (!strcmp(tag, "TT2")) id3tag.assignf("Title/Songname/Content description: {}", value); + if (!strcmp(tag, "TT3")) id3tag.assignf("Subtitle/Description refinement: {}", value); + if (!strcmp(tag, "TXT")) id3tag.assignf("Lyricist/text writer: {}", value); + if (!strcmp(tag, "TXX")) id3tag.assignf("User defined text information frame: {}", value); + if (!strcmp(tag, "TYE")) id3tag.assignf("Year: {}", value); + if (!strcmp(tag, "UFI")) id3tag.assignf("Unique file identifier: {}", value); + if (!strcmp(tag, "ULT")) id3tag.assignf("Unsychronized lyric/text transcription: {}", value); + if (!strcmp(tag, "WAF")) id3tag.assignf("Official audio file webpage: {}", value); + if (!strcmp(tag, "WAR")) id3tag.assignf("Official artist/performer webpage: {}", value); + if (!strcmp(tag, "WAS")) id3tag.assignf("Official audio source webpage: {}", value); + if (!strcmp(tag, "WCM")) id3tag.assignf("Commercial information: {}", value); + if (!strcmp(tag, "WCP")) id3tag.assignf("Copyright/Legal information: {}", value); + if (!strcmp(tag, "WPB")) id3tag.assignf("Publishers official webpage: {}", value); + if (!strcmp(tag, "WXX")) id3tag.assignf("User defined URL link frame: {}", value); + + // V2.3 V2.4 tags + if (!strcmp(tag, "COMM")) id3tag.assignf("Comment: {}", value); + if (!strcmp(tag, "OWNE")) id3tag.assignf("Ownership: {}", value); + if (!strcmp(tag, "PRIV")) id3tag.assignf("Private: {}", value); + if (!strcmp(tag, "SYLT")) id3tag.assignf("SynLyrics: {}", value); + if (!strcmp(tag, "TALB")) id3tag.assignf("Album: {}", value); + if (!strcmp(tag, "TBPM")) id3tag.assignf("BeatsPerMinute: {}", value); + if (!strcmp(tag, "TCAT")) id3tag.assignf("PodcastCategory: {}", value); + if (!strcmp(tag, "TCMP")) id3tag.assignf("Compilation: {}", value); + if (!strcmp(tag, "TCOM")) id3tag.assignf("Composer: {}", value); + if (!strcmp(tag, "TCON")) id3tag.assignf("ContentType: {}", value); + if (!strcmp(tag, "TCOP")) id3tag.assignf("Copyright: {}", value); + if (!strcmp(tag, "TDAT")) id3tag.assignf("Date: {}", value); + if (!strcmp(tag, "TDES")) id3tag.assignf("PodcastDescription: {}", value); + if (!strcmp(tag, "TDOR")) id3tag.assignf("Original Release Year: {}", value); + if (!strcmp(tag, "TDRC")) id3tag.assignf("Publication date: {}", value); + if (!strcmp(tag, "TDRL")) id3tag.assignf("ReleaseTime: {}", value); + if (!strcmp(tag, "TENC")) id3tag.assignf("Encoded by: {}", value); + if (!strcmp(tag, "TEXT")) {} // id3tag.assignf("Lyricist: {}", value); + if (!strcmp(tag, "TGID")) id3tag.assignf("PodcastID: {}", value); + if (!strcmp(tag, "TIME")) id3tag.assignf("Time: {}", value); + if (!strcmp(tag, "TIT1")) id3tag.assignf("Grouping: {}", value); + if (!strcmp(tag, "TIT2")) id3tag.assignf("Title: {}", value); + if (!strcmp(tag, "TIT3")) id3tag.assignf("Subtitle: {}", value); + if (!strcmp(tag, "TLAN")) id3tag.assignf("Language: {}", value); + if (!strcmp(tag, "TLEN")) id3tag.assignf("Length (ms): {}", value); + if (!strcmp(tag, "TMED")) id3tag.assignf("Media: {}", value); + if (!strcmp(tag, "TOAL")) id3tag.assignf("OriginalAlbum: {}", value); + if (!strcmp(tag, "TOPE")) id3tag.assignf("OriginalArtist: {}", value); + if (!strcmp(tag, "TOLY")) id3tag.assignf("OriginalLyricist: {}", value); + if (!strcmp(tag, "TORY")) id3tag.assignf("OriginalReleaseYear: {}", value); + if (!strcmp(tag, "TPE1")) id3tag.assignf("Artist: {}", value); + if (!strcmp(tag, "TPE2")) id3tag.assignf("Band: {}", value); + if (!strcmp(tag, "TPE3")) id3tag.assignf("Conductor: {}", value); + if (!strcmp(tag, "TPE4")) id3tag.assignf("InterpretedBy: {}", value); + if (!strcmp(tag, "TPOS")) id3tag.assignf("PartOfSet: {}", value); + if (!strcmp(tag, "TPUB")) id3tag.assignf("Publisher: {}", value); + if (!strcmp(tag, "TRCK")) id3tag.assignf("Track: {}", value); + if (!strcmp(tag, "TRSN")) id3tag.assignf("InternetRadioStationName: {}", value); + if (!strcmp(tag, "TSSE")) id3tag.assignf("SettingsForEncoding: {}", value); + if (!strcmp(tag, "TRDA")) id3tag.assignf("RecordingDates: {}", value); + if (!strcmp(tag, "TSO2")) id3tag.assignf("AlbumArtistSortOrder: {}", value); + if (!strcmp(tag, "TSOA")) id3tag.assignf("AlbumSortOrder: {}", value); + if (!strcmp(tag, "TSOP")) id3tag.assignf("PerformerSortOrder: {}", value); + if (!strcmp(tag, "TSOC")) id3tag.assignf("ComposerSortOrder: {}", value); + if (!strcmp(tag, "TSOT")) id3tag.assignf("TitleSortOrder: {}", value); + if (!strcmp(tag, "TXXX")) id3tag.assignf("UserDefinedText: {}", value); + if (!strcmp(tag, "TYER")) id3tag.assignf("Year: {}", value); + if (!strcmp(tag, "USER")) id3tag.assignf("TermsOfUse: {}", value); + if (!strcmp(tag, "USLT")) id3tag.assignf("Lyrics: {}", value); + if (!strcmp(tag, "WCOM")) id3tag.assignf("Commercial URL: {}", value); + if (!strcmp(tag, "WFED")) id3tag.assignf("Podcast URL: {}", value); + if (!strcmp(tag, "WOAF")) id3tag.assignf("File URL: {}", value); + if (!strcmp(tag, "WOAR")) id3tag.assignf("OfficialArtistWebpage: {}", value); + if (!strcmp(tag, "WOAS")) id3tag.assignf("Source URL: {}", value); + if (!strcmp(tag, "WORS")) id3tag.assignf("InternetRadioStationURL: {}", value); + if (!strcmp(tag, "WXXX")) id3tag.assignf("User defined URL link frame: {}", value); + if (!strcmp(tag, "XDOR")) id3tag.assignf("OriginalReleaseTime: {}", value); + + if (!id3tag.valid()) { + AUDIO_LOG_DEBUG("unknown tag: {}", tag); + return; + } + + latinToUTF8(id3tag); + + if (id3tag.contains("?xml")) { + showstreamtitle(id3tag.get()); + return; + } + + if (id3tag.starts_with("Grouping")) { + showstreamtitle(id3tag.get()); + return; + } + if (id3tag.strlen()) { info(*this, evt_id3data, "{}", id3tag.get()); } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::latinToUTF8(ps_ptr& buff, bool UTF8check) { + // most stations send strings in UTF-8 but a few sends in latin. To standardize this, all latin strings are + // converted to UTF-8. If UTF-8 is already present, nothing is done and true is returned. + // A conversion to UTF-8 extends the string. Therefore it is necessary to know the buffer size. If the converted + // string does not fit into the buffer, false is returned + + uint16_t pos = 0; + uint16_t in = 0; + uint16_t out = 0; + bool isUTF8 = true; + + // We cannot detect if a given string (or byte sequence) is a UTF-8 encoded text as for example each and every series + // of UTF-8 octets is also a valid (if nonsensical) series of Latin-1 (or some other encoding) octets. + // However not every series of valid Latin-1 octets are valid UTF-8 series. So you can rule out strings that do not conform + // to the UTF-8 encoding schema: + + if (UTF8check) { + const size_t strLen = buff.strlen(); + while (pos < strLen) { + if ((uint8_t)buff[pos] <= 0x7F) { // 0xxxxxxx: ASCII + pos++; + } else if ((buff[pos] & 0xE0) == 0xC0) { + // 110xxxxx 10xxxxxx: 2-byte + if (pos + 1 >= strLen || (uint8_t)buff[pos] < 0xC2 || ((uint8_t)buff[pos + 1] & 0xC0) != 0x80) { + isUTF8 = false; + break; + } + pos += 2; + } else if ((buff[pos] & 0xF0) == 0xE0) { + // 1110xxxx 10xxxxxx 10xxxxxx: 3-byte + if (pos + 2 >= strLen || ((uint8_t)buff[pos + 1] & 0xC0) != 0x80 || ((uint8_t)buff[pos + 2] & 0xC0) != 0x80) { + isUTF8 = false; + break; + } + if ((uint8_t)buff[pos] == 0xE0 && (uint8_t)buff[pos + 1] < 0xA0) { + isUTF8 = false; + break; + } // Overlong + if ((uint8_t)buff[pos] == 0xED && (uint8_t)buff[pos + 1] >= 0xA0) { + isUTF8 = false; + break; + } // UTF-16 surrogate + pos += 3; + } else if ((buff[pos] & 0xF8) == 0xF0) { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx: 4-byte + if (pos + 3 >= strLen || ((uint8_t)buff[pos + 1] & 0xC0) != 0x80 || ((uint8_t)buff[pos + 2] & 0xC0) != 0x80 || ((uint8_t)buff[pos + 3] & 0xC0) != 0x80) { + isUTF8 = false; + break; + } + if ((uint8_t)buff[pos] == 0xF0 && (uint8_t)buff[pos + 1] < 0x90) { + isUTF8 = false; + break; + } // Overlong + if ((uint8_t)buff[pos] > 0xF4 || ((uint8_t)buff[pos] == 0xF4 && (uint8_t)buff[pos + 1] > 0x8F)) { + isUTF8 = false; + break; + } // > U+10FFFF + pos += 4; + } else { + isUTF8 = false; + break; // Invalid first byte (continuation byte or 0xF8-0xFF) + } + } + if (isUTF8) return; // is UTF-8, do nothing + } + ps_ptr iso8859_1; + iso8859_1.assign(buff.get()); + + // Worst-case: all chars are latin1 > 0x7F became 2 Bytes → max length is twice +1 + std::size_t requiredSize = strlen(iso8859_1.get()) * 2 + 1; + + if (buff.size() < requiredSize) { + buff.realloc(requiredSize); + if (buff.size() < requiredSize) { + AUDIO_LOG_ERROR("latinToUTF8: realloc failed (need {} bytes, have {})", requiredSize, buff.size()); + return; // keep original string, avoid buffer overflow + } + } + + // coding into UTF-8 + while (iso8859_1[in] != '\0') { + if (iso8859_1[in] < 0x80) { + buff[out++] = iso8859_1[in++]; + } else { + buff[out++] = (0xC0 | (iso8859_1[in] >> 6)); + buff[out++] = (0x80 | (iso8859_1[in] & 0x3F)); + in++; + } + } + buff[out] = '\0'; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::htmlToUTF8(char* str) { // convert HTML to UTF-8 + + typedef struct { // --- EntityMap Definition --- + const char* name; + uint32_t codepoint; + } EntityMap; + + const EntityMap entities[] = { + {"amp", 0x0026}, // & + {"lt", 0x003C}, // < + {"gt", 0x003E}, // > + {"quot", 0x0022}, // " + {"apos", 0x0027}, // ' + {"nbsp", 0x00A0}, // non-breaking space + {"euro", 0x20AC}, // € + {"copy", 0x00A9}, // © + {"reg", 0x00AE}, // ® + {"trade", 0x2122}, // ™ + {"hellip", 0x2026}, // … + {"ndash", 0x2013}, // – + {"mdash", 0x2014}, // — + {"sect", 0x00A7}, // § + {"para", 0x00B6} // ¶ + }; + + // --- EntityMap Lookup --- + auto find_entity = [&](const char* p, uint32_t* codepoint, int* entity_len) { + for (size_t i = 0; i < sizeof(entities) / sizeof(entities[0]); i++) { + const char* name = entities[i].name; + size_t len = strlen(name); + if (strncmp(p + 1, name, len) == 0 && p[len + 1] == ';') { + *codepoint = entities[i].codepoint; + *entity_len = (int)(len + 2); // &name; + return 1; + } + } + return 0; + }; + + auto codepoint_to_utf8 = [&](uint32_t cp, char* dst) { // Convert a Codepoint (Unicode) to UTF-8, writes in DST, there is number of bytes back + if (cp <= 0x7F) { + dst[0] = cp; + return 1; + } else if (cp <= 0x7FF) { + dst[0] = 0xC0 | (cp >> 6); + dst[1] = 0x80 | (cp & 0x3F); + return 2; + } else if (cp <= 0xFFFF) { + dst[0] = 0xE0 | (cp >> 12); + dst[1] = 0x80 | ((cp >> 6) & 0x3F); + dst[2] = 0x80 | (cp & 0x3F); + return 3; + } else if (cp <= 0x10FFFF) { + dst[0] = 0xF0 | (cp >> 18); + dst[1] = 0x80 | ((cp >> 12) & 0x3F); + dst[2] = 0x80 | ((cp >> 6) & 0x3F); + dst[3] = 0x80 | (cp & 0x3F); + return 4; + } + return -1; // invalid Codepoint + }; + + char* p = str; + while (*p != '\0') { + if (p[0] == '&') { + uint32_t cp; + int consumed; + if (find_entity(p, &cp, &consumed)) { // looking for entity, such as © + char utf8[5] = {0}; + int len = codepoint_to_utf8(cp, utf8); + if (len > 0) { + size_t tail_len = strlen(p + consumed); + memmove(p + len, p + consumed, tail_len + 1); + memcpy(p, utf8, len); + p += len; + continue; + } + } + } + if (p[0] == '&' && p[1] == '#') { + char* endptr; + uint32_t codepoint = strtol(p + 2, &endptr, 10); + + if (*endptr == ';' && codepoint <= 0x10FFFF) { + char utf8[5] = {0}; + int utf8_len = codepoint_to_utf8(codepoint, utf8); + if (utf8_len > 0) { + // size_t entity_len = endptr - p + 1; + size_t tail_len = strlen(endptr + 1); + + // Show residual ring to the left + memmove(p + utf8_len, endptr + 1, tail_len + 1); // +1 because of '\0' + + // Copy UTF-8 characters + memcpy(p, utf8, utf8_len); + + // weiter bei neuem Zeichen + p += utf8_len; + continue; + } + } + } + p++; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +size_t Audio::readAudioHeader(uint32_t bytes) { + size_t bytesReaded = 0; + if (m_codec == CODEC_WAV) { + int res = read_WAV_Header(InBuff.getReadPtr(), bytes); + if (res >= 0) + bytesReaded = res; + else { // error, skip header + m_controlCounter = 100; + } + } + if (m_codec == CODEC_MP3) { + int res = read_ID3_Header(InBuff.getReadPtr(), bytes); + if (res > 0 || m_controlCounter < 100) + bytesReaded = res; + else { // error, skip header + m_controlCounter = 100; + } + } + if (m_codec == CODEC_M4A) { + int res = read_M4A_Header(InBuff.getReadPtr(), bytes); + if (res >= 0) + bytesReaded = res; + else { // error, skip header + m_controlCounter = 100; + } + } + if (m_codec == CODEC_AAC) { + // stream only, no header + m_audioDataSize = m_audioFileSize; + m_controlCounter = 100; + } + if (m_codec == CODEC_FLAC) { + int res = read_FLAC_Header(InBuff.getReadPtr(), bytes); + if (res >= 0) + bytesReaded = res; + else { // error + stopSong(); + } + } + if (m_codec == CODEC_OPUS) { m_controlCounter = 100; } + if (m_codec == CODEC_VORBIS) { m_controlCounter = 100; } + if (m_codec == CODEC_OGG) { m_controlCounter = 100; } + if (!isRunning()) { + AUDIO_LOG_ERROR("Processing stopped due to invalid audio header"); + return 0; + } + return bytesReaded; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::read_WAV_Header(uint8_t* data, size_t len) { + + if (m_controlCounter == 0) { + m_rwh.cs = 0; + m_rwh.bts = 0; + m_controlCounter++; + if ((*data != 'R') || (*(data + 1) != 'I') || (*(data + 2) != 'F') || (*(data + 3) != 'F')) { + AUDIO_LOG_ERROR("file has no RIFF tag"); + m_rwh.headerSize = 0; + return -1; // false; + } else { + m_rwh.headerSize = 4; + return 4; // ok + } + } + + if (m_controlCounter == 1) { + m_controlCounter++; + m_rwh.cs = (uint32_t)(*data + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24) - 8); + m_rwh.headerSize += 4; + return 4; // ok + } + + if (m_controlCounter == 2) { + m_controlCounter++; + if ((*data != 'W') || (*(data + 1) != 'A') || (*(data + 2) != 'V') || (*(data + 3) != 'E')) { + AUDIO_LOG_ERROR("format tag is not WAVE"); + return -1; // false; + } else { + m_rwh.headerSize += 4; + return 4; + } + } + + if (m_controlCounter == 3) { + if ((*data == 'f') && (*(data + 1) == 'm') && (*(data + 2) == 't')) { + m_controlCounter++; + m_rwh.headerSize += 4; + return 4; + } else { + m_rwh.headerSize += 4; + return 4; + } + } + + if (m_controlCounter == 4) { + m_controlCounter++; + m_rwh.cs = (uint32_t)(*data + (*(data + 1) << 8)); + if (m_rwh.cs > 40) return -1; // false, something going wrong + m_rwh.bts = m_rwh.cs - 16; // bytes to skip if fmt chunk is >16 + m_rwh.headerSize += 4; + return 4; + } + + if (m_controlCounter == 5) { + m_controlCounter++; + uint16_t fc = (uint16_t)(*(data + 0) + (*(data + 1) << 8)); // Format code + uint16_t ch = (uint16_t)(*(data + 2) + (*(data + 3) << 8)); // Number of interleaved channels + uint32_t sr = (uint32_t)(*(data + 4) + (*(data + 5) << 8) + (*(data + 6) << 16) + (*(data + 7) << 24)); // Samplerate + uint32_t dr = (uint32_t)(*(data + 8) + (*(data + 9) << 8) + (*(data + 10) << 16) + (*(data + 11) << 24)); // Datarate + uint16_t dbs = (uint16_t)(*(data + 12) + (*(data + 13) << 8)); // Data block size + uint16_t bps = (uint16_t)(*(data + 14) + (*(data + 15) << 8)); // Bits per sample + + info(*this, evt_info, "FormatCode: {}", fc); + // info(*this, evt_info, "Channel: {}", nic); + // info(*this, evt_info, "SampleRate (Hz): {}", sr); + info(*this, evt_info, "DataRate: {}", dr); + info(*this, evt_info, "DataBlockSize: {}", dbs); + info(*this, evt_info, "BitsPerSample: {}", bps); + + if ((bps != 8) && (bps != 16) && (bps != 24) && (bps != 32)) { + info(*this, evt_info, "BitsPerSample is {}, must be 8, 16, 24 or 32", bps); + stopSong(); + return -1; + } + if ((ch != 1) && (ch != 2)) { + info(*this, evt_info, "num channels is {}, must be 1 or 2", ch); + stopSong(); + return -1; + } + if (fc != 1) { + AUDIO_LOG_ERROR("format code is not 1 (PCM)"); + stopSong(); + return -1; // false; + } + m_decoder->setRawBlockParams(ch, sr, bps, 0, 0); + m_nominal_bitrate = ch * sr * bps; + m_rwh.headerSize += 16; + return 16; // ok + } + + if (m_controlCounter == 6) { + m_controlCounter++; + m_rwh.headerSize += m_rwh.bts; + return m_rwh.bts; // skip to data + } + + if (m_controlCounter == 7) { + if ((*(data + 0) == 'd') && (*(data + 1) == 'a') && (*(data + 2) == 't') && (*(data + 3) == 'a')) { + m_controlCounter++; + // vTaskDelay(30); + m_rwh.headerSize += 4; + return 4; + } else { + m_rwh.headerSize++; + return 1; + } + } + + if (m_controlCounter == 8) { + m_controlCounter++; + size_t cs = *(data + 0) + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24); // read chunkSize + m_rwh.headerSize += 4; + if (cs) { + m_audioDataSize = cs - 44; + } else { // sometimes there is nothing here + m_audioDataSize = m_audioFileSize - m_rwh.headerSize; + } + + m_audioFileDuration = m_audioDataSize / (getSampleRate() * getChannels()); + if (getBitsPerSample() == 16) m_audioFileDuration /= 2; + info(*this, evt_info, "Duration (s): {}", m_audioFileDuration); + return 4; + } + m_controlCounter = 100; // header succesfully read + m_audioDataStart = m_rwh.headerSize; + info(*this, evt_info, "Audio-Data-Start: {}", m_audioDataStart); + info(*this, evt_info, "Audio-Length: {}", m_audioDataSize); + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::read_FLAC_Header(uint8_t* data, size_t len) { + + if (m_rflh.retvalue && m_controlCounter != 0) { + if (m_rflh.retvalue > len) { // if returnvalue > bufferfillsize + if (len > InBuff.getMaxBlockSize()) len = InBuff.getMaxBlockSize(); + m_rflh.retvalue -= len; // and wait for more bufferdata + return len; + } else { + size_t tmp = m_rflh.retvalue; + m_rflh.retvalue = 0; + return tmp; + } + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_BEGIN) { // init + m_rflh.reset(); + m_controlCounter = FLAC_MAGIC; + m_rflh.picVec.clear(); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_MAGIC) { /* check MAGIC STRING */ + if (specialIndexOf(data, "OggS", 10) == 0) { // is ogg + m_rflh.headerSize = 0; + m_rflh.retvalue = 0; + m_controlCounter = FLAC_OKAY; + return 0; + } + if (specialIndexOf(data, "fLaC", 10) != 0) { + if (specialIndexOf(data, "ID3", 10) == 0) { // has ID3 before fLaC + // Synchsafe-Size + uint32_t size = (data[6] << 21) | (data[7] << 14) | (data[8] << 7) | data[9]; + size += 10; // header + body + m_rflh.retvalue = size; // skip ID3 header + body + return 0; + } + AUDIO_LOG_ERROR("Magic String 'fLaC' not found in header"); + stopSong(); + return -1; + } + + m_controlCounter = FLAC_MBH; // METADATA_BLOCK_HEADER + m_rflh.headerSize = 4; + m_rflh.retvalue = 4; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_MBH) { /* METADATA_BLOCK_HEADER */ + uint8_t blockType = *data; + + if (!m_rflh.f_lastMetaBlock) { + if ((blockType & 127) == 0) m_controlCounter = FLAC_SINFO; + if ((blockType & 127) == 1) m_controlCounter = FLAC_PADDING; + if ((blockType & 127) == 2) m_controlCounter = FLAC_APP; + if ((blockType & 127) == 3) m_controlCounter = FLAC_SEEK; + if ((blockType & 127) == 4) m_controlCounter = FLAC_VORBIS; + if ((blockType & 127) == 5) m_controlCounter = FLAC_CUESHEET; + if ((blockType & 127) == 6) m_controlCounter = FLAC_PICTURE; + if ((blockType & 128)) { m_rflh.f_lastMetaBlock = true; } + m_rflh.headerSize += 1; + m_rflh.retvalue = 1; + return 0; + } + + m_controlCounter = FLAC_OKAY; + + m_audioDataStart = m_rflh.headerSize; + m_audioDataSize = m_audioFileSize - m_audioDataStart; + m_decoder->setRawBlockParams(m_rflh.numChannels, m_rflh.sampleRate, m_rflh.bitsPerSample, m_rflh.totalSamplesInStream, (uint32_t)m_audioDataSize); + if (m_rflh.picLen) { + size_t pos = m_audioDataStart; + info(*this, evt_image, m_rflh.picVec); + } + + info(*this, evt_info, "Audio-Data-Start: {}", m_audioDataStart); + info(*this, evt_info, "Audio-Length: {}", m_audioDataSize); + if (m_rflh.duration) { + m_rflh.nominalBitrate = (m_audioDataSize * 8) / m_rflh.duration; + m_nominal_bitrate = m_rflh.nominalBitrate; + m_audioFileDuration = m_rflh.duration; + info(*this, evt_info, "Duration (s): {}", m_rflh.duration); + } + m_rflh.retvalue = 0; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_SINFO) { /* Stream info block */ + size_t l = bigEndian(data, 3); + vTaskDelay(2); + m_rflh.maxBlockSize = bigEndian(data + 5, 2); + info(*this, evt_info, "FLAC maxBlockSize: {}", m_rflh.maxBlockSize); + vTaskDelay(2); + m_rflh.maxFrameSize = bigEndian(data + 10, 3); + if (m_rflh.maxFrameSize) { + info(*this, evt_info, "FLAC maxFrameSize: {}", m_rflh.maxFrameSize); + } else { + info(*this, evt_info, "FLAC maxFrameSize: N/A"); + } + if (m_rflh.maxFrameSize > InBuff.getMaxBlockSize()) { + AUDIO_LOG_ERROR("FLAC maxFrameSize too large!"); + stopSong(); + return -1; + } + vTaskDelay(2); + uint32_t nextval = bigEndian(data + 13, 3); + m_rflh.sampleRate = nextval >> 4; + info(*this, evt_info, "FLAC sampleRate (Hz): {}", m_rflh.sampleRate); + vTaskDelay(2); + m_rflh.numChannels = ((nextval & 0x06) >> 1) + 1; + info(*this, evt_info, "FLAC numChannels: {}", m_rflh.numChannels); + vTaskDelay(2); + uint8_t bps = (nextval & 0x01) << 4; + bps += (*(data + 16) >> 4) + 1; + m_rflh.bitsPerSample = bps; + if ((bps != 8) && (bps != 16) && (bps != 24)) { + AUDIO_LOG_ERROR("bits per sample must be 8, 16 or 24, is {}", bps); + stopSong(); + return -1; + } + info(*this, evt_info, "FLAC bitsPerSample: {}", m_rflh.bitsPerSample); + m_rflh.totalSamplesInStream = bigEndian(data + 17, 4); + if (m_rflh.totalSamplesInStream) { + info(*this, evt_info, "total samples in stream: {}", m_rflh.totalSamplesInStream); + } else { + info(*this, evt_info, "total samples in stream: N/A"); + } + if (bps != 0 && m_rflh.totalSamplesInStream && m_rflh.sampleRate) { m_rflh.duration = m_rflh.totalSamplesInStream / m_rflh.sampleRate; } + m_controlCounter = FLAC_MBH; // METADATA_BLOCK_HEADER + m_rflh.retvalue = l + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_PADDING) { /* PADDING */ + size_t l = bigEndian(data, 3); + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = l + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_APP) { /* APPLICATION */ + size_t l = bigEndian(data, 3); + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = l + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_SEEK) { /* SEEKTABLE */ + size_t l = bigEndian(data, 3); + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = l + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_VORBIS) { /* VORBIS COMMENT */ // field names + + auto parse_flac_timestamp = [&](const char* s) { + if (!s || *s != '[') return -1; + int mm = 0, ss = 0, hh = 0; + if (sscanf(s, "[%d:%d.%d]", &mm, &ss, &hh) == 3) { return mm * 60000 + ss * 1000 + hh * 10; } + return -1; + }; + + ps_ptr vendorString; + ps_ptr commentString; + ps_ptr lyricsBuffer; + size_t vendorLength = bigEndian(data, 3); + size_t idx = 0; + data += 3; + idx += 3; + size_t vendorStringLength = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); + if (vendorStringLength) { + data += 4; + idx += 4; + } + if (vendorStringLength > 495) vendorStringLength = 495; // guard + vendorString.assign((const char*)data, vendorStringLength); + vendorString.insert("VENDOR_STRING: ", 0); + info(*this, evt_id3data, "{}", vendorString.get()); + data += vendorStringLength; + idx += vendorStringLength; + size_t commentListLength = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); + data += 4; + idx += 4; + + for (int i = 0; i < commentListLength; i++) { + (void)i; + size_t commentLength = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); + data += 4; + idx += 4; + if (commentLength) { // guard + commentString.assign((const char*)data, commentLength); + if (commentString.starts_with("LYRICS=")) + lyricsBuffer.clone_from(commentString); + else + info(*this, evt_id3data, "{}", commentString.get()); + } + data += commentLength; + idx += commentLength; + if (idx > vendorLength + 3) { AUDIO_LOG_ERROR("VORBIS COMMENT section is too long"); } + } + ps_ptr tmp; + ps_ptr timestamp; + timestamp.alloc(12, "timestamp"); + if (lyricsBuffer.valid()) { + lyricsBuffer.remove_prefix("LYRICS="); + idx = 0; + while (idx < lyricsBuffer.size()) { + int pos = lyricsBuffer.index_of('\n', idx); + if (pos == -1) break; + int len = pos - idx + 1; + tmp.copy_from(lyricsBuffer.get() + idx, len); + idx += len; + if (tmp.ends_with("\n")) tmp.truncate_at('\n'); + // tmp content e.g.: [00:27.07]Jetzt kommt die Zeit + // [00:28.84]Auf die ihr euch freut + timestamp.copy_from(tmp.get(), 10); + + int ms = parse_flac_timestamp(timestamp.c_get()); + + // timestamp.remove_chars("[]:."); + // timestamp.append("0"); // to ms 0028840 + tmp.remove_before(10, true); + if (tmp.strlen() > 0) { + m_syltLines.push_back(std::move(tmp)); + m_syltTimeStamp.push_back(ms); + } + } + info(*this, evt_info, "audiofile contains synchronized lyrics"); + // for(int i = 0; i < m_syltLines.size(); i++){ + // info(*this, evt_lyrics, "{:07} ms, {}", m_syltTimeStamp[i], m_syltLines[i].c_get()); + // } + } + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = vendorLength + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_CUESHEET) { /* CUESHEET */ + size_t l = bigEndian(data, 3); + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = l + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == FLAC_PICTURE) { /* PICTURE */ + m_rflh.picLen = bigEndian(data, 3); + m_rflh.picPos = m_rflh.headerSize + 3; + m_rflh.picVec.push_back(m_rflh.picPos); + m_rflh.picVec.push_back(m_rflh.picLen); + AUDIO_LOG_DEBUG("FLAC PICTURE, pos {}, size {}", m_rflh.picPos, m_rflh.picLen); + m_controlCounter = FLAC_MBH; + m_rflh.retvalue = m_rflh.picLen + 3; + m_rflh.headerSize += m_rflh.retvalue; + return 0; + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +int Audio::read_ID3_Header(uint8_t* data, size_t len) { + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_BEGIN) { /* read ID3 tag and ID3 header size */ + m_controlCounter = MP3_ID3HEADER; + m_ID3Hdr.reset(); // reset all + m_ID3Hdr.iBuffSize = 4096; + m_ID3Hdr.iBuff.alloc(m_ID3Hdr.iBuffSize + 10, "m_ID3Hdr.iBuff"); + memset(m_ID3Hdr.tag, 0, sizeof(m_ID3Hdr.tag)); + return 0; + } + if (m_controlCounter == MP3_NEXTID3) { + m_controlCounter = MP3_ID3HEADER; + // reset specific + m_ID3Hdr.id3Size = 0; + // m_ID3Hdr.totalId3Size = 0; // if we have more header, id3_1_size + id3_2_size + .... + m_ID3Hdr.remainingHeaderBytes = 0; + m_ID3Hdr.v22_tag_length = 0; + m_ID3Hdr.ID3version = 0; + m_ID3Hdr.ehsz = 0; + m_ID3Hdr.framesize = 0; + m_ID3Hdr.compressed = false; + m_ID3Hdr.SYLT.size = 0; + m_ID3Hdr.SYLT.pos = 0; + m_ID3Hdr.iBuffSize = 4096; + m_ID3Hdr.iBuff.alloc(m_ID3Hdr.iBuffSize + 10, "m_ID3Hdr.iBuff"); + memset(m_ID3Hdr.tag, 0, sizeof(m_ID3Hdr.tag)); + return 0; + } + + if (m_controlCounter == MP3_ID3HEADER) { + m_controlCounter = MP3_EXTHEADER; + int retval = 0; + if (!m_f_m3u8data) info(*this, evt_info, "File-Size: {}", m_audioFileSize); + + m_ID3Hdr.remainingHeaderBytes = 0; + m_ID3Hdr.ehsz = 0; + if (specialIndexOf(data, "ID3", 4) != 0) { // ID3 not found + if (!m_f_m3u8data) { info(*this, evt_info, "file has no ID3 tag, skip metadata"); } + m_audioDataSize = m_audioFileSize; + // if(!m_f_m3u8data) info(*this, evt_info, "Audio-Length: {}", m_audioDataSize); + m_controlCounter = MP3_XING; // have xing? + return 0; // error, no ID3 signature found + } + m_ID3Hdr.ID3version = *(data + 3); + switch (m_ID3Hdr.ID3version) { + case 2: + m_f_unsync = (*(data + 5) & 0x80); + m_f_exthdr = false; + break; + case 3: + case 4: + m_f_unsync = (*(data + 5) & 0x80); // bit7 + m_f_exthdr = (*(data + 5) & 0x40); // bit6 extended header + break; + }; + m_ID3Hdr.id3Size = bigEndian(data + 6, 4, 7); // ID3v2 size 4 * %0xxxxxxx (shift left seven times!!) + m_ID3Hdr.id3Size += 10; + + retval = 10; + + // Every read from now may be unsync'd + if (!m_f_m3u8data) info(*this, evt_info, "ID3 framesSize: {}", m_ID3Hdr.id3Size); + if (!m_f_m3u8data) info(*this, evt_info, "ID3 version: 2.{}", m_ID3Hdr.ID3version); + + if (m_ID3Hdr.ID3version == 2) { m_controlCounter = MP3_ID3V22; } + m_ID3Hdr.remainingHeaderBytes = m_ID3Hdr.id3Size; + m_ID3Size = m_ID3Hdr.id3Size; + m_ID3Hdr.remainingHeaderBytes -= 10; + + if (m_f_exthdr) { + m_ID3Hdr.ehsz = bigEndian(data + 10, 4, 7); // syncSave + info(*this, evt_info, "ID3 extended header, size: {}", m_ID3Hdr.ehsz); + m_ID3Hdr.ehsz -= 4; + m_ID3Hdr.remainingHeaderBytes -= 4; + m_ID3Hdr.id3Size += 4; + retval += 4; + } + return retval; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_EXTHEADER) { // skip extended header if exists + if (m_ID3Hdr.ehsz > len) { + m_ID3Hdr.ehsz -= len; + m_ID3Hdr.remainingHeaderBytes -= len; + return len; + } // Throw it away + else { + m_controlCounter = MP3_ID3FRAME; + m_ID3Hdr.remainingHeaderBytes -= m_ID3Hdr.ehsz; + return m_ID3Hdr.ehsz; + } // Throw it away + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_ID3FRAME) { // read a ID3 frame, get the tag + if (m_ID3Hdr.remainingHeaderBytes == 0) { + m_controlCounter = MP3_XING; + return 0; + } + m_controlCounter = MP3_FRAMESIZE; + m_ID3Hdr.frameid[0] = *(data + 0); + m_ID3Hdr.frameid[1] = *(data + 1); + m_ID3Hdr.frameid[2] = *(data + 2); + m_ID3Hdr.frameid[3] = *(data + 3); + m_ID3Hdr.frameid[4] = 0; + for (uint8_t i = 0; i < 4; i++) m_ID3Hdr.tag[i] = m_ID3Hdr.frameid[i]; // tag = frameid + if (m_ID3Hdr.frameid[0] == 0 && m_ID3Hdr.frameid[1] == 0 && m_ID3Hdr.frameid[2] == 0 && m_ID3Hdr.frameid[3] == 0) { + // We're in padding + m_controlCounter = MP3_LASTFRAMES; // all ID3 metadata processed + } + m_ID3Hdr.remainingHeaderBytes -= 4; + return 4; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_FRAMESIZE) { // get the frame size + m_controlCounter = MP3_TAG; + + if (m_ID3Hdr.ID3version == 4) { + m_ID3Hdr.framesize = bigEndian(data, 4, 7); // << 7 + } else { + m_ID3Hdr.framesize = bigEndian(data, 4); // << 8 + } + + uint8_t frameFlag_0 = *(data + 4); + uint8_t frameFlag_1 = *(data + 5); + (void)frameFlag_0; + m_ID3Hdr.compressed = frameFlag_1 & 0x80; // Frame is compressed using [#ZLIB zlib] with 4 bytes for 'decompressed + uint32_t decompsize = 0; + if (m_ID3Hdr.compressed) { + // AUDIO_LOG_INFO("iscompressed"); + decompsize = bigEndian(data + 6, 4); + (void)decompsize; + // AUDIO_LOG_INFO("decompsize={}", decompsize); + m_ID3Hdr.remainingHeaderBytes -= 6 + 4; + return 6 + 4; + } + m_ID3Hdr.remainingHeaderBytes -= 6; + return 6; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_SKIP) { // If the frame is larger than m_ID3Hdr.framesize, skip the rest + if (m_ID3Hdr.framesize > len) { + m_ID3Hdr.framesize -= len; + m_ID3Hdr.remainingHeaderBytes -= len; + return len; + } else { + m_controlCounter = MP3_ID3FRAME; // check next frame + m_ID3Hdr.remainingHeaderBytes -= m_ID3Hdr.framesize; + return m_ID3Hdr.framesize; + } + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_TAG) { // Read the value + m_controlCounter = MP3_SKIP; // only read 256 bytes + + uint8_t textEncodingByte = *(data + 0); // ID3v2 Text-Encoding-Byte + // $00 – ISO-8859-1 (LATIN-1, Identical to ASCII for values smaller than 0x80). + // $01 – UCS-2 encoded Unicode with BOM (Byte Order Mark), in ID3v2.2 and ID3v2.3. + // $02 – UTF-16BE encoded Unicode without BOM (Byte Order Mark) , in ID3v2.4. + // $03 – UTF-8 encoded Unicode, in ID3v2.4. + + if (startsWith(m_ID3Hdr.tag, "APIC")) { // a image embedded in file, passing it to external function + m_ID3Hdr.APIC_vec.push_back(m_ID3Hdr.totalId3Size + m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes); + m_ID3Hdr.APIC_vec.push_back(m_ID3Hdr.framesize); + AUDIO_LOG_DEBUG("APIC_pos {}, APIC_size {}", m_ID3Hdr.APIC_vec[2 * m_ID3Hdr.numID3Header], m_ID3Hdr.APIC_vec[2 * m_ID3Hdr.numID3Header + 1]); + return 0; + } + + if (startsWith(m_ID3Hdr.tag, "SYLT") || startsWith(m_ID3Hdr.tag, "USLT")) { // any lyrics embedded in file, passing it to external function + m_controlCounter = MP3_SYLT; + return 0; + } + + if ( // proprietary not standard information + startsWith(m_ID3Hdr.tag, "PRIV")) { + ; // AUDIO_LOG_ERROR("PRIV"); + return 0; + } + if (startsWith(m_ID3Hdr.tag, "TSIZ") || startsWith(m_ID3Hdr.tag, "XTRA")) { // tag with invalid length, skip everything and find the first sync word + m_ID3Hdr.framesize = 0; + size_t tmp = m_ID3Hdr.remainingHeaderBytes; + m_ID3Hdr.remainingHeaderBytes = 0; + return tmp; + } + + if (m_ID3Hdr.framesize == 0) return 0; + + ps_ptr tmp; + tmp.set_name("tmp"); + ps_ptr content_descriptor; + content_descriptor.set_name("content_descriptor"); + size_t fs = m_ID3Hdr.framesize; // fs = size of the frame data field as read from header + size_t bytesToCopy = fs; + size_t textDataLength = 0; + uint16_t idx = 0; + + if (bytesToCopy >= m_ID3Hdr.iBuffSize) { bytesToCopy = m_ID3Hdr.iBuffSize - 1; } // make sure a zero terminator fits + if (bytesToCopy > 0) { textDataLength = bytesToCopy - 1; } // Only if there are data that we can shorten + for (int i = 0; i < textDataLength; i++) { + m_ID3Hdr.iBuff[i] = *(data + i + 1); // Skipped the first byte (Encoding) + } + + if (textEncodingByte == 1 || textEncodingByte == 2) { // is UTF-16LE or UTF-16BE + m_ID3Hdr.iBuff[textDataLength] = 0; // UTF-16: set double zero terminator + m_ID3Hdr.iBuff[textDataLength + 1] = 0; // second '\0' for UTF-16 + } else { + m_ID3Hdr.iBuff[textDataLength] = 0; // only one '\0' for ISO-8859-1 or UTF-8 + } + + m_ID3Hdr.framesize -= fs; + + uint16_t dataLength = fs - 1; + bool isBigEndian = (textEncodingByte == 2); + + char encodingTab[4][12] = {"ISO-8859-1", "UTF-16", "UTF-16BE", "UTF-8"}; + + if (startsWith(m_ID3Hdr.tag, "COMM")) { // language code + m_ID3Hdr.lang[0] = m_ID3Hdr.iBuff[0]; + m_ID3Hdr.lang[1] = m_ID3Hdr.iBuff[1]; + m_ID3Hdr.lang[2] = m_ID3Hdr.iBuff[2]; + m_ID3Hdr.lang[3] = '\0'; + + idx = 4; + if (textEncodingByte == 1 || textEncodingByte == 2) idx++; + + uint16_t cd_len = 0; + if (textEncodingByte == 0) + cd_len = 1 + content_descriptor.copy_from_iso8859_1((const uint8_t*)(m_ID3Hdr.iBuff.get() + idx)); // iso8859_1 + else if (textEncodingByte == 3) + cd_len = 1 + content_descriptor.copy_from((const char*)(m_ID3Hdr.iBuff.get() + idx)); // utf-8 + else + cd_len = 2 + content_descriptor.copy_from_utf16((const uint8_t*)(m_ID3Hdr.iBuff.get() + idx), isBigEndian); // utf-16 + if (cd_len > 2) info(*this, evt_info, "Comment: text encoding; {}, language {}, content_descriptor: {}", encodingTab[textEncodingByte], m_ID3Hdr.lang, content_descriptor.c_get()); + + idx += cd_len; + // AUDIO_LOG_INFO("Tag: {}, Length: {}, Format: {}", m_ID3Hdr.tag, textDataLength, encodingTab[textEncodingByte]); + } else { + if (textEncodingByte == 0) { + tmp.copy_from_iso8859_1((const uint8_t*)m_ID3Hdr.iBuff.get() + idx); + } // ISO-8859-1 + else if (textEncodingByte == 1 || textEncodingByte == 2) { + tmp.copy_from_utf16((const uint8_t*)m_ID3Hdr.iBuff.get() + idx, isBigEndian); + } // UTF-16LE oder UTF-16BE + else if (textEncodingByte == 3) { + tmp.copy_from(m_ID3Hdr.iBuff.get() + idx); + } // UTF-8 copy directly because no conversion is necessary + } + showID3Tag(m_ID3Hdr.tag, tmp.c_get()); + m_ID3Hdr.remainingHeaderBytes -= fs; + return fs; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_SYLT) { // SYLT + m_controlCounter = MP3_SKIP; + if (m_dataMode == AUDIO_LOCALFILE || (m_streamType == ST_WEBFILE)) { + ps_ptr tmp; + ps_ptr content_descriptor; + ps_ptr syltBuff; + bool isBigEndian = true; + size_t len = 0; + int idx = 0; + m_ID3Hdr.SYLT.pos = m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes; + m_ID3Hdr.SYLT.size = m_ID3Hdr.framesize; + if (m_ID3Hdr.SYLT.size < len) return 0; + syltBuff.copy_from((const char*)data, m_ID3Hdr.SYLT.size); + m_ID3Hdr.SYLT.text_encoding = syltBuff[0]; // 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8 + if (m_ID3Hdr.SYLT.text_encoding == 1) isBigEndian = false; + if (m_ID3Hdr.SYLT.text_encoding > 3) { + AUDIO_LOG_ERROR("unknown text encoding: {}", m_ID3Hdr.SYLT.text_encoding); + m_ID3Hdr.SYLT.text_encoding = 0; + } + char encodingTab[4][12] = {"ISO-8859-1", "UTF-16", "UTF-16BE", "UTF-8"}; + memcpy(m_ID3Hdr.SYLT.lang, syltBuff.get() + 1, 3); + m_ID3Hdr.SYLT.lang[3] = '\0'; + info(*this, evt_info, "Lyrics: text_encoding: {}, language: {}, size {}", encodingTab[m_ID3Hdr.SYLT.text_encoding], m_ID3Hdr.SYLT.lang, m_ID3Hdr.SYLT.size); + m_ID3Hdr.SYLT.time_stamp_format = syltBuff[4]; + m_ID3Hdr.SYLT.content_type = syltBuff[5]; + idx = 6; + uint16_t cd_len = 0; + if (m_ID3Hdr.SYLT.text_encoding == 0) + cd_len = 1 + content_descriptor.copy_from_iso8859_1((const uint8_t*)(syltBuff.get() + idx)); // iso8859_1 + else if (m_ID3Hdr.SYLT.text_encoding == 3) + cd_len = 1 + content_descriptor.copy_from((const char*)(syltBuff.get() + idx)); // utf-8 + else + cd_len = 2 + content_descriptor.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian); // utf-16 + if (cd_len > 2) info(*this, evt_info, "Lyrics: content_descriptor: {}", content_descriptor.c_get()); + + idx += cd_len; + while (idx < m_ID3Hdr.SYLT.size) { + if (m_ID3Hdr.SYLT.text_encoding == 0) + idx += 1 + tmp.copy_from_iso8859_1((const uint8_t*)syltBuff.get() + idx); // ISO8859_1 + else if (m_ID3Hdr.SYLT.text_encoding == 3) + idx += 1 + tmp.copy_from((const char*)syltBuff.get() + idx); // UTF-8 + else + idx += 2 + tmp.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian); // UTF-16LE, UTF-16BE + + if (tmp.starts_with("\n")) tmp.remove_before(1); + m_syltLines.push_back(std::move(tmp)); + if (idx + 4 > m_ID3Hdr.SYLT.size) break; // no more 4 bytes? + uint32_t timestamp = bigEndian((uint8_t*)syltBuff.get() + idx, 4); + m_syltTimeStamp.push_back(timestamp); + idx += 4; + } + info(*this, evt_info, "audiofile contains synchronized lyrics"); + // for(int i = 0; i < m_syltLines.size(); i++){ + // info(*this, evt_lyrics, "{:07} ms, {}", m_syltTimeStamp[i], m_syltLines[i].c_get()); + // } + } + return 0; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + // --- section V2.2 only , higher Vers above ---- + // see https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.2.html + if (m_controlCounter == MP3_ID3V22) { // frames in V2.2, 3bytes identifier, 3bytes size descriptor + + if (m_ID3Hdr.v22_tag_length > 0) { + if (m_ID3Hdr.v22_tag_length > len) { + m_ID3Hdr.v22_tag_length -= len; + return len; + } // Throw it away + else { + uint32_t t = m_ID3Hdr.v22_tag_length; + m_ID3Hdr.v22_tag_length = 0; + return t; + } // Throw it away + } + + if (m_ID3Hdr.remainingHeaderBytes == 0) { + m_controlCounter = MP3_LASTFRAMES; + return 0; + } + + ps_ptr tag; + tag.set_name("tag"); + ps_ptr value; + value.set_name("value"); + if (data[0] == 0) { // we are in padding + m_controlCounter = MP3_LASTFRAMES; + uint16_t padding = m_ID3Hdr.remainingHeaderBytes; + m_ID3Hdr.remainingHeaderBytes = 0; + return padding; + } + tag.copy_from((const char*)data, 3); + m_ID3Hdr.v22_tag_length = bigEndian(data + 3, 3) + 6; + value.copy_from((const char*)data + 7, min(m_ID3Hdr.v22_tag_length - 7, (size_t)1024)); + + if (tag.starts_with("PIC")) { // image embedded in header + size_t pic_len = bigEndian(data + 3, 3); + uint32_t pic_start = m_ID3Hdr.totalId3Size + m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes; + + m_ID3Hdr.APIC_vec.push_back(pic_start + 6); + m_ID3Hdr.APIC_vec.push_back(pic_len); + } else if (startsWith(m_ID3Hdr.tag, "SLT")) { // lyrics embedded in header + if (m_dataMode == AUDIO_LOCALFILE) { + + ps_ptr tmp; + ps_ptr content_descriptor; + ps_ptr syltBuff; + bool isBigEndian = true; + size_t len = 0; + int idx = 0; + + m_ID3Hdr.SYLT.pos = m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes; + m_ID3Hdr.SYLT.size = m_ID3Hdr.v22_tag_length; + if (m_ID3Hdr.SYLT.size < len) return 0; + syltBuff.copy_from((const char*)data, m_ID3Hdr.SYLT.size); + m_ID3Hdr.SYLT.text_encoding = syltBuff[0]; + memcpy(m_ID3Hdr.SYLT.lang, syltBuff.get() + 1, 3); + m_ID3Hdr.SYLT.lang[3] = '\0'; + info(*this, evt_info, "Lyrics: text_encoding: {}, language: {}, size {}", + m_ID3Hdr.SYLT.text_encoding == 0 ? "ASCII" + : m_ID3Hdr.SYLT.text_encoding == 3 ? "UTF-8" + : "?", + m_ID3Hdr.SYLT.lang, m_ID3Hdr.SYLT.size); + m_ID3Hdr.SYLT.time_stamp_format = syltBuff[4]; + m_ID3Hdr.SYLT.content_type = syltBuff[5]; + + idx = 6; + + if (m_ID3Hdr.SYLT.text_encoding == 0 || m_ID3Hdr.SYLT.text_encoding == 3) { // utf-8 + len = content_descriptor.copy_from((const char*)(syltBuff.get() + idx)); + } else { // utf-16 + len = content_descriptor.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian); + } + if (len > 2) info(*this, evt_info, "Lyrics: content_descriptor: {}", content_descriptor.c_get()); + idx += len; + + while (idx < m_ID3Hdr.SYLT.size) { + // UTF-16LE, UTF-16BE + if (m_ID3Hdr.SYLT.text_encoding == 1 || m_ID3Hdr.SYLT.text_encoding == 2) { + idx += tmp.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian); + } else { + // ISO-8859-1 / UTF-8 + idx += tmp.copy_from((const char*)syltBuff.get() + idx); + } + if (tmp.starts_with("\n")) tmp.remove_before(1); + m_syltLines.push_back(std::move(tmp)); + + if (idx + 4 > m_ID3Hdr.SYLT.size) break; // no more 4 bytes? + + uint32_t timestamp = bigEndian((uint8_t*)syltBuff.get() + idx, 4); + m_syltTimeStamp.push_back(timestamp); + + idx += 4; + } + info(*this, evt_info, "audiofile contains synchronized lyrics"); + // for(int i = 0; i < m_syltLines.size(); i++){ + // info(*this, evt_lyrics, "{:07} ms, {}", m_syltTimeStamp[i], m_syltLines[i].c_get()); + // } + } + } else { + showID3Tag(tag.c_get(), value.c_get()); + } + + m_ID3Hdr.remainingHeaderBytes -= m_ID3Hdr.v22_tag_length; + + return 0; + } + // -- end section V2.2 ----------- + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_LASTFRAMES) { // skip all ID3 metadata (mostly spaces) + if (m_ID3Hdr.remainingHeaderBytes > len) { + m_ID3Hdr.remainingHeaderBytes -= len; + return len; + } // Throw it away + else { + m_controlCounter = MP3_XING; + return m_ID3Hdr.remainingHeaderBytes; + } // Throw it away + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == MP3_XING) { // exist another ID3tag? + + static const int samplerate_table[4][3] = { + {11025, 12000, 8000}, // MPEG 2.5 + {0, 0, 0}, // reserved + {22050, 24000, 16000}, // MPEG 2 + {44100, 48000, 32000} // MPEG 1 + }; + + static const int samples_per_frame[4][4] = {// layer: 0 1 2 3 + /* V2.5 */ {0, 576, 1152, 384}, + /* res. */ {0, 0, 0, 0}, + /* V2 */ {0, 576, 1152, 384}, + /* V1 */ {0, 1152, 1152, 384}}; + + m_audioDataStart += m_ID3Hdr.id3Size; + m_ID3Hdr.totalId3Size += m_ID3Hdr.id3Size; + m_ID3Hdr.id3Size = 0; + + if ((*(data + 0) == 'I') && (*(data + 1) == 'D') && (*(data + 2) == '3')) { + m_controlCounter = MP3_NEXTID3; + m_ID3Hdr.numID3Header++; + return 0; + } else { + // padding after ID3 body? + uint32_t padding_counter = 0; + while (data[padding_counter] == 0) { + padding_counter++; + m_audioDataStart++; + m_audioDataSize--; + } + if (padding_counter) return padding_counter; + + m_controlCounter = MP3_OKAY; // 100 -> ok + m_audioDataSize = m_audioFileSize - m_audioDataStart; + if (!m_f_m3u8data) info(*this, evt_info, "Audio-Data-Start: {}", m_audioDataStart); + if (!m_f_m3u8data) info(*this, evt_info, "Audio-Length: {}", m_audioDataSize); + + uint32_t hdr = bigEndian(data, 4); + if ((hdr & 0xFFE00000) != 0xFFE00000) AUDIO_LOG_ERROR("Syncword not found"); // check sync + int versionID = (hdr >> 19) & 0x3; // 0=MPEG2.5, 2=MPEG2, 3=MPEG1 + int layerIndex = (hdr >> 17) & 0x3; // 1=Layer3 + int bitrateIdx = (hdr >> 12) & 0xF; + int samplerateIdx = (hdr >> 10) & 0x3; + int mode = (hdr >> 6) & 0x3; // 0=stereo,3=mono + int samplerate = samplerate_table[versionID][samplerateIdx]; + int spf = samples_per_frame[versionID][layerIndex]; + + // Xing or Info Header present? + int8_t mp3_xing = specialIndexOf(data, "Xing", 50); + int8_t mp3_info = specialIndexOf(data, "Info", 50); + + uint8_t xingPos = 0; + if (mp3_xing > 0) xingPos = mp3_xing; + if (mp3_info > 0) xingPos = mp3_info; + + if (xingPos > 0 && layerIndex == 1) { // layer III only + uint32_t frames = bigEndian(data + xingPos + 8, 4); + AUDIO_LOG_DEBUG("frames {}", frames); + uint32_t bytes = bigEndian(data + xingPos + 12, 4); + AUDIO_LOG_DEBUG("bytes {}", bytes); + uint32_t duration = frames * spf / samplerate; + info(*this, evt_info, "Duration (s): {}", duration); + m_audioFileDuration = duration; + uint32_t bitrate = bytes * 8 / duration; + info(*this, evt_info, "Bitrate (b/s): {}", bitrate); + m_nominal_bitrate = bitrate; + } + + if (m_ID3Hdr.APIC_vec.size()) { // if we have a APIC + info(*this, evt_image, m_ID3Hdr.APIC_vec); + m_ID3Hdr.APIC_vec.clear(); + AUDIO_LOG_DEBUG("m_ID3Hdr.totalId3Size {}, m_audioDataStart {}", m_ID3Hdr.totalId3Size, m_audioDataStart); + if (m_ID3Hdr.totalId3Size != m_audioDataStart) audioFileSeek(m_audioDataStart); + } + m_ID3Hdr.numID3Header = 0; + m_ID3Hdr.totalId3Size = 0; + m_ID3Hdr.iBuff.reset(); + return 0; + } + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::read_M4A_Header(uint8_t* data, size_t len) { + bool atom_struct = false; + ps_ptr atom_name; + ps_ptr atom_size; + uint32_t idx = 0; + + /* + ftyp + | - moov -> trak -> ... -> mp4a contains raw block parameters + | L... -> ilst contains artist, composer .... + free (optional) // jump to another atoms at the end of mdat + | + mdat contains the audio data */ + + if (m_m4aHdr.retvalue) { + if (m_m4aHdr.retvalue > UINT16_MAX) { + int res = audioFileSeek(m_m4aHdr.headerSize); + if (res >= 0) { + AUDIO_LOG_INFO("skip {} bytes", m_m4aHdr.retvalue); + InBuff.reset(); + m_m4aHdr.retvalue = 0; + return 0; + } + } + if (m_m4aHdr.retvalue > len) { + m_m4aHdr.retvalue -= len; + m_m4aHdr.cnt += len; + return len; + } else { + size_t tmp = m_m4aHdr.retvalue; + m_m4aHdr.retvalue = 0; + m_m4aHdr.cnt += tmp; + return tmp; + } + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_BEGIN) { // init + memset(&m_m4aHdr, 0, sizeof(audiolib::m4aHdr_t)); + + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + + if (atom_name.equals("ftyp")) { + if (atom_struct) { + AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, (uint32_t)atom_size.to_uint32(16), m_m4aHdr.headerSize + (size_t)atom_size.to_uint32(16)); + m_m4aHdr.sizeof_ftyp = atom_size.to_uint32(16); + } + m_controlCounter = M4A_FTYP; + } else { + AUDIO_LOG_ERROR("begin: ftyp not found"); + stopSong(); + return -1; + } + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_FTYP) { /* check_m4a_file */ + + int m4a = specialIndexOf(data, "M4A ", 20); + int isom = specialIndexOf(data, "isom", 20); + int mp42 = specialIndexOf(data, "mp42", 20); + + if ((m4a != 8) && (isom != 8) && (mp42 != 8)) { + AUDIO_LOG_ERROR("subtype 'MA4 ', 'isom' or 'mp42' expected, but found '{} '", (data + 8)); + stopSong(); + return -1; + } + + m_m4aHdr.retvalue += m_m4aHdr.sizeof_ftyp; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_ftyp; + m_controlCounter = M4A_CHK; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_CHK) { /* check Tag */ + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + + if (atom_name.equals("moov")) { + if (!m_m4aHdr.mdat_seen) m_m4aHdr.progressive = true; // moov before mdat + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_moov = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MOOV; + return 0; + } + + if (atom_name.equals("mdat")) { + m_m4aHdr.mdat_seen = true; + if (!m_m4aHdr.progressive) { + m_m4aHdr.mdat_startPos = m_m4aHdr.headerSize + 8; + m_m4aHdr.sizeof_mdat = atom_size.to_uint32(16); + if (atom_struct) { + AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.mdat_startPos, m_m4aHdr.sizeof_mdat, m_m4aHdr.mdat_startPos + m_m4aHdr.sizeof_mdat); + } + info(*this, evt_info, "Audiofile is non progressive"); + m_m4aHdr.retvalue += m_m4aHdr.sizeof_mdat; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_mdat; + return 0; + stopSong(); + return -1; + } + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_mdat = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MDAT; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + m_m4aHdr.sizeof_moov -= atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_MOOV) { // moov + if (atom_struct) { AUDIO_LOG_WARN("moov size remain {}", m_m4aHdr.sizeof_moov); } + if (m_m4aHdr.sizeof_moov == 0) { + if (m_m4aHdr.progressive) { + m_controlCounter = M4A_CHK; + AUDIO_LOG_DEBUG("goto CHK"); + } else { + audioFileSeek(0); // non progressive, back to mdat + InBuff.reset(); + m_m4aHdr.headerSize = m_m4aHdr.mdat_startPos; + m_m4aHdr.retvalue = m_m4aHdr.mdat_startPos; // set InBuff.getReadPtr to audiodatastart + if (atom_struct) AUDIO_LOG_WARN("goto MDAT at {}", m_m4aHdr.mdat_startPos + 8); + m_controlCounter = M4A_MDAT; + } + return 0; + } // go back + + atom_name.copy_from((const char*)data + 4, 4); + atom_size.big_endian(data, 4); + m_m4aHdr.sizeof_moov -= atom_size.to_uint32(16); + + if (atom_name.equals("trak")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_trak = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_TRAK; + return 0; + } + + if (atom_name.equals("udta")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_udta = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_UDTA; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_TRAK) { // trak + if (atom_struct) { AUDIO_LOG_WARN("trak size remain {}", m_m4aHdr.sizeof_trak); } + if (m_m4aHdr.sizeof_trak == 0) { + m_controlCounter = M4A_MOOV; + return 0; + } // go back + + atom_name.copy_from((const char*)data + 4, 4); + atom_size.big_endian(data, 4); + m_m4aHdr.sizeof_trak -= atom_size.to_uint32(16); + + if (atom_name.equals("mdia")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_mdia = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MDIA; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_MDIA) { // mdia + if (atom_struct) { AUDIO_LOG_WARN("mdia size remain {}", m_m4aHdr.sizeof_mdia); } + if (m_m4aHdr.sizeof_mdia == 0) { + m_controlCounter = M4A_TRAK; + return 0; + } // go back + + atom_name.copy_from((const char*)data + 4, 4); + atom_size.big_endian(data, 4); + m_m4aHdr.sizeof_mdia -= atom_size.to_uint32(16); + + if (atom_name.equals("mdhd")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_mdhd = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MDHD; + return 0; + } + + if (atom_name.equals("minf")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_minf = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MINF; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_MINF) { // minf + if (atom_struct) { AUDIO_LOG_WARN("minf size remain {}", m_m4aHdr.sizeof_minf); } + if (m_m4aHdr.sizeof_minf == 0) { + m_controlCounter = M4A_MDIA; + return 0; + } // go back + + atom_name.copy_from((const char*)data + 4, 4); + atom_size.big_endian(data, 4); + m_m4aHdr.sizeof_minf -= atom_size.to_uint32(16); + + if (atom_name.equals("stbl")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_stbl = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_STBL; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_MDHD) { // mdhd + if (atom_struct) { AUDIO_LOG_WARN("mdhd size remain {}", m_m4aHdr.sizeof_mdhd); } + if (m_m4aHdr.sizeof_mdhd == 0) { + m_controlCounter = M4A_MDIA; + return 0; + } // go back + + ps_ptr mdhd_buffer; // read ESDS content in a buffer + mdhd_buffer.copy_from((char*)data, m_m4aHdr.sizeof_mdhd); // read MDHD content (without header) + // mdhd_buffer.hex_dump(m_m4aHdr.sizeof_mdhd); + /* version; 1 Byte offset 0 0 -> 32 bit, 1 -> 64 bit + flags[3]; 3 Bytes offset 1 + creation_time; 4 Bytes offset 4 + modification_time; 4 Bytes offset 8 + timescale; 4 Bytes offset 12 + duration; 4 Bytes offset 16 + language; 2 Bytes offset 20 + pre_defined; 2 Bytes offset 22 */ + m_m4aHdr.timescale = bigEndian((uint8_t*)mdhd_buffer.get() + 12, 4); + m_m4aHdr.duration = bigEndian((uint8_t*)mdhd_buffer.get() + 16, 4); + if (m_m4aHdr.timescale) { + m_audioFileDuration = m_m4aHdr.duration / m_m4aHdr.timescale; + info(*this, evt_info, "Duration (s): {}", m_audioFileDuration); + } + m_m4aHdr.retvalue += m_m4aHdr.sizeof_mdhd; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_mdhd; + m_controlCounter = M4A_MDIA; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_STBL) { // minf + if (atom_struct) { AUDIO_LOG_WARN("stbl size remain {}", m_m4aHdr.sizeof_stbl); } + if (m_m4aHdr.sizeof_stbl == 0) { + m_controlCounter = M4A_MINF; + return 0; + } // go back + + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + m_m4aHdr.sizeof_stbl -= atom_size.to_uint32(16); + + if (atom_name.equals("stsd")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + uint8_t header_size = 8; + m_m4aHdr.sizeof_stsd = atom_size.to_uint32(16) - 8 - header_size; + m_m4aHdr.retvalue += 8 + header_size; + m_m4aHdr.headerSize += 8 + header_size; + m_controlCounter = M4A_STSD; + return 0; + } + + if (atom_name.equals("stsz")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + uint8_t header_size = 8; + m_m4aHdr.sizeof_stsz = atom_size.to_uint32(16) - 8 - header_size; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_STSZ; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_STSD) { + if (atom_struct) { AUDIO_LOG_WARN("stsd size remain {}", m_m4aHdr.sizeof_stsd); } + if (m_m4aHdr.sizeof_stsd == 0) { + m_controlCounter = M4A_STBL; + return 0; + } // go back + + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + m_m4aHdr.sizeof_stsd -= atom_size.to_uint32(16); + + if (atom_name.equals("mp4a")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_mp4a = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_MP4A; + return 0; + } + + if (atom_name.equals("alac")) { + AUDIO_LOG_ERROR("Apple loseless audio codec (ALAC) not supported"); + stopSong(); + return 0; + } + + if (atom_name.equals("ac-3")) { + AUDIO_LOG_ERROR("Dolby Digital not supported"); + stopSong(); + return 0; + } + + if (atom_name.equals("ec-3")) { + AUDIO_LOG_ERROR("Dolby Digital Plud not supported"); + stopSong(); + return 0; + } + + if (atom_name.equals("Opus")) { + // todo + stopSong(); + return 0; + } + + if (atom_name.equals("mp3 ")) { + // todo + stopSong(); + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_CHPL) { + if (atom_struct) { AUDIO_LOG_WARN("chpl size remain {}", m_m4aHdr.sizeof_chpl); } + if (m_m4aHdr.sizeof_chpl == 0) { + m_controlCounter = M4A_UDTA; + return 0; + } // go back + + ps_ptr title_name; + // data[0] version + // data[1] 4 flags + uint32_t nr_of_chapters = bigEndian(data + 5, 4); // Number of chapters + // data[9] uint64 timestamp + uint8_t title_length = data[17]; + title_name.copy_from((char*)data + 18, title_length); + + info(*this, evt_info, "Number of chapters: {}", nr_of_chapters); + info(*this, evt_info, "Chapter name: {}", title_name.c_get()); + + m_m4aHdr.retvalue += m_m4aHdr.sizeof_chpl; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_chpl; + m_m4aHdr.sizeof_chpl = 0; // there are no subatoms + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_MP4A) { + if (atom_struct) { AUDIO_LOG_WARN("mp4a size remain {}", m_m4aHdr.sizeof_mp4a); } + if (m_m4aHdr.sizeof_mp4a == 0) { + m_controlCounter = M4A_STSD; + return 0; + } // go back + + if (!m_m4aHdr.sample_rate) { // read the header first + // data[0]...[5] reserved + // data[6] & [7] Data reference buffer_index + // data[8]...[15] reserved + m_m4aHdr.channel_count = data[16] * 256 + data[17]; + AUDIO_LOG_DEBUG("channels {}", m_m4aHdr.channel_count); + m_m4aHdr.sample_size = data[18] * 256 + data[19]; + AUDIO_LOG_DEBUG("bit per sample {}", m_m4aHdr.sample_size); + // data[20]...data[23] reserved + m_m4aHdr.sample_rate = data[24] * 256 + data[25]; + AUDIO_LOG_DEBUG("sample rate {}", m_m4aHdr.sample_rate); + // data[26]...data[27] sample rate fixed point is 0x00, 0x00 + m_m4aHdr.offset = 28; + m_m4aHdr.retvalue += m_m4aHdr.offset; + m_m4aHdr.headerSize += m_m4aHdr.offset; + m_m4aHdr.sizeof_mp4a -= m_m4aHdr.offset; + return 0; + } + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + m_m4aHdr.sizeof_mp4a -= atom_size.to_uint32(16); + + if (atom_name.equals("esds")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_esds = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_ESDS; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_UDTA) { // udta + if (atom_struct) { AUDIO_LOG_WARN("udta size remain {}", m_m4aHdr.sizeof_udta); } + if (m_m4aHdr.sizeof_udta == 0) { + m_controlCounter = M4A_MOOV; + return 0; + } // go back + + atom_size.big_endian(data, 4); + atom_name.copy_from((const char*)data + 4, 4); + m_m4aHdr.sizeof_udta -= atom_size.to_uint32(16); + + if (atom_name.equals("meta")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_meta = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_META; + return 0; + } + + if (atom_name.equals("chpl")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_chpl = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_CHPL; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_META) { // meta + if (atom_struct) { AUDIO_LOG_WARN("meta size remain {}", m_m4aHdr.sizeof_meta); } + if (m_m4aHdr.sizeof_meta == 0) { + m_controlCounter = M4A_UDTA; + return 0; + } // go back, 4bytes typ + 4 bytes size + + if (!m_m4aHdr.version_flags) { + // 0x00, 0x00, 0x00, 0x94, 0x6D, 0x65, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, + // size | m e t a | flags + m_m4aHdr.version_flags = true; + m_m4aHdr.sizeof_meta -= 4; + m_m4aHdr.retvalue += 4; + m_m4aHdr.headerSize += 4; + idx += 4; + } + atom_size.big_endian(data + idx, 4); + atom_name.copy_from((const char*)data + 4 + idx, 4); + m_m4aHdr.sizeof_meta -= atom_size.to_uint32(16); + + if (atom_name.equals("ilst")) { + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.sizeof_ilst = atom_size.to_uint32(16) - 8; + m_m4aHdr.retvalue += 8; + m_m4aHdr.headerSize += 8; + m_controlCounter = M4A_ILST; + return 0; + } + + if (atom_struct) { AUDIO_LOG_WARN("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), m_m4aHdr.headerSize, atom_size.to_uint32(16), m_m4aHdr.headerSize + atom_size.to_uint32(16)); } + m_m4aHdr.retvalue += atom_size.to_uint32(16); + m_m4aHdr.headerSize += atom_size.to_uint32(16); + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_ESDS) { // Elementary Stream Descriptor + ps_ptr esds_buffer; // read ESDS content in a buffer + esds_buffer.copy_from((char*)data, m_m4aHdr.sizeof_esds); // read ESDS content (without header) + // esds_buffer.hex_dump(m_m4aHdr.sizeof_esds); + + // search for decoderConfigDescriptor (tag 0x04) + int32_t dec_config_descriptor_offset = esds_buffer.special_index_of("\x04\x80\x80\x80", 4, (uint32_t)m_m4aHdr.sizeof_esds); + if (dec_config_descriptor_offset > 0) { // decoderConfigDescriptor found + uint8_t dec_config_descriptor_length = ((uint8_t*)esds_buffer.get())[dec_config_descriptor_offset + 4]; // Length after Tag + 3 Extended Length Bytes + m_m4aHdr.objectTypeIndicator = ((uint8_t*)esds_buffer.get())[dec_config_descriptor_offset + 5]; // 0x40 (AAC) + m_m4aHdr.streamType = ((uint8_t*)esds_buffer.get())[dec_config_descriptor_offset + 6]; // 0x05 (Audio) + m_m4aHdr.bufferSizeDB = bigEndian((uint8_t*)esds_buffer.get() + dec_config_descriptor_offset + 7, 3); // 24 bit + m_m4aHdr.maxBitrate = bigEndian((uint8_t*)esds_buffer.get() + dec_config_descriptor_offset + 10, 4); // 32 bit + m_m4aHdr.nomBitrate = bigEndian((uint8_t*)esds_buffer.get() + dec_config_descriptor_offset + 14, 4); // 32 bit + // info(*this, evt_info, "maxBitrate {}, nominalBitrate {}", m_m4aHdr.maxBitrate, m_m4aHdr.nomBitrate); + } + + // search for decoderspecificinfo (tag 0x05) + int32_t dec_specific_offset = esds_buffer.special_index_of("\x05\x80\x80\x80", 4, m_m4aHdr.sizeof_esds); + if (dec_specific_offset >= 0) { // decoderSpecificInfo found + uint8_t dec_specific_length = ((uint8_t*)esds_buffer.get())[dec_specific_offset + 4]; // Länge nach Tag + 3 Extended Length Bytes + AUDIO_LOG_DEBUG("DecoderSpecificInfo found at offset {}, length: {}", dec_specific_offset, dec_specific_length); + + // extract decoderSpecificInfo-data + ps_ptr dec_specific_data; + dec_specific_data.alloc(dec_specific_length, "dec_specific_data"); + memcpy(dec_specific_data.get(), (uint8_t*)esds_buffer.get() + dec_specific_offset + 5, dec_specific_length); + m_m4aHdr.aac_profile = (uint8_t)dec_specific_data.get()[0] >> 3; + if (m_m4aHdr.aac_profile > 4) { + AUDIO_LOG_ERROR("unsupported AAC Profile {}", m_m4aHdr.aac_profile); + stopSong(); + return 0; + } + AUDIO_LOG_DEBUG("DecoderSpecificInfo data: 0x{:02X} 0x{:02X}", (uint8_t)dec_specific_data.get()[0], (uint8_t)dec_specific_data.get()[1]); + char profile[5][33] = {"unknown", "AAC Main", "AAC LC (Low Complexity)", "AAC SSR (Scalable Sample Rate)", "AAC LTP (Long Term Prediction)"}; + info(*this, evt_info, "AAC Profile: {}", profile[m_m4aHdr.aac_profile]); + info(*this, evt_info, "AAC Channels; {}", m_m4aHdr.channel_count); + info(*this, evt_info, "AAC Sample Rate: {}", m_m4aHdr.sample_rate); + info(*this, evt_info, "AAC Bits Per Sample: {}", m_m4aHdr.sample_size); + m_M4A_chConfig = m_m4aHdr.channel_count; + m_M4A_sampleRate = m_m4aHdr.sample_rate; + m_M4A_objectType = m_m4aHdr.aac_profile; + } else { + AUDIO_LOG_WARN("No DecoderSpecificInfo found in esds"); + } + m_m4aHdr.retvalue += m_m4aHdr.sizeof_esds; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_esds; + m_controlCounter = M4A_MP4A; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_ILST) { + + auto parse_m4a_timestamp = [&](const char* s) { + if (!s || *s != '[') return -1; + int mm = 0, ss = 0, hh = 0; + if (sscanf(s, "[%d:%d.%d]", &mm, &ss, &hh) == 3) { return mm * 60000 + ss * 1000 + hh * 10; } + return -1; + }; + + struct TagInfo { // Definition of the Taginfo structure for iTunes-style metadata + const uint8_t tag[4]; + const char* name; + const char* descr; + }; + const TagInfo tags[] = { + // List of all usual tags + {{0xA9, 0x6E, 0x61, 0x6D}, "©nam", "Title"}, {{0xA9, 0x41, 0x52, 0x54}, "©ART", "Artist"}, {{0xA9, 0x61, 0x72, 0x74}, "©art", "Artist"}, + {{0xA9, 0x61, 0x6C, 0x62}, "©alb", "Album"}, {{0xA9, 0x74, 0x6F, 0x6F}, "©too", "Encoder"}, {{0xA9, 0x63, 0x6D, 0x74}, "©cmt", "Comment"}, + {{0xA9, 0x77, 0x72, 0x74}, "©wrt", "Composer"}, {{0x74, 0x6D, 0x70, 0x6F}, "tmpo", "Tempo (BPM)"}, {{0x74, 0x72, 0x6B, 0x6E}, "trkn", "Track-Number"}, + {{0xA9, 0x64, 0x61, 0x79}, "©day", "Year"}, {{0x63, 0x70, 0x69, 0x6C}, "cpil", "Compilation-Flag"}, {{0x61, 0x41, 0x52, 0x54}, "aART", "Album Artist"}, + {{0xA9, 0x67, 0x65, 0x6E}, "©gen", "Genre"}, {{0x63, 0x6F, 0x76, 0x72}, "covr", "Cover Art"}, {{0x64, 0x69, 0x73, 0x6B}, "disk", "Disk-Nummer"}, + {{0xA9, 0x6C, 0x79, 0x72}, "©lyr", "Songtext"}, {{0xA9, 0x70, 0x72, 0x74}, "cprt", "Copyright"}, {{0x67, 0x6E, 0x72, 0x65}, "gnre", "Genre-ID"}, + {{0x72, 0x74, 0x6E, 0x67}, "rtng", "Evaluation"}, {{0x70, 0x67, 0x61, 0x70}, "pgap", "Gapless Playback"}, + }; + const size_t tags_count = sizeof(tags) / sizeof(tags[0]); // Number of tags + + ps_ptr id3tag; + ps_ptr lyricsBuffer; + uint32_t pos = m_m4aHdr.headerSize; + uint32_t consumed = 0; + while (true) { + atom_size.big_endian(data + consumed, 4); + atom_name.copy_from((const char*)data + 4 + consumed, 4); + uint32_t as = atom_size.to_uint32(16); + AUDIO_LOG_DEBUG("atom {} @ {}, size: {}, ends @ {}", atom_name.c_get(), pos, as, pos + as); + m_m4aHdr.ilst_pos += as; + pos += as; + consumed += as; + + // 0x00, 0x00, 0x00, 0x1C, 0xA9, 0x64, 0x61, 0x79, 0x00, 0x00, 0x00, 0x14, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x32, 0x32, + // sub atom length | © d a y | sub sub atom length | d a t a | data type 1->UTF-8 | reserved | 2 0 2 2 + + ps_ptr sa; // sub atom + sa.copy_from((const char*)data + consumed - as, min(as, (uint32_t)1024)); + + char san[5] = {0}; // sub atom name + char ssan[5] = {0}; // sub sub atom name (should be 'data') + strncpy(san, &sa[4], 4); + strncpy(ssan, &sa[12], 4); + uint32_t ssal = bigEndian((uint8_t*)&sa[8], 4); // sub sub atom length + uint32_t dty = bigEndian((uint8_t*)&sa[16], 4); // data type 1-UTF8 + if (strncmp(ssan, "data", 4) == 0) { + for (int i = 0; i < tags_count; i++) { + if (memcmp(san, tags[i].tag, 4) == 0) { + id3tag.reset(); + if (dty == 0 && strlen(&sa[24]) > 0) { + if (strcmp(san, "covr") == 0) { + m_m4aHdr.picLen = as - 24; + m_m4aHdr.picPos = pos + 24 - as; + AUDIO_LOG_DEBUG("cover jpeg start: {}, len {}", m_m4aHdr.picPos, m_m4aHdr.picLen); + } + id3tag.assignf("{}: {}", tags[i].descr, &sa[24]); // binary + } else if (dty == 1 && strlen(&sa[24]) > 0) + id3tag.assignf("{}: {}", tags[i].descr, &sa[24]); // UTF-8 Text + else if (dty == 0x0D) { + m_m4aHdr.picLen = as - 24; + m_m4aHdr.picPos = pos + 24 - as; + AUDIO_LOG_DEBUG("cover jpeg start: {}, len {}", m_m4aHdr.picPos, m_m4aHdr.picLen); + } // jpeg + else if (dty == 0x0E) { + m_m4aHdr.picLen = as - 24; + m_m4aHdr.picPos = pos + 24 - as; + AUDIO_LOG_WARN("cover png start: {}, len {}", m_m4aHdr.picPos, m_m4aHdr.picLen); + } // png + else if (dty == 21) { + if (memcmp(tags[i].tag, "cpil", 4) == 0) { break; } // Compilation Flag + if (memcmp(tags[i].tag, "pgap", 4) == 0) { break; } // Gapless Playback + if (memcmp(tags[i].tag, "rtng", 4) == 0) { break; } // Evaluation + } + if (id3tag.valid()) { info(*this, evt_id3data, "{}", id3tag.get()); } + if (strcmp(tags[i].descr, "Songtext") == 0) { lyricsBuffer.copy_from(&sa[24]); } + break; + } + } + } else + AUDIO_LOG_DEBUG("{} tag not supported", san); + + if (consumed > len + m_m4aHdr.ilst_already_consumed) { // ILST > len can happen + m_m4aHdr.ilst_already_consumed += len; + m_m4aHdr.retvalue = consumed; + m_m4aHdr.headerSize += consumed; + m_controlCounter = M4A_ILST; + return 0; + } + + if (m_m4aHdr.sizeof_ilst <= m_m4aHdr.ilst_pos) { + + ps_ptr tmp; // last todo if we have lyrics + ps_ptr timestamp; + timestamp.alloc(12, "timestamp"); + if (lyricsBuffer.valid()) { + lyricsBuffer.remove_prefix("LYRICS="); + idx = 0; + while (idx < lyricsBuffer.size()) { + int pos = lyricsBuffer.index_of('\n', idx); + if (pos == -1) break; + int len = pos - idx + 1; + tmp.copy_from(lyricsBuffer.get() + idx, len); + idx += len; + if (tmp.ends_with("\n")) tmp.truncate_at('\n'); + // tmp content e.g.: [00:27.07]Jetzt kommt die Zeit + // [00:28.84]Auf die ihr euch freut + timestamp.copy_from(tmp.get(), 10); + + int ms = parse_m4a_timestamp(timestamp.c_get()); + + // timestamp.remove_chars("[]:."); + // timestamp.append("0"); // to ms 0028840 + tmp.remove_before(10, true); + if (tmp.strlen() > 0) { + m_syltLines.push_back(std::move(tmp)); + m_syltTimeStamp.push_back(ms); + } + } + info(*this, evt_info, "audiofile contains synchronized lyrics"); + // for(int i = 0; i < m_syltLines.size(); i++){ + // info(*this, evt_lyrics, "{:07} ms, {}", m_syltTimeStamp[i], m_syltLines[i].c_get()); + // } + } + m_m4aHdr.retvalue = consumed; + m_m4aHdr.headerSize += consumed; + m_controlCounter = M4A_META; + break; + } + } + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_controlCounter == M4A_STSZ) { + uint8_t version = data[0]; + (void)version; + uint32_t flags = bigEndian(data + 1, 3); + (void)flags; + uint32_t sample_size = bigEndian(data + 4, 4); + (void)sample_size; + m_m4aHdr.stsz_num_entries = bigEndian(data + 8, 4); + m_m4aHdr.stsz_table_pos = m_m4aHdr.headerSize + 12; + m_m4aHdr.retvalue += m_m4aHdr.sizeof_stsz + 8; + m_m4aHdr.headerSize += m_m4aHdr.sizeof_stsz + 8; + m_controlCounter = M4A_STBL; + return 0; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + uint8_t extLen = 0; + if (m_controlCounter == M4A_MDAT) { // mdat + // ps_ptr hd; + // hd.copy_from((const char*)data, 30); + // hd.hex_dump(30); + m_audioDataSize = m_m4aHdr.sizeof_mdat; // length of this atom + + // Extended Size + // 00 00 00 01 6D 64 61 74 00 00 00 00 00 00 16 64 + // 0001 m d a t 5732 + + if (m_audioDataSize == 1) { // Extended Size + m_audioDataSize = bigEndian(data + 8, 8); + m_audioDataSize -= 16; + extLen = 8; + } else { + m_audioDataSize -= 8; + } + m_m4aHdr.retvalue = extLen; + m_m4aHdr.headerSize += extLen; + m_controlCounter = M4A_AMRDY; // last step before starting the audio + return 0; + } + + if (m_controlCounter == M4A_AMRDY) { // almost ready + m_audioDataStart = m_m4aHdr.headerSize; + if (m_m4aHdr.picLen) { + size_t pos = m_audioFilePosition; + std::vector vec; + vec.push_back(m_m4aHdr.picPos); + vec.push_back(m_m4aHdr.picLen); + info(*this, evt_image, vec); + vec.clear(); + audioFileSeek(pos); // the filepointer could have been changed by the user, set it back + } + m_stsz_numEntries = m_m4aHdr.stsz_num_entries; + m_stsz_position = m_m4aHdr.stsz_table_pos; + info(*this, evt_info, "Audio-Data-Start: {}", m_audioDataStart); + info(*this, evt_info, "Audio-Length: {}", m_audioDataSize); + if (m_audioFileDuration) { + m_nominal_bitrate = (m_audioDataSize * 8) / m_audioFileDuration; + info(*this, evt_info, "Duration (s): {}", m_audioFileDuration); + } + + m_controlCounter = M4A_OKAY; // that's all + return 0; + } + // this section should never be reached + AUDIO_LOG_ERROR("error"); + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +size_t Audio::process_m3u8_ID3_Header(uint8_t* packet) { + uint8_t ID3version; + size_t id3Size; + bool m_f_unsync = false, m_f_exthdr = false; + uint64_t current_timestamp = 0; + + (void)m_f_unsync; // suppress -Wunused-variable + (void)current_timestamp; // suppress -Wunused-variable + + if (specialIndexOf(packet, "ID3", 4) != 0) { // ID3 not found + // AUDIO_LOG_INFO("m3u8 file has no mp3 tag"); + return 0; // error, no ID3 signature found + } + ID3version = *(packet + 3); + switch (ID3version) { + case 2: + m_f_unsync = (*(packet + 5) & 0x80); + m_f_exthdr = false; + break; + case 3: + case 4: + m_f_unsync = (*(packet + 5) & 0x80); // bit7 + m_f_exthdr = (*(packet + 5) & 0x40); // bit6 extended header + break; + }; + id3Size = bigEndian(&packet[6], 4, 7); // ID3v2 size 4 * %0xxxxxxx (shift left seven times!!) + id3Size += 10; + // AUDIO_LOG_INFO("ID3 framesSize: {}", id3Size); + // AUDIO_LOG_INFO("ID3 version: 2.{}", ID3version); + + if (m_f_exthdr) { + AUDIO_LOG_ERROR("ID3 extended header in m3u8 files not supported"); + return 0; + } + // AUDIO_LOG_INFO("ID3 normal frames"); + + if (specialIndexOf(&packet[10], "PRIV", 5) != 0) { // tag PRIV not found + AUDIO_LOG_ERROR("tag PRIV in m3u8 Id3 Header not found"); + return 0; + } + // if tag PRIV exists assume content is "com.apple.streaming.transportStreamTimestamp" + // a time stamp is expected in the header. + + current_timestamp = (double)bigEndian(&packet[69], 4) / 90000; // seconds + + return id3Size; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::stopSong() { + m_f_lockInBuffer = true; // wait for the decoding to finish + uint8_t maxWait = 0; + uint32_t currTime = getAudioCurrentTime(); + + xSemaphoreTake(mutex_audioTaskIsDecoding, 1 * configTICK_RATE_HZ); // wait for audioTask is ready + { + if (m_f_running) { + m_f_running = false; + if (m_client->connected()) { + if (m_streamType == ST_WEBSTREAM) { info(*this, evt_info, "Closing web stream \"{}\"", m_lastHost.c_get()); } + if (m_streamType == ST_WEBFILE) { info(*this, evt_info, "Closing web file \"{}\"", m_lastHost.c_get()); } + m_client->stop(); + } + if (m_audiofile) { + info(*this, evt_info, "Closing audio file \"{}\"", m_audiofile.name()); + m_audiofile.close(); + } + } + destroy_decoder(); + m_f_lockInBuffer = false; + } + xSemaphoreGive(mutex_audioTaskIsDecoding); + return currTime; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::pauseResume() { + xSemaphoreTake(mutex_audioTask, 0.3 * configTICK_RATE_HZ); + bool retVal = false; + if (m_dataMode == AUDIO_LOCALFILE || m_streamType == ST_WEBSTREAM || m_streamType == ST_WEBFILE) { + m_f_running = !m_f_running; + retVal = true; + if (!m_f_running) { + m_outBuff.clear(); + memset(m_resamplesBuff.get(), 0, m_resamplesBuffSize * sizeof(int16_t)); // Clear SamplesBuffer + m_validSamples = 0; + } + } + xSemaphoreGive(mutex_audioTask); + return retVal; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +audiolib::BiquadCoeffs Audio::makeButterworthLPF_Q31(float fs) { // Calculation of the biquad coefficients for the resampler + + float fc = 0.45f * fs; + if (fc > 20000.0f) fc = 20000.0f; // absolute upper limit (security) + if (fc < 3000.0f) fc = 3000.0f; // absolute lower limit (prevents “thin” sound) + + constexpr float Q = 0.70710678f; + + float w0 = 2.0f * M_PI * fc / fs; + float cw = cosf(w0); + float sw = sinf(w0); + float alpha = sw / (2.0f * Q); + + float b0 = (1.0f - cw) * 0.5f; + float b1 = 1.0f - cw; + float b2 = (1.0f - cw) * 0.5f; + float a0 = 1.0f + alpha; + float a1 = -2.0f * cw; + float a2 = 1.0f - alpha; + + // normalize + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + // convert to Q31 + constexpr float Q31 = 2147483648.0f; // 2^31 + + audiolib::BiquadCoeffs c; + c.b0 = (int32_t)lrintf(b0 * Q31); + c.b1 = (int32_t)lrintf(b1 * Q31); + c.b2 = (int32_t)lrintf(b2 * Q31); + c.a1 = (int32_t)lrintf(a1 * Q31); + c.a2 = (int32_t)lrintf(a2 * Q31); + + return c; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::resampleI2Soutput(audiolib::resampler_t& rs, int32_t* input, uint32_t inputSamples, int32_t* output) { + + auto lerp_q32 = [&](int32_t a, int32_t b, uint32_t frac) -> int32_t { return a + (int32_t)(((int64_t)(b - a) * frac) >> 32); }; + auto biquadProcess = [&](audiolib::Biquad& s, const audiolib::BiquadCoeffs& c, int32_t x) -> int32_t { + // Q31 signal, Q31 coeffs → Q62 acc + int64_t acc = (int64_t)c.b0 * x + s.z1; + s.z1 = (int64_t)c.b1 * x - (int64_t)c.a1 * (acc >> 31) + s.z2; + s.z2 = (int64_t)c.b2 * x - (int64_t)c.a2 * (acc >> 31); + int64_t y = acc >> 31; + if (y > INT32_MAX) return INT32_MAX; + if (y < INT32_MIN) return INT32_MIN; + return (int32_t)y; + }; + + uint32_t outFrames = 0; + uint32_t i = 0; + + // If we have a "last" from the previous frame, start with that + if (rs.hasLast && inputSamples > 0) { + int32_t l0 = rs.lastL; + int32_t r0 = rs.lastR; + int32_t l1 = input[0]; + int32_t r1 = input[1]; + + // Continue processing with the old phase value + while ((rs.phase >> 32) == 0) { + uint32_t frac = (uint32_t)rs.phase; + int32_t l = lerp_q32(l0, l1, frac); + int32_t r = lerp_q32(r0, r1, frac); + + l = biquadProcess(rs.lpLeft, rs.g_lpCoeffs, l); + r = biquadProcess(rs.lpRight, rs.g_lpCoeffs, r); + + output[outFrames * 2] = l; + output[outFrames * 2 + 1] = r; + ++outFrames; + + rs.phase += rs.phaseStep; + } + rs.phase -= (1ULL << 32); + // i remains 0, we haven't used input[0] as "l0" yet! + } + + // Rest of the frame as usual + for (; i + 1 < inputSamples; ++i) { + int32_t l0 = input[i * 2]; + int32_t r0 = input[i * 2 + 1]; + int32_t l1 = input[(i + 1) * 2]; + int32_t r1 = input[(i + 1) * 2 + 1]; + + while ((rs.phase >> 32) == 0) { + uint32_t frac = (uint32_t)rs.phase; + int32_t l = lerp_q32(l0, l1, frac); + int32_t r = lerp_q32(r0, r1, frac); + + l = biquadProcess(rs.lpLeft, rs.g_lpCoeffs, l); + r = biquadProcess(rs.lpRight, rs.g_lpCoeffs, r); + + output[outFrames * 2] = l; + output[outFrames * 2 + 1] = r; + ++outFrames; + + rs.phase += rs.phaseStep; + } + rs.phase -= (1ULL << 32); + } + + // Save last sample for next frame + if (inputSamples > 0) { + rs.lastL = input[(inputSamples - 1) * 2]; + rs.lastR = input[(inputSamples - 1) * 2 + 1]; + rs.hasLast = true; + } + + return outFrames; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void IRAM_ATTR Audio::playChunk() { + if (m_validSamples == 0) return; // nothing to do + + bool continueI2S = true; + m_plCh.i2s_bytesConsumed = 0; + m_plCh.err = ESP_OK; + + constexpr int BYTES_PER_FRAME = 2 * sizeof(int32_t); + + if (m_plCh.count > 0) goto i2swrite; // Not all samples could be written to I2S during the last run + audio_process_raw_samples(m_outBuff.get(), m_validSamples); + //------------------------------------------------------------------------------------------ + { + const bool applyGain = settings.VOLUME_CONTROL && (m_audio_items.limiter[LEFTCHANNEL] != 1.0f || m_audio_items.limiter[RIGHTCHANNEL] != 1.0f); + for (int i = 0; i < m_validSamples; i++) { + if (settings.VU_LEVEL) calculateVUlevel(&m_outBuff[i * 2]); + if (settings.IIR_FILTER) IIR_filter(&m_outBuff[i * 2]); + if (applyGain) Gain(&m_outBuff[i * 2]); + } + } + if (settings.SPECTRUM) processSpectrum(); + if (m_f_forceMono) stereo2mono(m_outBuff.get(), m_validSamples); + //------------------------------------------------------------------------------------------ + if (m_output_sr && m_output_sr != m_i2s_items.sampleRate) { + m_validSamples = resampleI2Soutput(m_resampler, m_outBuff.get(), m_validSamples, m_resamplesBuff.get()); // have new amount of samples + audio_process_i2s(m_resamplesBuff.get(), m_validSamples, &continueI2S); // resampled stereo 32bps + } else { + audio_process_i2s(m_outBuff.get(), (int32_t)m_validSamples, &continueI2S); + } + //------------------------------------------------------------------------------------------------------ + if (!continueI2S) { + m_validSamples = 0; + m_plCh.count = 0; + return; + } + //------------------------------------------------------------------------------------------------------ + +i2swrite: + if (m_output_sr && m_output_sr != m_i2s_items.sampleRate) { // with resampler + m_plCh.err = i2s_channel_write(m_i2s_tx_handle, m_resamplesBuff.get() + m_plCh.count, m_validSamples * BYTES_PER_FRAME, &m_plCh.i2s_bytesConsumed, 50); + } else { // without resampler + m_plCh.err = i2s_channel_write(m_i2s_tx_handle, m_outBuff.get() + m_plCh.count, m_validSamples * BYTES_PER_FRAME, &m_plCh.i2s_bytesConsumed, 20); + } + + if (!(m_plCh.err == ESP_OK || m_plCh.err == ESP_ERR_TIMEOUT)) goto exit; + m_validSamples -= m_plCh.i2s_bytesConsumed / BYTES_PER_FRAME; + m_plCh.count += m_plCh.i2s_bytesConsumed / 2; + if (m_validSamples <= 0) { + m_validSamples = 0; + m_plCh.count = 0; + } + + // ---- statistics, bytes written to I2S (every 10s) + // static int cnt = 0; + // static uint32_t t = millis(); + + // if(t + 10000 < millis()){ + // AUDIO_LOG_INFO("{}", cnt); + // cnt = 0; + // t = millis(); + // } + // cnt+= i2s_bytesConsumed; + //------------------------------------------- + + return; +exit: + if (m_plCh.err == ESP_OK) + return; + else if (m_plCh.err == ESP_ERR_INVALID_ARG) + AUDIO_LOG_ERROR("NULL pointer or this handle is not tx handle"); + else if (m_plCh.err == ESP_ERR_TIMEOUT) + AUDIO_LOG_ERROR("Writing timeout, no writing event received from ISR within ticks_to_wait"); + else if (m_plCh.err == ESP_ERR_INVALID_STATE) + AUDIO_LOG_ERROR("I2S is not ready to write"); + else + AUDIO_LOG_ERROR("i2s err {}", m_plCh.err); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::loop() { + get_info(); + if (!m_f_running) return; + + if (m_f_firstLoop) { + m_f_firstLoop = false; + memset(&m_lVar, 0, sizeof(m_lVar)); + } + + if (m_playlistFormat != FORMAT_M3U8) { // normal process + switch (m_dataMode) { + case AUDIO_LOCALFILE: processLocalFile(); break; + case HTTP_RESPONSE_HEADER: + if (!parseHttpResponseHeader()) { + if (m_f_timeout && m_lVar.count < 3) { + m_f_timeout = false; + m_lVar.count++; + connecttohost(m_lastHost.get()); + } + } else { + m_lVar.count = 0; + } + break; + case AUDIO_PLAYLISTINIT: readPlayListData(); break; + case AUDIO_PLAYLISTDATA: + if (m_playlistFormat == FORMAT_M3U) httpPrint(parsePlaylist_M3U()); + if (m_playlistFormat == FORMAT_PLS) httpPrint(parsePlaylist_PLS()); + if (m_playlistFormat == FORMAT_ASX) httpPrint(parsePlaylist_ASX()); + break; + case AUDIO_DATA: + if (m_streamType == ST_WEBSTREAM) processWebStream(); + if (m_streamType == ST_WEBFILE) processWebFile(); + break; + } + } else { // m3u8 datastream only + ps_ptr host; + switch (m_dataMode) { + case HTTP_RESPONSE_HEADER: + if (!parseHttpResponseHeader()) { + if (m_lVar.count < 3) { + m_lVar.count++; + connecttohost(m_lastHost.get()); + } else { + stopSong(); + } + } else { + m_lVar.count = 0; + m_f_firstCall = true; // read ID3 header in processWebStreamHLS/TS() + } + break; + case AUDIO_PLAYLISTINIT: + if (readPlayListData()) + break; + else { // readPlayListData == false means connect to m3u8 URL + httpPrint(m_m3u8_host.get()); + m_dataMode = HTTP_RESPONSE_HEADER; // we have a new playlist now + break; + } + case AUDIO_PLAYLISTDATA: + host = parsePlaylist_M3U8(); + if (host.valid()) { // host contains the next playlist URL + httpPrint(host.get()); + m_dataMode = HTTP_RESPONSE_HEADER; + } else { // host == NULL means connect to m3u8 URL + if (m_lVar.no_host_timer > millis()) { + // AUDIO_LOG_DEBUG("wait"); + break; + } + if (m_f_stream) m_lVar.no_host_timer = millis() + 10000; + httpPrint(m_m3u8_host.get()); + m_dataMode = HTTP_RESPONSE_HEADER; // we have a new playlist now + } + break; + case AUDIO_DATA: + if (m_f_ts) { + processWebStreamTS(); // aac, mp3 or aacp with ts packets + } else { + processWebStreamHLS(); // aac, mp3 or aacp normal stream + } + + if (m_f_continue) { // at this point m_f_continue is true, means processWebStream() needs more data + m_dataMode = AUDIO_PLAYLISTDATA; + m_f_continue = false; + } + break; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::readPlayListData() { + + int32_t chunkLen = 0; + uint16_t readedBytes = 0; + ps_ptr pl; + uint32_t ctl = 0; + size_t plSize = 0; + + auto detectTimeout = [&]() -> bool { + uint32_t t = millis(); + while (!m_client->available()) { + vTaskDelay(2); + if (t + 2000 < millis()) { + AUDIO_LOG_WARN("Playlist is incomplete, fetch again"); + if (m_f_chunked) getChunkSize(0, true); + return true; + } + } + return false; + }; + + if (m_dataMode != AUDIO_PLAYLISTINIT) { + AUDIO_LOG_ERROR("wrong datamode {}", dataModeStr[m_dataMode]); + goto exit; + } + + if (m_f_chunked) { + getChunkSize(0, true); + chunkLen = getChunkSize(&readedBytes); + if (chunkLen <= 0) { + AUDIO_LOG_ERROR("chunked datatransfer but chunkLen is invalid"); + goto exit; + } + plSize = chunkLen; + } else { + plSize = m_audioFileSize; + } + + if (!plSize) { // maybe playlist without contentLength or chunkSize + AUDIO_LOG_ERROR("file size is not given"); + goto exit; + } + + pl.alloc(2048, "pl"); + // delete all memory in m_playlistContent + if (m_playlistFormat == FORMAT_M3U8 && !psramFound()) { AUDIO_LOG_ERROR("m3u8 playlists requires PSRAM enabled!"); } + vector_clear_and_shrink(m_playlistContent); + + while (true) { // outer while + uint32_t ctime = millis(); + uint32_t timeout = 2000; // ms + + pl.clear(); // playlistLine + + while (true) { // inner while + uint16_t pos = 0; + while (true) { // super inner while :-)) + uint32_t t = millis(); + if (ctl == plSize) break; + if (detectTimeout()) goto exit; + pl[pos] = audioFileRead(); + ctl++; + if (pl[pos] == '\n') { + pl[pos] = '\0'; + pos++; + break; + } + if (pl[pos] == '\r') { + pl[pos] = '\0'; + pos++; + continue; + } + pos++; + if (pos == 2044) { + pos--; + continue; + } + if (ctl == plSize) { + pl[pos] = '\0'; + break; + } + } + if (pos) { + pl[pos] = '\0'; + break; + } + if (ctl == plSize) break; + if (detectTimeout()) goto exit; + } // inner while + AUDIO_LOG_DEBUG("PL: {}", pl.c_get()); + if (pl.starts_with_icase("stop(); + httpPrint(m_m3u8_host.c_get()); + return true; + } + } + } + //-------------------------------------------------------------------------------------------------------------- + + // AUDIO_LOG_INFO("current playlist line: {}", pl.get()); + if (pl.size() > 0) m_playlistContent.emplace_back(pl); + + // termination conditions + // 1. The http response header returns a value for contentLength -> read chars until contentLength is reached + // 2. no contentLength, but Transfer-Encoding:chunked -> compute chunksize and read until chunksize is reached + // 3. no chunksize and no contentlengt, but Connection: close -> read all available chars + if (ctl == plSize) { + if (m_f_chunked) { + chunkLen = getChunkSize(&readedBytes); // expected: "\r\n\0\r\n\r\n" if ready + if (chunkLen > 0) { + plSize += chunkLen; + continue; // next round + } + } + break; + } + } // outer while + + m_dataMode = AUDIO_PLAYLISTDATA; + return true; + +exit: + vector_clear_and_shrink(m_playlistContent); + getChunkSize(0, true); + return false; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +const char* Audio::parsePlaylist_M3U() { + + uint8_t lines = m_playlistContent.size(); + int pos = 0; + char* host = nullptr; + + for (int i = 0; i < lines; i++) { + // m_playlistContent[i].println(); + if (m_playlistContent[i].contains("#EXTINF:")) { // Info? + pos = m_playlistContent[i].index_of(","); // Comma in this line? + if (pos > 0) { + // Show artist and title if present in metadata + info(*this, evt_id3data, "{}", m_playlistContent[i].get() + pos + 1); + } + continue; + } + if (m_playlistContent[i].starts_with("#")) { // Commentline? + continue; + } + + pos = m_playlistContent[i].index_of("http://:@", 0); // ":@"?? remove that! + if (pos >= 0) { + AUDIO_LOG_INFO("Entry in playlist found: {}", (m_playlistContent[i].get() + pos + 9)); + host = m_playlistContent[i].get() + pos + 9; + break; + } + // AUDIO_LOG_INFO("Entry in playlist found: {}", pl); + pos = m_playlistContent[i].index_of("http", 0); // Search for "http" + if (pos >= 0) { // Does URL contain "http://"? + // AUDIO_LOG_ERROR("{} pos={}", m_playlistContent[i], pos); + host = m_playlistContent[i].get() + pos; // Yes, set new host + break; + } + } + // vector_clear_and_shrink(m_playlistContent); + return host; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +const char* Audio::parsePlaylist_PLS() { + uint8_t lines = m_playlistContent.size(); + int pos = 0; + char* host = nullptr; + + for (int i = 0; i < lines; i++) { + if (i == 0) { + if (m_playlistContent[0].strlen() == 0) goto exit; // empty line + if (!m_playlistContent[0].starts_with("[playlist]")) { // first entry in valid pls + m_dataMode = HTTP_RESPONSE_HEADER; // pls is not valid + AUDIO_LOG_INFO("Playlist is not valid, switch to HTTP_RESPONSE_HEADER"); + goto exit; + } + continue; + } + if (m_playlistContent[i].starts_with("File1")) { + if (host) continue; // we have already a url + pos = m_playlistContent[i].index_of("http", 0); // File1=http://streamplus30.leonex.de:14840/; + if (pos >= 0) { // yes, URL contains "http"? + host = m_playlistContent[i].get() + pos; // Now we have an URL for a stream in host. + } + continue; + } + if (m_playlistContent[i].starts_with("Title1")) { // Title1=Antenne Tirol + const char* plsStationName = (m_playlistContent[i].get() + 7); + info(*this, evt_name, "{}", plsStationName); + continue; + } + if (m_playlistContent[i].starts_with("Length1")) { continue; } + if (m_playlistContent[i].contains("Invalid username")) { // Unable to access account: + goto exit; // Invalid username or password + } + } + return host; + +exit: + m_f_running = false; + stopSong(); + vector_clear_and_shrink(m_playlistContent); + m_dataMode = AUDIO_NONE; + return nullptr; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +const char* Audio::parsePlaylist_ASX() { // Advanced Stream Redirector + uint8_t lines = m_playlistContent.size(); + bool f_entry = false; + int pos = 0; + char* host = nullptr; + + for (int i = 0; i < lines; i++) { + int p1 = m_playlistContent[i].index_of("<", 0); + int p2 = m_playlistContent[i].index_of(">", 1); + if (p1 >= 0 && p2 > p1) { // #196 set all between "< ...> to lowercase + for (uint8_t j = p1; j < p2; j++) { m_playlistContent[i][j] = toLowerCase(m_playlistContent[i][j]); } + } + if (m_playlistContent[i].contains("")) f_entry = true; // found entry tag (returns -1 if not found) + if (f_entry) { + if (m_playlistContent[i].contains("ref href")) { // + pos = m_playlistContent[i].index_of("http", 0); + if (pos > 0) { + host = (m_playlistContent[i].get() + pos); // http://87.98.217.63:24112/stream" /> + int pos1 = indexOf(host, "\"", 0); // http://87.98.217.63:24112/stream + if (pos1 > 0) host[pos1] = '\0'; // Now we have an URL for a stream in host. + } + } + } + pos = m_playlistContent[i].index_of("", 0); + if (pos >= 0) { + char* plsStationName = (m_playlistContent[i].get() + pos + 7); // remove <Title> + pos = indexOf(plsStationName, "</", 0); + if (pos >= 0) { + *(plsStationName + pos) = 0; // remove + } + info(*this, evt_name, "{}", plsStationName); + } + + if (m_playlistContent[i].starts_with("http") && !f_entry) { // url only in asx + host = m_playlistContent[i].get(); + } + } + return host; +} + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +uint16_t Audio::accomplish_m3u8_url() { + + for (uint16_t i = 0; i < m_linesWithURL.size(); i++) { + + ps_ptr tmp; + + if (!m_linesWithURL[i].starts_with("http")) { // playlist: http://station.com/aaa/bbb/xxx.m3u8 + // chunklist: http://station.com/aaa/bbb/ddd.aac + // result: http://station.com/aaa/bbb/ddd.aac + tmp = m_m3u8_host; + if (m_linesWithURL[i][0] != '/') { // playlist: http://station.com/aaa/bbb/xxx.m3u8 // tmp + // chunklist: ddd.aac // m_linesWithURL[i] + // result: http://station.com/aaa/bbb/ddd.aac // m_linesWithURL[i] + int idx = tmp.last_index_of('/'); + tmp[idx + 1] = '\0'; + tmp.append(m_linesWithURL[i].get()); + m_linesWithURL[i].clone_from(tmp); + continue; + } else { // playlist: http://station.com/aaa/bbb/xxx.m3u8 + // chunklist: /aaa/bbb/ddd.aac + // result: http://station.com/aaa/bbb/ddd.aac + int idx = tmp.index_of('/', 8); + tmp[idx] = '\0'; + tmp.append(m_linesWithURL[i].get()); + m_linesWithURL[i].clone_from(tmp); + continue; + } + } else { /* nothing todo*/ + continue; + } + } + // for(uint16_t i = 0; i < m_linesWithURL.size(); i++) m_linesWithURL[i].println(); + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int16_t Audio::prepare_first_m3u8_url(ps_ptr& playlistBuff) { + // in m_lineswithURL, searches for the first new URL through the recent URL. + // URLs that have already been used are removed from the DEQUE + // If all URLs are new, there is nothing to do and 0 is returned. + // no new URL is found -1 returned + int idx = -1; + for (int i = 0; i < m_linesWithURL.size(); i++) { + if (playlistBuff.equals(m_linesWithURL[i].get())) idx = i; + } + if (idx == -1) { + AUDIO_LOG_DEBUG("nothing found, all entries are new"); + return 0; + } + if (idx == m_linesWithURL.size()) { + AUDIO_LOG_DEBUG("only last entry found, nothing is new"); + return -1; + } + for (int j = 0; j < idx + 1; j++) { m_linesWithURL.pop_front(); } + AUDIO_LOG_DEBUG("{} entries are known and removed", idx + 1); + return idx + 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +ps_ptr Audio::parsePlaylist_M3U8() { + // example: audio chunks + // #EXTM3U + // #EXT-X-TARGETDURATION:10 + // #EXT-X-MEDIA-SEQUENCE:163374040 + // #EXT-X-DISCONTINUITY + // #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" + // http://n3fa-e2.revma.ihrhls.com/zc7729/63_sdtszizjcjbz02/main/163374038.aac + // #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" + // http://n3fa-e2.revma.ihrhls.com/zc7729/63_sdtszizjcjbz02/main/163374039.aac + + // #EXTM3U + // #EXT-X-VERSION:3 + // #EXT-X-MEDIA-SEQUENCE:0 + // #EXT-X-TARGETDURATION:4 + // #EXTINF:3.997,90s90s - Rock + // #EXT-X-PROGRAM-DATE-TIME:2025-08-17T14:08:21.088877044Z + // https://hz71.streamabc.net/hls/d2gu4l4peavc72tgotd0/regc-90s90srock1436287-mp3-192-2191420/0.mp3 + // #EXTINF:3.997,90s90s - Rock + // #EXT-X-PROGRAM-DATE-TIME:2025-08-17T14:08:24.088877044Z + // https://hz71.streamabc.net/hls/d2gu4l4peavc72tgotd0/regc-90s90srock1436287-mp3-192-2191420/1.mp3 + // #EXTINF:3.997,90s90s - Rock + // #EXT-X-PROGRAM-DATE-TIME:2025-08-17T14:08:28.088877044Z + // https://hz71.streamabc.net/hls/d2gu4l4peavc72tgotd0/regc-90s90srock1436287-mp3-192-2191420/2.mp3 + // #EXTINF:3.997,90s90s - Rock + // #EXT-X-PROGRAM-DATE-TIME:2025-08-17T14:08:32.088877044Z + // https://hz71.streamabc.net/hls/d2gu4l4peavc72tgotd0/regc-90s90srock1436287-mp3-192-2191420/3.mp3 + + if (!m_lastHost.valid()) { + AUDIO_LOG_ERROR("m_lastHost is NULL"); + return {}; + } // guard + + uint32_t lines = m_playlistContent.size(); + bool f_haveRedirection = false; + + if (lines) { + bool addNextLine = false; + deque_clear_and_shrink(m_linesWithURL); + vector_clear_and_shrink(m_linesWithEXTINF); + for (uint32_t i = 0; i < lines; i++) { + // AUDIO_LOG_INFO("pl{} = {}", i, m_playlistContent[i].get()); + if (m_playlistContent[i].starts_with("#EXT-X-STREAM-INF:")) { f_haveRedirection = true; /*AUDIO_LOG_ERROR("we have a redirection");*/ } + if (addNextLine) { + if (m_playlistContent[i].starts_with("#EXT-X-PROGRAM-DATE-TIME:")) continue; // skip this line + addNextLine = false; + // size_t len = strlen(linesWithSeqNr[idx].get()) + strlen(m_playlistContent[i].get()) + 1; + m_linesWithURL.emplace_back(m_playlistContent[i]); + } + if (m_playlistContent[i].starts_with("#EXTINF:")) { + m_linesWithEXTINF.emplace_back(m_playlistContent[i]); + addNextLine = true; + } + } + if (!f_haveRedirection) { + accomplish_m3u8_url(); + prepare_first_m3u8_url(m_playlistBuff); + vector_clear_and_shrink(m_playlistContent); + } + } + + for (int i = 0; i < m_linesWithURL.size(); i++) { /*AUDIO_LOG_INFO("{}", m_linesWithURL[i].get())*/ + ; + } + for (int i = 0; i < m_linesWithEXTINF.size(); i++) { /*AUDIO_LOG_INFO("{}", m_linesWithEXTINF[i].get());*/ + showstreamtitle(m_linesWithEXTINF[i].get()); + } + + if (f_haveRedirection) { + m_m3u8_host = m3u8redirection(&m_m3u8Codec); + vector_clear_and_shrink(m_playlistContent); + return {}; + } + + if (m_codec == CODEC_NONE) { + m_codec = CODEC_AAC; + if (m_m3u8Codec == CODEC_MP3) m_codec = CODEC_MP3; + } // if we have no redirection + //---------------------------------------------------------------------------------------------------------------------------------------------------- + + if (m_linesWithURL.size() > 0) { + ps_ptr playlistBuff; + if (m_linesWithURL[0].valid()) { + playlistBuff = m_linesWithURL[0]; + m_linesWithURL.pop_front(); + m_linesWithURL.shrink_to_fit(); + } + AUDIO_LOG_DEBUG("now playing {}", playlistBuff.get()); + if (playlistBuff.ends_with("ts")) m_f_ts = true; + if (playlistBuff.contains(".ts?") > 0) m_f_ts = true; + m_playlistBuff = playlistBuff; + return playlistBuff; + } + return {}; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +ps_ptr Audio::m3u8redirection(uint8_t* codec) { + // example: redirection + // #EXTM3U + // #EXT-X-STREAM-INF:BANDWIDTH=117500,AVERAGE-BANDWIDTH=117000,CODECS="mp4a.40.2" + // 112/playlist.m3u8?hlssid=7562d0e101b84aeea0fa35f8b963a174 + // #EXT-X-STREAM-INF:BANDWIDTH=69500,AVERAGE-BANDWIDTH=69000,CODECS="mp4a.40.5" + // 64/playlist.m3u8?hlssid=7562d0e101b84aeea0fa35f8b963a174 + // #EXT-X-STREAM-INF:BANDWIDTH=37500,AVERAGE-BANDWIDTH=37000,CODECS="mp4a.40.29" + // 32/playlist.m3u8?hlssid=7562d0e101b84aeea0fa35f8b963a174 + + if (!m_lastHost.valid()) { + AUDIO_LOG_ERROR("m_lastHost is empty"); + return {}; + } // guard + const char codecString[9][11] = { + "mp4a.40.34", // mp3 stream + "mp4a.40.01", // AAC Main + "mp4a.40.2", // MPEG-4 AAC LC + "mp4a.40.02", // MPEG-4 AAC LC, leading 0 for Aud-OTI compatibility + "mp4a.40.29", // MPEG-4 HE-AAC v2 (AAC LC + SBR + PS) + "mp4a.40.42", // xHE-AAC + "mp4a.40.5", // MPEG-4 HE-AAC v1 (AAC LC + SBR) + "mp4a.40.05", // MPEG-4 HE-AAC v1 (AAC LC + SBR), leading 0 for Aud-OTI compatibility + "mp4a.67", // MPEG-2 AAC LC + }; + + uint16_t choosenLine = 0; + uint16_t plcSize = m_playlistContent.size(); + int8_t cS = 100; + + for (uint16_t i = 0; i < plcSize; i++) { // looking for lowest codeString + if (m_playlistContent[i].contains("CODECS=\"mp4a")) { + for (uint8_t j = 0; j < 9; j++) { + if (m_playlistContent[i].contains(codecString[j])) { + if (j < cS) { + cS = j; + choosenLine = i; + } + } + } + } + } + if (cS == 0) + *codec = CODEC_MP3; + else if (cS < 100) + *codec = CODEC_AAC; + + if (cS == 100) { // "mp4a.xx.xx" not found + *codec = CODEC_AAC; // assume AAC + for (uint16_t i = 0; i < plcSize; i++) { // we have no codeString, looking for "http" + if (m_playlistContent[i].contains("#EXT-X-STREAM-INF")) { choosenLine = i; } + } + } + + choosenLine++; // next line is the redirection url + + ps_ptr result; + ps_ptr line; + line.clone_from(m_playlistContent[choosenLine]); + + if (line.starts_with("../")) { + // ../../2093120-b/RISMI/stream01/streamPlaylist.m3u8 + while (line.starts_with("../")) { line.remove_prefix("../"); } + result.clone_from(m_currentHost); + int idx = result.last_index_of('/'); + if (idx > 0 && (size_t)idx != result.strlen() - 1) result.truncate_at((size_t)idx + 1); + result.append(line.get()); + } else if (!line.starts_with_icase("http")) { + + // http://arcast.com.ar:1935/radio/radionar.stream/playlist.m3u8 m_lastHost + // chunklist_w789468022.m3u8 line + // http://arcast.com.ar:1935/radio/radionar.stream/chunklist_w789468022.m3u8 --> result + + result.clone_from(m_currentHost); + int pos = m_currentHost.last_index_of('/'); + if (pos > 0) { + result.truncate_at((size_t)pos + 1); + result.append(line.get()); + } + } else { + result.clone_from(line); + } + + return result; // it's a redirection, a new m3u8 playlist +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::processLocalFile() { + if (!(m_audiofile && m_f_running && m_dataMode == AUDIO_LOCALFILE)) return; // guard + + m_prlf.availableBytes = 0; + m_prlf.bytesAddedToBuffer = 0; + + if (m_f_firstCall) { // runs only one time per connection, prepare for start + m_f_firstCall = false; + m_f_stream = false; + m_prlf.audioHeaderFound = false; + m_prlf.newFilePos = 0; + m_prlf.ctime = millis(); + m_audioFilePosition = 0; + m_audioDataSize = m_audioFileSize; + m_audioDataStart = 0; + m_f_allDataReceived = false; + m_prlf.timeout = 8000; // ms + } + + if (m_resumeFilePos >= 0) { // we have a resume file position + m_prlf.newFilePos = newInBuffStart(m_resumeFilePos); + if (m_prlf.newFilePos < 0) AUDIO_LOG_WARN("skip to new position was not successful"); + m_haveNewFilePos = m_prlf.newFilePos; + m_audioDataReadPtr = m_prlf.newFilePos; + m_resumeFilePos = -1; + m_f_allDataReceived = false; + return; + } + + m_prlf.availableBytes = min(InBuff.writeSpace(), (size_t)(m_audioFileSize - m_audioFilePosition)); + m_prlf.bytesAddedToBuffer = audioFileRead(InBuff.getWritePtr(), min(m_prlf.availableBytes, (uint32_t)UINT16_MAX)); + if (m_prlf.bytesAddedToBuffer > 0) { InBuff.bytesWritten(m_prlf.bytesAddedToBuffer); } + if (m_audioDataSize && m_audioFilePosition >= m_audioDataSize) { + if (!m_f_allDataReceived) m_f_allDataReceived = true; + } + if (!m_audioDataSize && m_audioFilePosition == m_audioFileSize) { + if (!m_f_allDataReceived) m_f_allDataReceived = true; + } + // AUDIO_LOG_DEBUG("m_audioFilePosition {} >= m_audioDataSize {}, m_f_allDataReceived {}", m_audioFilePosition, m_audioDataSize, m_f_allDataReceived); + + if (!m_decoder && InBuff.bufferFilled() > 127) { + if (!initializeDecoder()) return; + m_prlf.maxFrameSize = InBuff.getMaxBlockSize(); + } + + if (!m_f_stream) { + if (m_controlCounter != 100) { + if (m_f_ogg) { m_controlCounter = 100; } + if ((millis() - m_prlf.ctime) > m_prlf.timeout) { + AUDIO_LOG_ERROR("audioHeader reading timeout"); + m_f_running = false; + goto exit; + } + if (InBuff.bufferFilled() > m_prlf.maxFrameSize || (InBuff.bufferFilled() == m_audioFileSize) || m_f_allDataReceived) { // at least one complete frame or the file is smaller + InBuff.bytesWasRead(readAudioHeader(InBuff.readSpace())); + } + if (m_controlCounter == 100) { + if (m_audioDataStart > 0) { m_prlf.audioHeaderFound = true; } + if (!m_audioDataSize) m_audioDataSize = m_audioFileSize; + } + return; + } else { + m_f_stream = true; + info(*this, evt_info, "stream ready"); + } + } + + if (m_fileStartTime > 0 && m_nominal_bitrate) { + if (getBitRate() > 0) + setAudioPlayTime(m_fileStartTime); + else + info(*this, evt_info, "can't set audio play time directly"); + m_fileStartTime = -1; + } + + // end of file reached? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_eof) { // m_f_eof and m_f_ID3v1TagFound will be set in playAudioData() + if (m_f_ID3v1TagFound) readID3V1Tag(); + exit: + ps_ptr afn; // audio file name + if (m_audiofile) afn.assign(m_audiofile.name()); // store temporary the name + m_audioCurrentTime = 0; + m_audioFileDuration = 0; + m_resumeFilePos = -1; + m_haveNewFilePos = 0; + m_codec = CODEC_NONE; + stopSong(); + + if (afn.valid()) { info(*this, evt_eof, "{}", afn.c_get()); } + return; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +void Audio::processWebStream() { + if (m_dataMode != AUDIO_DATA) return; // guard + uint16_t readedBytes = 0; + + m_pwst.availableBytes = 0; // available from stream + m_pwst.f_clientIsConnected = m_client->connected(); + m_pwst.writeSpace = UINT16_MAX; + + // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_firstCall) { // runs only ont time per connection, prepare for start + m_f_firstCall = false; + m_f_stream = false; + m_pwst.chunkSize = 0; + m_metacount = m_metaint; + m_f_allDataReceived = false; + readMetadata(0, &readedBytes, true); + getChunkSize(0, true); + m_audioFilePosition = 0; + } + + m_pwst.availableBytes = m_client->available(); // available from stream + // chunked data tramsfer + if (m_f_chunked && m_pwst.availableBytes) { + if (m_pwst.chunkSize == 0) { + int chunkLen = getChunkSize(&m_pwst.readedBytes); + if (chunkLen == -1) { // need more data + vTaskDelay(10); + return; + } + if (chunkLen == -100) { // error + stopSong(); + return; + } + if (chunkLen == 0) { m_f_allDataReceived = true; } + m_pwst.chunkSize = chunkLen; + m_pwst.readedBytes = 0; // readedBytes is not a part of chunkSize + } + m_pwst.writeSpace = min(m_pwst.writeSpace, m_pwst.chunkSize); + } + + // we have metadata - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if ((m_metaint) && (m_metacount == 0)) { + if (!m_pwst.availableBytes) return; + readedBytes = 0; + bool res = false; + if (m_f_chunked) { + res = readMetadata(min(m_pwst.availableBytes, m_pwst.chunkSize), &readedBytes); + } else { + res = readMetadata(m_pwst.availableBytes, &readedBytes); + } + m_pwst.readedBytes += readedBytes; + if (m_f_chunked) m_pwst.chunkSize -= readedBytes; // reduce chunkSize by metadata length + if (res == false) return; + m_metacount = m_metaint; + return; + } + if (m_metaint) m_pwst.writeSpace = min(m_pwst.writeSpace, m_metacount); + + // buffer fill routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_pwst.availableBytes) { + m_pwst.writeSpace = min(m_pwst.writeSpace, (uint32_t)InBuff.writeSpace()); + int32_t bytesAddedToBuffer = audioFileRead(InBuff.getWritePtr(), min(m_pwst.writeSpace, (uint32_t)UINT16_MAX)); + + if (bytesAddedToBuffer > 0) { + m_pwst.writeSpace -= bytesAddedToBuffer; + if (m_metaint) m_metacount -= bytesAddedToBuffer; + if (m_f_chunked) m_pwst.chunkSize -= bytesAddedToBuffer; + InBuff.bytesWritten(bytesAddedToBuffer); + } + } + + // if the buffer is often almost empty issue a warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_stream) { + if (!m_f_allDataReceived) streamDetection(m_pwst.availableBytes); + if (!m_pwst.f_clientIsConnected) { + if (m_f_tts && !m_f_allDataReceived) m_f_allDataReceived = true; + } // connection closed (OpenAi) + } + + if (!m_decoder && InBuff.bufferFilled() > 127) { + if (initializeDecoder()) + m_pwst.maxFrameSize = InBuff.getMaxBlockSize(); + else + return; + } + + // start audio decoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (((InBuff.bufferFilled() > m_pwst.maxFrameSize * 2) || (m_f_allDataReceived)) && !m_f_stream) { // waiting for buffer filled + info(*this, evt_info, "stream ready"); + m_f_stream = true; // ready to play the audio data + } + + if (m_f_eof) { + info(*this, evt_eof, "{}", m_lastHost.c_get()); + stopSong(); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::processWebFile() { + + if (!m_lastHost.valid()) { + AUDIO_LOG_ERROR("m_lastHost is empty"); + return; + } // guard + uint32_t availableBytes = 0; + int32_t bytesAddedToBuffer = 0; + // m_pwf.f_clientIsConnected = m_client->connected(); // we are not connected + + if (m_f_firstCall) { // runs only ont time per connection, prepare for start + m_f_firstCall = false; + m_f_stream = false; + m_controlCounter = 0; + m_pwf.audioHeaderFound = false; + m_pwf.newFilePos = 0; + m_pwf.ctime = millis(); + m_audioFilePosition = 0; + m_audioDataSize = m_audioFileSize; + m_audioDataStart = 0; + m_f_allDataReceived = false; + m_pwf.timeout = 8000; // ms + if (!initializeDecoder()) return; + m_pwf.maxFrameSize = InBuff.getMaxBlockSize(); // every frame is not bigger + } + + if (m_resumeFilePos >= 0) { // we have a resume file position + m_pwf.newFilePos = newInBuffStart(m_resumeFilePos); + if (m_pwf.newFilePos < 0) AUDIO_LOG_WARN("skip to new position was not successful"); + m_haveNewFilePos = m_pwf.newFilePos; + m_audioDataReadPtr = m_pwf.newFilePos; + m_resumeFilePos = -1; + m_f_allDataReceived = false; + return; + } + + m_pwf.availableBytes = min(m_client->available(), (int)InBuff.writeSpace()); + m_pwf.bytesAddedToBuffer = audioFileRead(InBuff.getWritePtr(), min(m_pwf.availableBytes, (uint32_t)UINT16_MAX)); + if (m_pwf.bytesAddedToBuffer > 0) { InBuff.bytesWritten(m_pwf.bytesAddedToBuffer); } + if (m_audioDataSize && m_audioFilePosition >= m_audioDataSize) { + if (!m_f_allDataReceived) m_f_allDataReceived = true; + } + if (!m_audioDataSize && m_audioFilePosition == m_audioFileSize) { + if (!m_f_allDataReceived) m_f_allDataReceived = true; + } + // AUDIO_LOG_ERROR("m_audioFilePosition {} >= m_audioDataSize {}, m_f_allDataReceived {}", m_audioFilePosition, m_audioDataSize, m_f_allDataReceived); + if (!m_decoder && InBuff.bufferFilled() > 127) { + if (!initializeDecoder()) return; + } + + if (!m_f_stream) { + if (m_controlCounter != 100) { + if (m_f_ogg) { m_controlCounter = 100; } + if ((millis() - m_pwf.ctime) > m_pwf.timeout) { + AUDIO_LOG_ERROR("audioHeader reading timeout"); + m_f_running = false; + goto exit; + } + if (InBuff.bufferFilled() > m_pwf.maxFrameSize || (InBuff.bufferFilled() == m_audioFileSize) || m_f_allDataReceived) { // at least one complete frame or the file is smaller + InBuff.bytesWasRead(readAudioHeader(InBuff.readSpace())); + } + if (m_controlCounter == 100) { + if (m_audioDataStart > 0) { m_pwf.audioHeaderFound = true; } + if (!m_audioDataSize) m_audioDataSize = m_audioFileSize; + } + return; + } else { + if (m_resumeFilePos == -1) { + if (InBuff.bufferFilled() > 2 * InBuff.getMaxBlockSize()) { + m_f_stream = true; + info(*this, evt_info, "stream ready"); + } + } + } + } + + if (m_fileStartTime > 0 && m_nominal_bitrate) { + if (getBitRate() > 0) + setAudioPlayTime(m_fileStartTime); + else + info(*this, evt_info, "can't set audio play time directly"); + m_fileStartTime = -1; + } + + // end of file reached? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_eof) { // m_f_eof and m_f_ID3v1TagFound will be set in playAudioData() + if (m_f_ID3v1TagFound) readID3V1Tag(); + exit: + stopSong(); + info(*this, evt_eof, "{}", m_lastHost.c_get()); + + m_audioCurrentTime = 0; + m_audioFileDuration = 0; + m_resumeFilePos = -1; + m_haveNewFilePos = 0; + m_codec = CODEC_NONE; + return; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::processWebStreamTS() { + + // first call, set some values to default ——————————————————————————————————— + if (m_f_firstCall) { // runs only one time per connection, prepare for start + m_f_firstCall = false; + m_f_m3u8data = true; + m_audioFilePosition = 0; + m_pwsst.f_firstPacket = true; + m_pwsst.f_chunkFinished = false; + m_pwsst.f_nextRound = false; + m_pwsst.byteCounter = 0; + m_t0 = millis(); + if (!m_pwsst.ts_packet.valid()) m_pwsst.ts_packet.alloc_array(m_pwsst.ts_packetsize, "m_pwsst.ts_packet"); // first init + if (!m_decoder) { // first init + getChunkSize(0, true); + m_pwsst.chunkSize = 0; + ts_parsePacket(0, 0, 0); + m_pwsst.ts_packetPtr = 0; + if (!initializeDecoder()) return; + } + } // ————————————————————————————————————————————————————————————————————————— + + m_pwsst.ts_packetStart = 0; + m_pwsst.ts_packetLength = 0; + uint32_t availableBytes = m_client->available(); // available bytes in stream + + if (availableBytes) { + /* If the m3u8 stream uses 'chunked data transfer' no content length is supplied. Then the chunk size determines the audio data to be processed. + However, the chunk size in some streams is limited to 32768 bytes, although the chunk can be larger. Then the chunk size is + calculated again. The data used to calculate (here readedBytes) the chunk size is not part of it. + */ + uint16_t readedBytes = 0; + uint32_t minAvBytes = 0; + if (m_pwsst.f_chunkFinished) goto chunkFinished; + if (m_f_chunked && m_pwsst.chunkSize == m_pwsst.byteCounter) { + int chunkLen = getChunkSize(&readedBytes); + if (chunkLen == -1) { // need more data + vTaskDelay(10); + return; + } + if (chunkLen == -100) { // error + stopSong(); + return; + } + m_pwsst.chunkSize += chunkLen; + AUDIO_LOG_DEBUG("chunkLen {}, rb {}", chunkLen, readedBytes); + if (chunkLen == 0) { + m_pwsst.f_chunkFinished = true; + m_pwsst.chunkSize = 0; + m_pwsst.byteCounter = 0; + goto chunkFinished; + } + } + if (m_pwsst.chunkSize) + minAvBytes = min3(availableBytes, m_pwsst.ts_packetsize - m_pwsst.ts_packetPtr, m_pwsst.chunkSize - m_pwsst.byteCounter); + else + minAvBytes = min(availableBytes, (uint32_t)(m_pwsst.ts_packetsize - m_pwsst.ts_packetPtr)); + + int res = audioFileRead(m_pwsst.ts_packet.get() + m_pwsst.ts_packetPtr, minAvBytes); + if (res > 0) { + m_pwsst.ts_packetPtr += res; + m_pwsst.byteCounter += res; + if (m_pwsst.ts_packetPtr < m_pwsst.ts_packetsize) return; // not enough data yet, the process must be repeated if the packet size (188 bytes) is not reached + m_pwsst.ts_packetPtr = 0; + if (m_pwsst.f_firstPacket) { // search for ID3 Header in the first packet + m_pwsst.f_firstPacket = false; + uint8_t ID3_HeaderSize = process_m3u8_ID3_Header(m_pwsst.ts_packet.get()); + if (ID3_HeaderSize > m_pwsst.ts_packetsize) { + AUDIO_LOG_ERROR("ID3 Header is too big"); + stopSong(); + return; + } + if (ID3_HeaderSize) { + memcpy(m_pwsst.ts_packet.get(), &m_pwsst.ts_packet.get()[ID3_HeaderSize], m_pwsst.ts_packetsize - ID3_HeaderSize); + m_pwsst.ts_packetPtr = m_pwsst.ts_packetsize - ID3_HeaderSize; + return; + } + } + if (!ts_parsePacket(&m_pwsst.ts_packet.get()[0], &m_pwsst.ts_packetStart, &m_pwsst.ts_packetLength)) { + stopSong(); + AUDIO_LOG_ERROR("song stopped"); + return; + }; + + if (m_pwsst.ts_packetLength) { + size_t ws = InBuff.writeSpace(); + if (ws >= m_pwsst.ts_packetLength) { + memcpy(InBuff.getWritePtr(), m_pwsst.ts_packet.get() + m_pwsst.ts_packetStart, m_pwsst.ts_packetLength); + InBuff.bytesWritten(m_pwsst.ts_packetLength); + m_pwsst.f_nextRound = true; + } else { + int t = 0; + memcpy(InBuff.getWritePtr(), m_pwsst.ts_packet.get() + m_pwsst.ts_packetStart, ws); // write everything that fits into the buffer + InBuff.bytesWritten(ws); + while (true) { + if (InBuff.writeSpace() >= m_pwsst.ts_packetLength - ws) { + memcpy(InBuff.getWritePtr(), &m_pwsst.ts_packet.get()[ws + m_pwsst.ts_packetStart], m_pwsst.ts_packetLength - ws); // write the rest + InBuff.bytesWritten(m_pwsst.ts_packetLength - ws); + break; + } + t++; + vTaskDelay(10); // wait until the buffer is free + if (t == 10) { + AUDIO_LOG_ERROR("InBuff is full"); + break; + } + } + } + } + if (m_audioFileSize && m_pwsst.byteCounter > m_audioFileSize) { + AUDIO_LOG_ERROR("byteCounter overflow, byteCounter: {}, contentlength: {}", m_pwsst.byteCounter, m_audioFileSize); + return; + } + if (m_pwsst.chunkSize && m_pwsst.byteCounter > m_pwsst.chunkSize) { + AUDIO_LOG_ERROR("byteCounter overflow, byteCounter: {}, chunkSize: {}", m_pwsst.byteCounter, m_pwsst.chunkSize); + return; + } + } + } + if (m_audioFileSize && m_pwsst.byteCounter == m_audioFileSize) { + if (InBuff.bufferFilled() < settings.BUFFER_TRESHOLD_HLS) { + m_f_continue = true; + m_pwsst.byteCounter = 0; + m_pwsst.ts_packetPtr = 0; + } + m_pwsst.f_nextRound = false; + goto exit; + } + +chunkFinished: + if (m_pwsst.f_chunkFinished) { + if (InBuff.bufferFilled() < settings.BUFFER_TRESHOLD_HLS) { + m_pwsst.f_chunkFinished = false; + m_f_continue = true; + m_pwsst.byteCounter = 0; + m_pwsst.chunkSize = 0; + m_pwsst.ts_packetPtr = 0; + } + goto exit; + } + + // if the buffer is often almost empty issue a warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_stream) { streamDetection(availableBytes); } + + // buffer fill routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + if (InBuff.bufferFilled() > settings.BUFFER_TRESHOLD_HLS && !m_f_stream) { // waiting for buffer filled + m_f_stream = true; // ready to play the audio data + uint16_t filltime = millis() - m_t0; + info(*this, evt_info, "stream ready"); + info(*this, evt_info, "buffer filled in {} ms", filltime); + } + } + +exit: + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::processWebStreamHLS() { + + // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (m_f_firstCall) { // runs only ont time per connection, prepare for start + m_f_firstCall = false; + m_f_m3u8data = true; + m_t0 = millis(); + m_controlCounter = 0; + m_audioFilePosition = 0; + m_pwsHLS.ID3BuffSize = 4096; + m_pwsHLS.availableBytes = 0; + m_pwsHLS.firstBytes = true; + m_pwsHLS.f_chunkFinished = false; + m_pwsHLS.byteCounter = 0; + m_pwsHLS.chunkSize = 0; + m_pwsHLS.ID3WritePtr = 0; + m_pwsHLS.ID3ReadPtr = 0; + m_pwsHLS.ID3Buff.alloc(m_pwsHLS.ID3BuffSize, "m_pwsHLS.ID3Buff"); + getChunkSize(0, true); + if (!m_decoder && !initializeDecoder()) return; + m_pwsHLS.maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger + } + + if (m_dataMode != AUDIO_DATA) return; // guard + + m_pwsHLS.availableBytes = m_client->available(); + if (m_pwsHLS.availableBytes) { // an ID3 header could come here + uint16_t readedBytes = 0; + + if (m_f_chunked && !m_pwsHLS.chunkSize) { + m_pwsHLS.chunkSize = getChunkSize(&readedBytes); + if (m_pwsHLS.chunkSize == -1) { // need more data + vTaskDelay(10); + return; + } + if (m_pwsHLS.chunkSize == -100) { // error + stopSong(); + return; + } + m_pwsHLS.byteCounter += readedBytes; + } + + if (m_pwsHLS.firstBytes) { + if (m_pwsHLS.ID3WritePtr < m_pwsHLS.ID3BuffSize) { + m_pwsHLS.ID3WritePtr += audioFileRead(&m_pwsHLS.ID3Buff[m_pwsHLS.ID3WritePtr], m_pwsHLS.ID3BuffSize - m_pwsHLS.ID3WritePtr); + return; + } + if (m_controlCounter < 100) { + int res = read_ID3_Header(&m_pwsHLS.ID3Buff[m_pwsHLS.ID3ReadPtr], m_pwsHLS.ID3BuffSize - m_pwsHLS.ID3ReadPtr); + if (res >= 0) m_pwsHLS.ID3ReadPtr += res; + if (m_pwsHLS.ID3ReadPtr > m_pwsHLS.ID3BuffSize) { + AUDIO_LOG_ERROR("buffer overflow"); + stopSong(); + return; + } + return; + } + if (m_controlCounter != 100) return; + + size_t ws = InBuff.writeSpace(); + if (ws >= m_pwsHLS.ID3BuffSize - m_pwsHLS.ID3ReadPtr) { + memcpy(InBuff.getWritePtr(), &m_pwsHLS.ID3Buff[m_pwsHLS.ID3ReadPtr], m_pwsHLS.ID3BuffSize - m_pwsHLS.ID3ReadPtr); + InBuff.bytesWritten(m_pwsHLS.ID3BuffSize - m_pwsHLS.ID3ReadPtr); + } else { + int t = 0; + memcpy(InBuff.getWritePtr(), &m_pwsHLS.ID3Buff[m_pwsHLS.ID3ReadPtr], ws); + InBuff.bytesWritten(ws); + while (true) { + if (InBuff.writeSpace() >= m_pwsHLS.ID3BuffSize - (m_pwsHLS.ID3ReadPtr + ws)) { + memcpy(InBuff.getWritePtr(), &m_pwsHLS.ID3Buff[ws + m_pwsHLS.ID3ReadPtr], m_pwsHLS.ID3BuffSize - (m_pwsHLS.ID3ReadPtr + ws)); // write everything that fits into the buffer + InBuff.bytesWritten(m_pwsHLS.ID3BuffSize - (m_pwsHLS.ID3ReadPtr + ws)); + break; + } + t++; + vTaskDelay(10); // wait until the buffer is free + if (t == 10) { + AUDIO_LOG_ERROR("InBuff is full"); + break; + } + } + } + m_pwsHLS.ID3Buff.reset(); + m_pwsHLS.byteCounter += m_pwsHLS.ID3BuffSize; + m_pwsHLS.firstBytes = false; + } + + size_t bytesWasWritten = 0; + if (InBuff.writeSpace() >= m_pwsHLS.availableBytes) { + // if(availableBytes > 1024) availableBytes = 1024; // 1K throttle + bytesWasWritten = audioFileRead(InBuff.getWritePtr(), m_pwsHLS.availableBytes); + } else { + bytesWasWritten = audioFileRead(InBuff.getWritePtr(), InBuff.writeSpace()); + } + InBuff.bytesWritten(bytesWasWritten); + + m_pwsHLS.byteCounter += bytesWasWritten; + + if (m_pwsHLS.byteCounter == m_audioFileSize || m_pwsHLS.byteCounter == m_pwsHLS.chunkSize) { + m_pwsHLS.f_chunkFinished = true; + m_pwsHLS.byteCounter = 0; + } + } + + if (m_pwsHLS.f_chunkFinished) { + if (InBuff.bufferFilled() < settings.BUFFER_TRESHOLD_HLS) { + m_pwsHLS.f_chunkFinished = false; + m_f_continue = true; + } + } + + // if the buffer is often almost empty issue a warning or try a new connection - - - - - - - - - - - - - - - - - - - + if (m_f_stream) { streamDetection(m_pwsHLS.availableBytes); } + + if (InBuff.bufferFilled() > settings.BUFFER_TRESHOLD_HLS && !m_f_stream) { // waiting for buffer filled + m_f_stream = true; // ready to play the audio data + // uint16_t filltime = millis() - m_t0; + info(*this, evt_info, "stream ready"); + // info(*this, evt_info, "buffer filled in {} ms", filltime); + } + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::playAudioData() { + + if (m_f_eof || m_f_lockInBuffer || !m_f_stream) { + vTaskDelay(1); + return; + } // guard, stream not ready or eof reached or InBuff is locked or not running + if (m_validSamples) { + playChunk(); + return; + } // guard, play samples first + //-------------------------------------------------------------------------------- + m_pad.count = 0; + m_pad.bytesToDecode = InBuff.readSpace(); + m_pad.bytesDecoded = 0; + + if (m_f_firstPlayCall) { + m_audioDataReadPtr = 0; + m_f_firstPlayCall = false; + m_pad.count = 0; + m_pad.oldAudioDataSize = 0; + m_bytesNotConsumed = 0; + m_pad.lastFrames = false; + m_f_eof = false; + } + //-------------------------------------------------------------------------------- + + bool isFile = false; + bool isStream = false; + + if (m_dataMode == AUDIO_LOCALFILE) isFile = true; + if (m_streamType == ST_WEBFILE && m_playlistFormat != FORMAT_M3U8) isFile = true; // local file or webfile but not m3u8 file + if (m_streamType == ST_WEBSTREAM || m_playlistFormat == FORMAT_M3U8) isStream = true; + if (!isFile && !isStream) return; + + xSemaphoreTake(mutex_audioTaskIsDecoding, 1 * configTICK_RATE_HZ); + { + m_pad.bytesDecoded = 0; + if (isFile) { + if (!m_audioDataSize) goto exit; // no data to decode if filesize is 0 + if (m_audioDataStart + m_audioDataSize - m_audioDataReadPtr == 128) { + m_f_ID3v1TagFound = true; + m_f_eof = true; + goto exit; + } + if (m_audioDataSize <= m_audioDataReadPtr) { + m_f_eof = true; + goto exit; + } + + if (m_audioDataStart + m_audioDataSize >= m_audioFilePosition) m_f_allDataReceived = true; + if (m_audioDataSize - m_audioDataReadPtr <= InBuff.getMaxBlockSize()) m_pad.lastFrames = true; + + if (m_pad.lastFrames) { + m_pad.bytesToDecode = min(InBuff.readSpace(), (size_t)(m_audioDataStart + m_audioDataSize - m_audioDataReadPtr)); + m_pad.bytesDecoded = sendBytes(InBuff.getReadPtr(), m_pad.bytesToDecode); + } else { + m_pad.bytesToDecode = InBuff.readSpace(); + if (m_pad.bytesToDecode >= InBuff.getMaxBlockSize()) { m_pad.bytesDecoded = sendBytes(InBuff.getReadPtr(), m_pad.bytesToDecode); } + } + } + + if (isStream) { + if (m_f_allDataReceived) { // Google TTS, OpenAI + m_pad.lastFrames = true; + if (m_f_tts && !InBuff.bufferFilled()) { + m_f_eof = true; + goto exit; + } + } + if (m_pad.lastFrames) { + if (m_f_chunked) { + m_pad.bytesToDecode = InBuff.readSpace(); + } else { + m_pad.bytesToDecode = min(InBuff.readSpace(), (size_t)(m_audioDataStart + m_audioDataSize - m_audioDataReadPtr)); + } + m_pad.bytesDecoded = sendBytes(InBuff.getReadPtr(), m_pad.bytesToDecode); + } else { + m_pad.bytesToDecode = InBuff.readSpace(); + if (m_pad.bytesToDecode >= InBuff.getMaxBlockSize()) { m_pad.bytesDecoded = sendBytes(InBuff.getReadPtr(), m_pad.bytesToDecode); } + } + } + + if (m_pad.bytesDecoded > 0) { + InBuff.bytesWasRead(m_pad.bytesDecoded); + m_audioDataReadPtr += m_pad.bytesDecoded; + } + } +exit: + xSemaphoreGive(mutex_audioTaskIsDecoding); + + AUDIO_LOG_DEBUG("m_audioDataReadPtr {}, m_audioDataSize {}", m_audioDataReadPtr, m_audioDataSize); + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::parseHttpResponseHeader() { // this is the response to a GET / request + + if (m_dataMode != HTTP_RESPONSE_HEADER) return false; + m_icy_items.reset(); + m_metaint = 0; // no metaint yet + + m_phreh.reset(); + m_phreh.ctime = millis(); + m_phreh.timeout = 5000; // ms + m_httpRespHdrBuff.clear(); + uint16_t pos = 0; + + while (true) { // read the header first and store it in m_httpRespHdrBuff + if (m_client->available()) { m_httpRespHdrBuff[pos++] = audioFileRead(); } + if (m_httpRespHdrBuff.ends_with("\r\n\r\n")) break; + if (m_httpRespHdrBuff.ends_with("\n\n")) break; + if (pos == m_httpRespHdrBuff.size()) { + AUDIO_LOG_WARN("responseHeaderline overflow"); + m_httpRespHdrBuff[pos - 1] = '\0'; + break; + } + if ((millis() - m_phreh.ctime) > m_phreh.timeout) { + AUDIO_LOG_ERROR("timeout"); + m_phreh.f_time = false; + // stopSong(); + return false; + } + } + + ps_ptr rhl; + bool ct_seen = false; + + // m_httpRespHdrBuff.println(); + + pos = 0; + while (true) { // read the header line for line + int idx = m_httpRespHdrBuff.index_of('\n', pos); + if (idx > pos) { + rhl = m_httpRespHdrBuff.substr(pos, idx - pos); + rhl.set_name("rhl"); + rhl.remove_chars("\r"); + pos = idx + 1; + if (rhl.strlen() == 0) continue; + } else { // done? + if (ct_seen) + goto lastToDo; + else { goto exit; } + } + + // rhl.println(); + + if (rhl.starts_with_icase("icy-")) { // —— ICY BLOCK —————————————————————————————————————————————————————————— + m_phreh.f_icy_data = true; + + if (rhl.starts_with_icase("icy-genre:")) { + m_icy_items.icy_genre.copy_from(rhl.get() + 10); // Ambient, Rock, etc + m_icy_items.icy_genre.trim(); + latinToUTF8(m_icy_items.icy_genre); + } + + if (rhl.starts_with_icase("icy-logo:")) { + m_icy_items.icy_logo.copy_from(rhl.get() + 9); // https://www.0nradio.com/logos/0n-70s_600x600.jpg + m_icy_items.icy_logo.trim(); + latinToUTF8(m_icy_items.icy_logo); + } + + if (rhl.starts_with_icase("icy-name:")) { + m_icy_items.icy_name.copy_from(rhl.get() + 9); + m_icy_items.icy_name.trim(); + latinToUTF8(m_icy_items.icy_name); + } + + if (rhl.starts_with_icase("icy-url:")) { + m_icy_items.icy_url.copy_from(rhl.get() + 8); + m_icy_items.icy_url.trim(); + } + + if (rhl.starts_with_icase("icy-description:")) { + m_icy_items.icy_description.copy_from(rhl.get() + 16); + m_icy_items.icy_description.trim(); + latinToUTF8(m_icy_items.icy_description); + } + + if (rhl.starts_with_icase("icy-metaint:")) { + m_icy_items.icy_metaint.copy_from(rhl.get() + 12); + m_icy_items.icy_metaint.trim(); + } + + if (rhl.starts_with_icase("icy-br:")) { + m_icy_items.icy_br.copy_from(rhl.get() + 7); + m_icy_items.icy_br.trim(); + } + } // —— END ICY BLOCK ————————————————————————————————————————————————————————————————————————————————————————— + + if (rhl.starts_with_icase("HTTP/")) { // HTTP status error code + char statusCode[5]; + statusCode[0] = rhl[9]; + statusCode[1] = rhl[10]; + statusCode[2] = rhl[11]; + statusCode[3] = '\0'; + int sc = atoi(statusCode); + if (sc == 403 && !m_f_alt_user_agent) { // HTTP/1.1 403 Forbidden + m_f_alt_user_agent = true; + AUDIO_LOG_WARN("403 Forbidden, test alternative user agent"); + connecttohost(m_lastHost.c_get()); + return true; + } + m_f_alt_user_agent = false; + if (sc > 310) { // e.g. HTTP/1.1 301 Moved Permanently + info(*this, evt_streamtitle, "{}", rhl.get()); + goto exit; + } + } else if (rhl.starts_with_icase("content-type:")) { // content-type: text/html; charset=UTF-8 + int idx = rhl.index_of(';', 13); + if (idx > 0) rhl[idx] = '\0'; + if (parseContentType(rhl.get() + 13)) + ct_seen = true; + else { + AUDIO_LOG_WARN("unknown contentType {}", rhl.get() + 13); + goto exit; + } + } + + else if (rhl.starts_with_icase("location:")) { + int pos = rhl.index_of_icase("http", 0); + if (pos == -1) { + int doubleSlash = rhl.index_of("//"); // e.g. location: //frontend.streamonkey.net/... host: http://webstream.radiof.de/ + if (doubleSlash >= 9) rhl.insert("http:", doubleSlash); // ==> http://frontend.streamonkey.net/fhn-radiof945/stream/mp3?aggregator=fh-tinyurl + pos = rhl.index_of_icase("http", 0); + } + if (pos >= 0) { + const char* c_host = (rhl.get() + pos); + if (!m_currentHost.equals(c_host)) { // prevent a loop + int pos_slash = indexOf(c_host, "/", 9); + if (pos_slash > 9) { + if (!strncmp(c_host, m_currentHost.get(), pos_slash)) { + info(*this, evt_info, "redirect to new extension at existing host \"{}\"", c_host); + if (m_playlistFormat == FORMAT_M3U8) { + // m_lastHost.assign(c_host); + m_f_m3u8data = true; + } + httpPrint(c_host); + while (m_client->available()) audioFileRead(); // empty client buffer + return true; + } + } + info(*this, evt_info, "redirect to new host \"{}\"", c_host); + httpPrint(c_host); + return true; + } + } else { + AUDIO_LOG_WARN("unknown redirection: {}", rhl.c_get()); + } + } + + else if (rhl.starts_with_icase("content-encoding:")) { + info(*this, evt_info, "{}", rhl.get()); + if (rhl.contains("gzip")) { + AUDIO_LOG_ERROR("can't extract gzip"); + goto exit; + } + } + + else if (rhl.starts_with_icase("content-disposition:")) { // e.g we have this headerline: content-disposition: attachment; filename=stream.asx + int idx = rhl.index_of_icase("filename="); + if (idx >= 0) { + ps_ptr fn; + fn.assign(rhl.get() + idx + 9); // Position directly after "filename=" + fn.replace("\"", ""); // remove '\"' around filename if present + info(*this, evt_info, "Filename is {}", fn.get()); + } + } else if (rhl.starts_with_icase("connection:")) { + if (rhl.contains_with_icase("close")) { m_f_connectionClose = true; /* AUDIO_LOG_ERROR("connection will be closed"); */ } // ends after ogg last Page is set + } + + else if (rhl.starts_with_icase("content-length:")) { + const char* c_cl = (rhl.get() + 15); + int32_t i_cl = atoi(c_cl); + m_audioFileSize = i_cl; + // info(*this, evt_info, "content-length: {}", m_audioFileSize); + } + + else if (rhl.starts_with_icase("transfer-encoding:")) { + if (rhl.ends_with_icase("chunked")) { // Station provides chunked transfer + m_f_chunked = true; + info(*this, evt_info, "chunked data transfer"); + m_chunkcount = 0; // Expect chunkcount in DATA + } + } + + else if (rhl.starts_with_icase("accept-ranges:")) { + if (rhl.ends_with_icase("bytes")) m_f_acceptRanges = true; + // AUDIO_LOG_INFO("{}", rhl.c_get()); + } + + else if (rhl.starts_with_icase("content-range:")) { + AUDIO_LOG_INFO("{}", rhl.c_get()); + } + + else if (rhl.starts_with_icase("www-authenticate:")) { + AUDIO_LOG_WARN("authentification failed, wrong credentials?"); + goto exit; + } else { + ; + } + } // outer while + +exit: // termination condition + m_f_alt_user_agent = false; + m_dataMode = AUDIO_NONE; + stopSong(); + return false; + +lastToDo: + m_f_alt_user_agent = false; + m_streamType = ST_WEBSTREAM; + if (m_audioFileSize > 0) m_streamType = ST_WEBFILE; // content length found + if (m_phreh.f_icy_data) m_streamType = ST_WEBSTREAM; + if (m_f_tts) m_streamType = ST_WEBSTREAM; // this is from AI or GoogleTTS(AI response) + + if (ct_seen && m_playlistFormat == FORMAT_M3U8 && !m_m3u8_host.valid()) { m_m3u8_host = m_lastHost; } + + if (m_codec != CODEC_NONE) { + m_dataMode = AUDIO_DATA; // Expecting data now + } else if (m_playlistFormat != FORMAT_NONE) { + m_dataMode = AUDIO_PLAYLISTINIT; // playlist expected + // AUDIO_LOG_INFO("now parse playlist"); + } else { + AUDIO_LOG_INFO("unknown content found at: {}", m_currentHost.c_get()); + goto exit; + } + + if (m_phreh.f_icy_data) { + if (m_icy_items.icy_description.valid()) info(*this, evt_icydescription, "{}", m_icy_items.icy_description); + if (m_icy_items.icy_genre.valid()) info(*this, evt_genre, "{}", m_icy_items.icy_genre); + if (m_icy_items.icy_logo.valid()) info(*this, evt_icylogo, "{}", m_icy_items.icy_logo); + if (m_icy_items.icy_name.valid()) info(*this, evt_name, "{}", m_icy_items.icy_name); + if (m_icy_items.icy_url.valid()) info(*this, evt_icyurl, "{}", m_icy_items.icy_url); + if (m_icy_items.icy_metaint.valid()) m_metaint = m_icy_items.icy_metaint.to_uint32(); + if (m_icy_items.icy_br.valid()) m_nominal_bitrate = m_icy_items.icy_br.to_uint32() * 1000; + } + + AUDIO_LOG_DEBUG("playlistFormat {}, dataMode {}, streamType: {}", plsFmtStr[m_playlistFormat], dataModeStr[m_dataMode], streamTypeStr[m_streamType]); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::parseHttpRangeHeader() { // this is the response to a Range request + + ps_ptr rhl; + rhl.alloc(1024, "rhl"); // responseHeaderline + bool ct_seen = false; + + if (m_dataMode != HTTP_RANGE_HEADER) { + AUDIO_LOG_ERROR("wrong datamode {}", m_dataMode); + goto exit; + } + + m_phrah.ctime = millis(); + m_phrah.timeout = 4500; // ms + + if (m_client->available() == 0) { + if (!m_phrah.f_time) { + m_phrah.stime = millis(); + m_phrah.f_time = true; + } + if ((millis() - m_phrah.stime) > m_phrah.timeout) { + AUDIO_LOG_ERROR("timeout"); + m_phrah.f_time = false; + return false; + } + } + m_phrah.f_time = false; + + rhl.clear(); + + while (true) { // outer while + uint16_t pos = 0; + if ((millis() - m_phrah.ctime) > m_phrah.timeout) { + AUDIO_LOG_ERROR("timeout"); + m_f_timeout = true; + goto exit; + } + while (m_client->available()) { + uint8_t b = audioFileRead(); + if (b == '\n') { + if (!pos) { // empty line received, is the last line of this responseHeader + goto lastToDo; + } + break; + } + if (b == '\r') rhl[pos] = 0; + if (b < 0x20) continue; + rhl[pos] = b; + pos++; + if (pos == 1023) { + pos = 1022; + continue; + } + if (pos == 1022) { + rhl[pos] = '\0'; + AUDIO_LOG_WARN("responseHeaderline overflow"); + } + } // inner while + if (!pos) { + vTaskDelay(5); + continue; + } + // AUDIO_LOG_WARN("rh {}", rhl.c_get()); + if (rhl.starts_with_icase("HTTP/")) { // HTTP status error code + char statusCode[5]; + statusCode[0] = rhl[9]; + statusCode[1] = rhl[10]; + statusCode[2] = rhl[11]; + statusCode[3] = '\0'; + int sc = atoi(statusCode); + if (sc > 310) { // e.g. HTTP/1.1 301 Moved Permanently + info(*this, evt_name, "{}", rhl.get()); + goto exit; + } + } + if (rhl.starts_with_icase("Server:")) { info(*this, evt_info, "{}", rhl.c_get()); } + if (rhl.starts_with_icase("Content-Length:")) { + // info(*this, evt_info, "{}", rhl.c_get()); + } + if (rhl.starts_with_icase("Content-Range:")) { info(*this, evt_info, "{}", rhl.c_get()); } + if (rhl.starts_with_icase("Content-Type:")) { + // info(*this, evt_info, "{}", rhl.c_get()); + } + } +exit: + return false; +lastToDo: + m_dataMode = AUDIO_DATA; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::initializeDecoder() { + if (m_decoder) { + AUDIO_LOG_WARN("stopSong first"); + return true; + } + m_codec = determineCodec(m_codec); // OGG cn be VORBIS, FLAC or OPUS, contentType must not always be correct + + const char* type = nullptr; + switch (m_codec) { + case CODEC_MP3: + type = "MP3"; + InBuff.setMaxBlocksize(m_frameSizeMP3); + break; + case CODEC_AAC: + type = "AAC"; + InBuff.setMaxBlocksize(m_frameSizeAAC); + break; + case CODEC_M4A: + type = "AAC"; + InBuff.setMaxBlocksize(m_frameSizeAAC); + break; + case CODEC_FLAC: + type = "FLAC"; + InBuff.setMaxBlocksize(m_frameSizeFLAC); + break; + case CODEC_OPUS: + type = "OPUS"; + InBuff.setMaxBlocksize(m_frameSizeOPUS); + break; + case CODEC_VORBIS: + type = "VORBIS"; + InBuff.setMaxBlocksize(m_frameSizeVORBIS); + break; + case CODEC_WAV: + type = "WAV"; + InBuff.setMaxBlocksize(m_frameSizeWav); + break; + default: + AUDIO_LOG_ERROR("unknown decoder"); + stopSong(); + return false; + break; + } + + if (type) { + m_decoder = createDecoder(type); + if (!m_decoder || !m_decoder->init()) { + AUDIO_LOG_ERROR("The {Decoder could not be initialized", type); + stopSong(); + return false; + } + } + info(*this, evt_info, "{}Decoder has been initialized", m_decoder->whoIsIt()); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::parseContentType(ps_ptr ct) { + enum : int { CT_NONE, CT_MP3, CT_AAC, CT_M4A, CT_WAV, CT_FLAC, CT_PLS, CT_M3U, CT_ASX, CT_M3U8, CT_TXT, CT_AACP, CT_OPUS, CT_OGG, CT_VORBIS }; + + // MIME types and their CT_Val values + static const struct { + const char* mime_type; + int ct_val; + } mime_map[] = { + {"audio/mpeg", CT_MP3}, + {"audio/mpeg3", CT_MP3}, + {"audio/x-mpeg", CT_MP3}, + {"audio/x-mpeg-3", CT_MP3}, + {"audio/mp3", CT_MP3}, + {"audio/aac", CT_AAC}, + {"audio/x-aac", CT_AAC}, + {"audio/aacp", CT_AAC}, + {"video/mp2t", CT_AAC}, + {"audio/mp2t", CT_AAC}, + {"video/m2ts", CT_AAC}, + {"audio/mp4", CT_M4A}, + {"audio/m4a", CT_M4A}, + {"audio/x-m4a", CT_M4A}, + {"audio/wav", CT_WAV}, + {"audio/x-wav", CT_WAV}, + {"audio/flac", CT_FLAC}, + {"audio/x-flac", CT_FLAC}, + {"audio/scpls", CT_PLS}, + {"audio/x-scpls", CT_PLS}, + {"application/pls+xml", CT_PLS}, + {"audio/mpegurl", CT_M3U}, + {"audio/x-mpegurl", CT_M3U}, + {"audio/ms-asf", CT_ASX}, + {"video/x-ms-asf", CT_ASX}, + {"audio/x-ms-asx", CT_ASX}, + {"application/ogg", CT_OGG}, + {"audio/ogg", CT_OGG}, + {"application/vnd.apple.mpegurl", CT_M3U8}, + {"application/hls+xml", CT_M3U8}, + {"application/x-mpegurl", CT_M3U8}, + {"application/octet-stream", CT_TXT}, + {"text/html", CT_TXT}, + {"text/plain", CT_TXT}, + {"application/json", CT_TXT}, + {NULL, CT_NONE} // Final marker + }; + + ct.trim(); + + m_codec = CODEC_NONE; + int ct_val = CT_NONE; + + // Search in the Lookup table + for (int i = 0; mime_map[i].mime_type != NULL; i++) { + ct.toLowerCase(); + if (ct.equals(mime_map[i].mime_type)) { + ct_val = mime_map[i].ct_val; + break; + } + } + + // Special cases for video/mp2t and audio/mp2t + if (ct_val == CT_AAC && (ct == "video/mp2t" || ct == "audio/mp2t") && m_m3u8Codec == CODEC_MP3) { ct_val = CT_MP3; } + // Special case for audio/mpegurl + if (ct_val == CT_M3U && ct == "audio/mpegurl" && m_expectedPlsFmt == FORMAT_M3U8) { ct_val = CT_M3U8; } + // Special case for application/json + if (ct_val == CT_TXT && ct == "application/json" && m_expectedPlsFmt == FORMAT_M3U8) { ct_val = CT_M3U8; } + + // exam for invalid content types + if (ct_val == CT_NONE) { + AUDIO_LOG_WARN("ContentType {} not supported", ct); + return false; + } + + // allocation of m_codec and m_playlist format + switch (ct_val) { + case CT_MP3: m_codec = CODEC_MP3; break; + case CT_AAC: m_codec = CODEC_AAC; break; + case CT_M4A: m_codec = CODEC_M4A; break; + case CT_FLAC: m_codec = CODEC_FLAC; break; + case CT_OPUS: + m_codec = CODEC_OPUS; + m_f_ogg = true; + break; + case CT_VORBIS: + m_codec = CODEC_VORBIS; + m_f_ogg = true; + break; + case CT_WAV: m_codec = CODEC_WAV; break; + case CT_OGG: + m_codec = CODEC_OGG; + m_f_ogg = true; + break; + case CT_PLS: m_playlistFormat = FORMAT_PLS; break; + case CT_M3U: m_playlistFormat = FORMAT_M3U; break; + case CT_ASX: m_playlistFormat = FORMAT_ASX; break; + case CT_M3U8: m_playlistFormat = FORMAT_M3U8; break; + case CT_TXT: + if (m_expectedCodec == CODEC_AAC) m_codec = CODEC_AAC; + if (m_expectedCodec == CODEC_MP3) m_codec = CODEC_MP3; + if (m_expectedPlsFmt == FORMAT_ASX) m_playlistFormat = FORMAT_ASX; + if (m_expectedPlsFmt == FORMAT_M3U) m_playlistFormat = FORMAT_M3U; + if (m_expectedPlsFmt == FORMAT_M3U8) m_playlistFormat = FORMAT_M3U8; + if (m_expectedPlsFmt == FORMAT_PLS) m_playlistFormat = FORMAT_PLS; + break; + default: AUDIO_LOG_ERROR("{}, unsupported audio format", ct); return false; + } + + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::showstreamtitle(char* st) { + if (!st) return; + // example for ml: + // StreamTitle='Oliver Frank - Mega Hitmix';StreamUrl='www.radio-welle-woerthersee.at'; + // or adw_ad='true';durationMilliseconds='10135';adId='34254';insertionType='preroll'; + // html: 'Bielszy odcień bluesa 682 cz.1' --> 'Bielszy odcień bluesa 682 cz.1' + + ps_ptr ml; + ps_ptr title; + ps_ptr artist; + ps_ptr streamTitle; + ps_ptr sUrl; + ml.htmlToUTF8(st); // convert to UTF-8 + + int16_t idx1 = 0, idx2, idx4, idx5, idx6, idx7, titleLen = 0, artistLen = 0, titleStart = 0, artistStart = 0; + + // if(idx1 < 0) idx1 = indexOf(ml, "Title:", 0); // Title found (e.g. https://stream-hls.bauermedia.pt/comercial.aac/playlist.m3u8) + // if(idx1 < 0) idx1 = indexOf(ml, "title:", 0); // Title found (e.g. #EXTINF:10,title="The Dan Patrick Show (M-F 9a-12p ET)",artist="zc1401" + + if (ml.index_of("StreamTitle='37364 + 00000037364.jpgBoyfriend + SingleDOVE CAMERON + CD4161BOYFRIEND + 2126303 + Dove Cameroncidadefm.jpg + Cidade12012660981 + Boyfriend
Cidade + 2022-11-15T22:00:00+00:002022-11-16T06:59:59+00:00 + Cidade22h às 07h0 +
';StreamUrl=''; + */ + idx4 = ml.index_of(""); + idx5 = ml.index_of(""); + idx6 = ml.index_of(""); + idx7 = ml.index_of(""); + if (idx4 == -1 || idx5 == -1) return; + titleStart = idx4 + 21; // + titleLen = idx5 - titleStart; + + if (idx6 != -1 && idx7 != -1) { + artistStart = idx6 + 21; // + artistLen = idx7 - artistStart; + } + if (titleLen) title.assign(ml.get() + titleStart, titleLen); + if (artistLen) artist.assign(ml.get() + artistStart, artistLen); + + if (title.valid() && artist.valid()) { + streamTitle.assign(title.get()); + streamTitle.append(" - "); + streamTitle.append(artist.get()); + } else if (title.valid()) { + streamTitle.assign(title.get()); + } else if (artist.valid()) { + streamTitle.assign(artist.get()); + } + } + + else if (ml.index_of("StreamTitle='") == 0) { + int start = 13; + int end = ml.index_of("';", start); + if (end < 0) end = ml.index_of("'", start); // fallback — when the station is transmitting incorrectly + if (end > start) { + int len = end - start; + streamTitle.assign(ml.get() + start, len); + } + } + + else if (ml.starts_with("Grouping:")) { + streamTitle.assign(ml.get() + 9); + } + + else if (ml.starts_with("#EXTINF")) { + // extraxt StreamTitle from m3u #EXTINF line to icy-format + // orig: #EXTINF:10,title="text="TitleName",artist="ArtistName" + // conv: StreamTitle=TitleName - ArtistName + // orig: #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" + // conv: StreamTitle=text=\"Spot Block End\" amgTrackId=\"9876543\" - + + idx1 = ml.index_of("title=\""); + idx2 = ml.index_of("artist=\""); + if (idx1 > 0) { + int titleStart = idx1 + 7; + int idx3 = ml.index_of("\"", titleStart); + if (idx3 > titleStart) { + int titleLength = idx3 - titleStart; + title.assign(ml.get() + titleStart, titleLength); + if (title.starts_with("text=\\")) { // #EXTINF:10,title="text=\"Spot Block End\"",artist=" ", + titleStart += 7; + idx3 = ml.index_of("\\", titleStart); + if (idx3 > titleStart) { + int titleLength = idx3 - titleStart; + title.assign(ml.get() + titleStart, titleLength); + } + } + } + } + if (idx2 > 0) { + int artistStart = idx2 + 8; + int idx3 = ml.index_of("\"", artistStart); + if (idx3 > artistStart) { + int artistLength = idx3 - artistStart; + artist.assign(ml.get() + artistStart, artistLength); + if (strcmp(artist.get(), " ") == 0) artist.reset(); + } + } + if (title.valid() && artist.valid()) { + streamTitle.assign(title.get()); + streamTitle.append(" - "); + streamTitle.append(artist.get()); + } else if (title.valid()) { + streamTitle.assign(title.get()); + } else if (artist.valid()) { + streamTitle.assign(artist.get()); + } + } else { + ; + } + + if (ml.index_of("StreamUrl=", 0) > 0) { + idx1 = ml.index_of("StreamUrl=", 0); + idx2 = ml.index_of(";", idx1); + if (idx1 >= 0 && idx2 > idx1) { // StreamURL found + uint16_t len = idx2 - idx1; + sUrl.assign(ml.get() + idx1, len); + if (!sUrl.equals(m_streamURL.c_get())) { + info(*this, evt_info, "Stream URL: {}", sUrl.c_get()); // e.g. StreamUrl='http://myUrl.com' + m_streamURL = sUrl; + } + } + } + + if (ml.index_of("adw_ad=", 0) > 0) { + idx1 = ml.index_of("adw_ad=", 0); + if (idx1 >= 0) { // Advertisement found + idx1 = ml.index_of("durationMilliseconds=", 0); + idx2 = ml.index_of(";", idx1); + if (idx1 >= 0 && idx2 > idx1) { + uint16_t len = idx2 - idx1; + ps_ptr sAdv; + sAdv.assign(ml.get() + idx1, len + 1); + // info(*this, evt_info, "Adveritsement: {}", sAdv.get()); + uint8_t pos = 21; // remove "StreamTitle=" + if (sAdv[pos] == '\'') pos++; // remove leading \' + if (sAdv[strlen(sAdv.get()) - 1] == '\'') sAdv[strlen(sAdv.get()) - 1] = '\0'; // remove trailing \' + info(*this, evt_info, "Advertisement: {}", sAdv.get() + pos); + } + } + return; + } + if (!streamTitle.valid()) return; + + if (!m_streamTitle.equals(streamTitle)) { + m_streamTitle.clone_from(streamTitle); + } else { + return; // is equal + } + + if (m_streamTitle.starts_with("{\"")) { // maybe a json string + // "{\"status\":0,\"error\":{\"info\":\"\\u042d\\u0442\\u043e \\u0440\\u0435\\u043a\\u043b\\u0430\\u043c\\u0430 \\u0438\\u043b\\u0438 + // \\u0434\\u0436\\u0438\\u043d\\u0433\\u043b\",\"code\":201},\"result\":\"\\u042d\\u0442\\u043e \\u0440\\u0435\\u043a\\u043b\\u0430\\u043c\\u0430 \\u0438\\u043b\\u0438 + // \\u0434\\u0436\\u0438\\u043d\\u0433\\u043b\"}\n0"; + ps_ptr jsonIn; + jsonIn.clone_from(m_streamTitle); + jsonIn.truncate_at('\n'); // can be '{"status":1,"message":"Ok","result":"Ok","errorCode":0}\n0' + if (!jsonIn.isJson()) return; + int idx = jsonIn.index_of_icase("\"result\""); + if (idx < 0) return; + jsonIn.remove_before(idx + 10); // remove "result": + jsonIn.truncate_at('"'); // remove after '"' Ok","result":"Ok","errorCode":0} --> OK + // AUDIO_LOG_INFO("jsonIn: {}", jsonIn.c_get()); + m_streamTitle.unicodeToUTF8(jsonIn.c_get()); + } + + info(*this, evt_streamtitle, "{}", m_streamTitle.c_get()); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::showCodecParams() { + + info(*this, evt_info, "Channels: {}", getChannels()); + info(*this, evt_info, "SampleRate (Hz): {}", getSampleRate()); + info(*this, evt_info, "BitsPerSample: {}", getBitsPerSample()); + // if(getBitRate()) { info(*this, evt_info, "BitRate (b/s): {}", getBitRate()); } + // else { info(*this, evt_info, "BitRate (b/s): N/A"); } + + if (m_codec == CODEC_AAC) { + info(*this, evt_info, "{}", m_decoder->arg2()); // AAC Format + uint8_t answ = m_decoder->val2(); // SBR + if (answ > 0 && answ < 4) { + const char sbr[4][50] = {"without SBR", "upsampled SBR", "downsampled SBR", "no SBR used, but file is upsampled by a factor 2"}; + info(*this, evt_info, "Spectral band replication: {}", sbr[answ]); + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::findNextSync(uint8_t* data, size_t len) { + // Mp3 and aac audio data are divided into frames. At the beginning of each frame there is a sync word. + // The sync word is 0xFFF. This is followed by information about the structure of the frame. + // Wav files have no frames + // Return: 0 the synchronous word was found at position 0 + // > 0 is the offset to the next sync word + // -1 the sync word was not found within the block with the length len + + m_fnsy.nextSync = 0; + + if (m_codec == CODEC_WAV) { + m_f_playing = true; + m_fnsy.nextSync = 0; + } + if (m_codec == CODEC_MP3) { + m_fnsy.nextSync = m_decoder->findSyncWord(data, (int32_t)len); + if (m_fnsy.nextSync == -1) return len; // syncword not found, search next block + m_decoder->clear(); + } + if (m_codec == CODEC_AAC) { m_fnsy.nextSync = m_decoder->findSyncWord(data, (int32_t)len); } + if (m_codec == CODEC_M4A) { + if (!m_M4A_chConfig) m_M4A_chConfig = 2; // guard + if (!m_M4A_sampleRate) m_M4A_sampleRate = 44100; + if (!m_M4A_objectType) m_M4A_objectType = 2; + m_decoder->setRawBlockParams(m_M4A_chConfig, m_M4A_sampleRate, 0, m_M4A_objectType, 0); + m_f_playing = true; + m_fnsy.nextSync = 0; + } + if (m_codec == CODEC_FLAC) { + m_fnsy.nextSync = m_decoder->findSyncWord(data, (int32_t)len); + if (m_fnsy.nextSync == -1) return len; // OggS not found, search next block + } + if (m_codec == CODEC_OPUS) { + m_fnsy.nextSync = m_decoder->findSyncWord(data, (int32_t)len); + if (m_fnsy.nextSync == -1) return len; // OggS not found, search next block + } + if (m_codec == CODEC_VORBIS) { + m_fnsy.nextSync = m_decoder->findSyncWord(data, len); + if (m_fnsy.nextSync == -1) return len; // OggS not found, search next block + } + if (m_fnsy.nextSync == -1) { + if (m_fnsy.swnf == 0) + info(*this, evt_info, "syncword not found"); + else { + m_fnsy.swnf++; // syncword not found counter, can be multimediadata + } + } + if (m_fnsy.nextSync == 0) { + if (m_fnsy.swnf) { + info(*this, evt_info, "syncword not found {} times", m_fnsy.swnf); + m_fnsy.swnf = 0; + } else { + info(*this, evt_info, "syncword found at pos 0"); + m_f_decode_ready = true; + } + } + if (m_fnsy.nextSync > 0) { info(*this, evt_info, "syncword found at pos {}", m_fnsy.nextSync); } + return m_fnsy.nextSync; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setDecoderItems() { + setChannels(m_decoder->getChannels()); + setSampleRate(m_decoder->getSampleRate()); + setBitsPerSample(m_decoder->getBitsPerSample()); + if (m_decoder->arg1()) info(*this, evt_info, "{}", m_decoder->arg1()); + if (m_decoder->getAudioDataStart() > 0) { // only flac-ogg, native flac sets audioDataStart in readFlacHeader() + m_audioDataStart = m_decoder->getAudioDataStart(); + info(*this, evt_info, "AudioDataStart: {}", m_audioDataStart); + if (m_audioFileSize && !m_audioDataSize) m_audioDataSize = m_audioFileSize - m_audioDataStart; + } + if (m_lastGranulePosition && m_audioFileSize && m_i2s_items.sampleRate) { + m_audioFileDuration = (uint32_t)(m_lastGranulePosition / m_i2s_items.sampleRate); + m_nominal_bitrate = (m_audioFileSize - m_audioDataStart) * 8 / m_audioFileDuration; + AUDIO_LOG_DEBUG("m_nominal_bitrate {}, m_lastGranulePosition {}", m_nominal_bitrate, m_lastGranulePosition); + info(*this, evt_info, "Duration (s): {}", m_audioFileDuration); + } + + if (getBitsPerSample() != 8 && getBitsPerSample() != 16 && getBitsPerSample() != 24 && getBitsPerSample() != 32) { + AUDIO_LOG_ERROR("Bits per sample must be 8, 16, 24 or 32 found {}", getBitsPerSample()); + stopSong(); + } + + if (getChannels() != 1 && getChannels() != 2) { + AUDIO_LOG_ERROR("Num of channels must be 1 or 2, found {}", getChannels()); + stopSong(); + } + showCodecParams(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::decodeError(int8_t res, uint8_t* data, int32_t bytesDecoded) { + // for(int i = 0; i < 10; i++){printf("0x%02X ", data[i]);} printf("\n"); + if (res == -100) { + stopSong(); + return bytesDecoded; + } // serious error, e.g. decoder could not be initialized + if (m_codec == CODEC_AAC && res == -21) { // mono <-> stereo change + // According to the specification, the channel configuration is transferred in the first ADTS header and no longer changes in the entire + // stream. Some streams send short mono blocks in a stereo stream. e.g. http://mp3.ffh.de/ffhchannels/soundtrack.aac + // This triggers error -21 because the faad2 decoder cannot switch automatically. + m_sbyt.channels = 0; + if ((data[0] == 0xFF) || ((data[1] & 0xF0) == 0xF0)) { + int channel_config = ((data[2] & 0x01) << 2) | ((data[3] & 0xC0) >> 6); + if (channel_config != m_sbyt.channels) { + m_sbyt.channels = channel_config; + info(*this, evt_info, "AAC channel config changed to {}", m_sbyt.channels); + } + } + m_decoder->reset(); + m_decoder->init(); + return 0; + } + if (m_codec == CODEC_MP3) { + if (res == MP3Decoder::MP3_NEED_RESTART) { + info(*this, evt_info, "" ANSI_ESC_RED "Network error" ANSI_ESC_RESET ""); + connecttohost(m_lastHost.get()); + return 0; + } + } + m_f_playing = false; // seek for new syncword + if (bytesDecoded == 0) return 1; // skip one byte and seek for the next sync word + return bytesDecoded; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::decodeContinue(int8_t res, uint8_t* data, int32_t bytesDecoded, int32_t* bytesLeft) { + // if(m_codec == CODEC_MP3){ if(res == MAD_ERROR_CONTINUE) return bytesDecoded;} // nothing to play, mybe eof + if (m_codec == CODEC_AAC) { + if (res == AACDecoder::AAC_ID3_HDR) { + uint32_t size = ((data[6 + bytesDecoded] & 0x7F) << 21) | ((data[7 + bytesDecoded] & 0x7F) << 14) | ((data[8 + bytesDecoded] & 0x7F) << 7) | (data[9 + bytesDecoded] & 0x7F); + size += 10; // skip payload + return bytesDecoded + size; + if (bytesDecoded > *bytesLeft) AUDIO_LOG_ERROR("AAC input data too small bytesDecoded {} > bytesLeft {}", bytesDecoded, *bytesLeft); + } + } + + if (m_codec == CODEC_FLAC) { + if (res == FlacDecoder::FLAC_PARSE_OGG_DONE) return bytesDecoded; + if (res == FlacDecoder::FLAC_DECODE_FRAMES_LOOP) return bytesDecoded; + } // nothing to play + if (m_codec == CODEC_OPUS) { + if (res == OpusDecoder::OPUS_PARSE_OGG_DONE) return bytesDecoded; + if (res == OpusDecoder::OPUS_END) return bytesDecoded; + } // nothing to play + if (m_codec == CODEC_VORBIS) { + if (res == VorbisDecoder::VORBIS_PARSE_OGG_DONE) return bytesDecoded; + if (res == VorbisDecoder::VORBIS_COMMENT_DONE) return bytesDecoded; + if (res == VorbisDecoder::VORBIS_COMMENT_NEED_MORE) return bytesDecoded; + } // nothing to play + if (m_codec == CODEC_MP3) { + if (res == MP3Decoder::MP3_NEXT_FRAME) return bytesDecoded; + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::sendBytes(uint8_t* data, size_t len) { + if (!m_f_running) return 0; // guard + if (!m_decoder) return 0; // guard + + int res = 0; + int bytesDecoded = 0; + const char* st = NULL; + std::vector vec; + uint16_t samples_out = 0; + if (m_validSamples) { goto exit; } // nothing to decode, next round + + m_sbyt.bytesLeft = 0; + m_sbyt.nextSync = 0; + + if (!m_f_playing) { + m_sbyt.channels = 2; // assume aac stereo + m_sbyt.isPS = 0; + m_sbyt.f_setDecodeParamsOnce = true; + m_sbyt.nextSync = findNextSync(data, len); + if (m_sbyt.nextSync < 0) return len; // no syncword found + if (m_sbyt.nextSync == 0) { m_f_playing = true; } + if (m_sbyt.nextSync > 0) return m_sbyt.nextSync; + } + // m_f_playing is true at this pos + + m_sbyt.bytesLeft = len; + + if (m_codec == CODEC_NONE && m_playlistFormat == FORMAT_M3U8) return 0; // can happen when the m3u8 playlist is loaded + if (!m_f_decode_ready) return 0; // find sync first + + //----------------------------------------------------------------- + res = m_decoder->decode(data, &m_sbyt.bytesLeft, m_outBuff.get()); + bytesDecoded = len - m_sbyt.bytesLeft; + //----------------------------------------------------------------- + + // res - possible values are: + // 0: okay, no error + // >= 100: the decoder needs more data + // < 0: there has been an error + // -100: serious error, stop song + + if (res < 0) { return decodeError(res, data, bytesDecoded); } // Error, skip the frame... + if (res > 99) { return decodeContinue(res, data, bytesDecoded, &m_sbyt.bytesLeft); } // decoder needs more data... + + if ((bytesDecoded == 0) && (m_codec != CODEC_VORBIS && m_codec != CODEC_FLAC)) { // unlikely framesize, exept VORBIS decodes lastSegmentTable + info(*this, evt_info, "framesize is 0, start decoding again"); + m_f_playing = false; // seek for new syncword + // we're here because there was a wrong sync word so skip one byte and seek for the next + return 1; + } + // status: bytesDecoded > 0 and res >= 0 + + switch (m_codec) { + case CODEC_WAV: m_validSamples = m_decoder->getOutputSamples(); break; + case CODEC_MP3: m_validSamples = m_decoder->getOutputSamples(); break; + case CODEC_AAC: + m_validSamples = m_decoder->getOutputSamples() / getChannels(); + if (!m_sbyt.isPS && m_decoder->val1()) { // only change 0 -> 1 + m_sbyt.isPS = 1; + info(*this, evt_info, "Parametric Stereo"); + } else + m_sbyt.isPS = m_decoder->val1(); + break; + case CODEC_M4A: m_validSamples = m_decoder->getOutputSamples() / getChannels(); break; + case CODEC_FLAC: + m_validSamples = m_decoder->getOutputSamples(); + st = m_decoder->getStreamTitle(); + if (st) { info(*this, evt_streamtitle, "{}", st); } + vec = m_decoder->getMetadataBlockPicture(); + if (vec.size() > 0) { // get blockpic data + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + // AUDIO_LOG_INFO("ogg metadata blockpicture found:"); + // for(int i = 0; i < vec.size(); i += 2) { AUDIO_LOG_INFO("segment {:02}, pos {:07}, len {:05}", i / 2, vec[i], vec[i + 1]); } + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + info(*this, evt_image, vec); + } + break; + case CODEC_OPUS: + m_validSamples = m_decoder->getOutputSamples(); + st = m_decoder->getStreamTitle(); + if (st) { info(*this, evt_streamtitle, st); } + vec = m_decoder->getMetadataBlockPicture(); + if (vec.size() > 0) { // get blockpic data + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + // AUDIO_LOG_INFO("ogg metadata blockpicture found:"); + // for(int i = 0; i < vec.size(); i += 2) { AUDIO_LOG_INFO("segment {:02}, pos {:07}, len {:05}", i / 2, vec[i], vec[i + 1]); } + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + info(*this, evt_image, vec); + } + if (m_decoder->arg1()) { + if (m_sbyt.opus_mode != m_decoder->arg1()) { + info(*this, evt_info, m_decoder->arg1()); + m_sbyt.opus_mode = m_decoder->arg1(); + } + } + break; + + case CODEC_VORBIS: + m_validSamples = m_decoder->getOutputSamples(); + st = m_decoder->getStreamTitle(); + if (st) { info(*this, evt_streamtitle, st); } + vec = m_decoder->getMetadataBlockPicture(); + if (vec.size() > 0) { // get blockpic data + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + // AUDIO_LOG_INFO("ogg metadata blockpicture found:"); + // for(int i = 0; i < vec.size(); i += 2) { AUDIO_LOG_INFO("segment {:02}, pos {:07}, len {:05}", i / 2, vec[i], vec[i + 1]); } + // AUDIO_LOG_INFO("---------------------------------------------------------------------------"); + info(*this, evt_image, vec); + } + break; + } + if (m_sbyt.f_setDecodeParamsOnce && m_validSamples) { + m_sbyt.f_setDecodeParamsOnce = false; + setDecoderItems(); + } + samples_out = m_validSamples; + +exit: + m_curSample = 0; + if (m_validSamples) { + calculateAudioTime(bytesDecoded, samples_out); + playChunk(); + } + return bytesDecoded; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::calculateAudioTime(uint16_t bytesDecoderIn, uint16_t samples_decoder_out) { + + // if(m_dataMode != AUDIO_LOCALFILE && m_streamType != ST_WEBFILE) return; //guard + + float audioCurrentTime = 0.0; + + if (m_cat.firstCall) { // first call + m_cat.firstCall = false; + m_cat.reset(); + + if (m_codec == CODEC_FLAC && m_decoder->getAudioFileDuration()) { // BITSTREAMINFO FLAC/OGG + m_audioFileDuration = m_decoder->getAudioFileDuration(); + m_cat.nominalBitRate = (m_audioDataSize / m_decoder->getAudioFileDuration()) * 8; + } + + if (m_nominal_bitrate) { + info(*this, evt_bitrate, "{}", m_nominal_bitrate); + m_cat.nominalBitRate = m_nominal_bitrate; + m_audioFileDuration = round(((float)m_audioDataSize * 8 / m_cat.nominalBitRate)); + if (m_lastGranulePosition) + m_cat.tota_samples = m_lastGranulePosition; + else + m_cat.tota_samples = m_audioFileDuration * m_i2s_items.sampleRate; + } + } + + m_cat.sumBytesIn += bytesDecoderIn; + m_cat.deltaBytesIn += bytesDecoderIn; + m_cat.sum_samples += samples_decoder_out; + + if (m_cat.timeStamp + 50 < millis()) { + uint32_t t = millis(); // time tracking + uint32_t delta_t = t - m_cat.timeStamp; // ---"--- + m_cat.timeStamp = t; // ---"--- + + if (m_cat.nominalBitRate) { + audioCurrentTime = (uint32_t)(m_cat.sum_samples / m_i2s_items.sampleRate); + } else { + double instBitRate = (m_cat.deltaBytesIn * 8000.0) / delta_t; + m_cat.counter++; + m_cat.avrBitRate += (instBitRate - m_cat.avrBitRate) / m_cat.counter; + if ((abs(m_cat.avrBitRate - m_cat.oldAvrBitrate < 50)) && !m_cat.avrBitrateStable && m_cat.avrBitRate > 1000) { + m_cat.brCounter++; + if (m_cat.brCounter > 6) { + m_cat.avrBitrateStable = m_cat.avrBitRate; + info(*this, evt_bitrate, "{}", m_cat.avrBitrateStable); // estimated + } + } + m_avr_bitrate = m_cat.avrBitRate; + audioCurrentTime = (float)m_cat.sumBytesIn * 8 / m_cat.avrBitRate; + m_audioFileDuration = round(((float)m_audioDataSize * 8 / m_cat.avrBitRate)); + m_cat.oldAvrBitrate = m_avr_bitrate; + } + m_cat.deltaBytesIn = 0; + m_audioCurrentTime = round(audioCurrentTime); + } + + if (m_haveNewFilePos && (m_cat.avrBitRate || m_cat.nominalBitRate)) { + uint32_t posWhithinAudioBlock = m_haveNewFilePos - m_audioDataStart; + float newTime = 0; + if (m_cat.nominalBitRate) { + newTime = (float)posWhithinAudioBlock / (m_cat.nominalBitRate / 8); + } else { + newTime = (float)posWhithinAudioBlock / (m_cat.avrBitRate / 8); + m_avr_bitrate = m_cat.avrBitRate; + } + m_audioCurrentTime = round(newTime); + m_cat.sumBytesIn = posWhithinAudioBlock; + m_haveNewFilePos = 0; + m_cat.syltIdx = 0; + if (m_syltLines.size()) { + while (m_cat.syltIdx < m_syltLines.size()) { + if (m_audioCurrentTime * 1000 < m_syltTimeStamp[m_cat.syltIdx]) break; + m_cat.syltIdx++; + } + if (m_cat.syltIdx) m_cat.syltIdx--; + } + } + + if (m_syltLines.size()) { + // AUDIO_LOG_INFO("{}", audioCurrentTime * 1000); // ms + if (m_cat.syltIdx >= m_syltLines.size()) return; + if (m_audioCurrentTime * 1000 > m_syltTimeStamp[m_cat.syltIdx]) { + info(*this, evt_lyrics, "{}", m_syltLines[m_cat.syltIdx].c_get()); + m_cat.syltIdx++; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::i2s_config() { + esp_err_t result = ESP_OK; + // -------- I2S configuration ------------------------------------------------------------------------------------------- + memset(&m_i2s_chan_cfg, 0, sizeof(i2s_chan_config_t)); +#if (ESP_IDF_VERSION_MAJOR < 6) + m_i2s_chan_cfg.id = (i2s_port_t)m_i2s_items.i2s_num; // I2S_NUM_AUTO, I2S_NUM_0, I2S_NUM_1 +#else + m_i2s_chan_cfg.id = m_i2s_items.i2s_num; // I2S_NUM_AUTO, I2S_NUM_0, I2S_NUM_1 +#endif + m_i2s_chan_cfg.role = I2S_ROLE_MASTER; // I2S controller master role, bclk and lrc signal will be set to output + m_i2s_chan_cfg.dma_desc_num = settings.DMA_DESC_NUM; // number of DMA buffer + m_i2s_chan_cfg.dma_frame_num = settings.DMA_FRAME_NUM; // I2S frame number in one DMA buffer. + m_i2s_chan_cfg.auto_clear = true; // i2s will always send zero automatically if no data to send + m_i2s_chan_cfg.allow_pd = false; + m_i2s_chan_cfg.intr_priority = 2; + result = i2s_new_channel(&m_i2s_chan_cfg, &m_i2s_tx_handle, NULL); + if (result != ESP_OK) { // ESP_ERR_INVALID_ARG? + AUDIO_LOG_ERROR("I2S channel: invalid argument"); + return false; + } + + memset(&m_i2s_std_cfg, 0, sizeof(i2s_std_config_t)); + m_i2s_std_cfg.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO); // Set to enable bit shift in Philips mode + m_i2s_std_cfg.gpio_cfg.bclk = I2S_GPIO_UNUSED; // BCLK, Assignment in setPinout() + m_i2s_std_cfg.gpio_cfg.din = I2S_GPIO_UNUSED; // not used + m_i2s_std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED; // DOUT, Assignment in setPinout() + m_i2s_std_cfg.gpio_cfg.mclk = I2S_GPIO_UNUSED; // MCLK, Assignment in setPinout() + m_i2s_std_cfg.gpio_cfg.ws = I2S_GPIO_UNUSED; // LRC, Assignment in setPinout() + m_i2s_std_cfg.gpio_cfg.invert_flags.mclk_inv = false; + m_i2s_std_cfg.gpio_cfg.invert_flags.bclk_inv = false; + m_i2s_std_cfg.gpio_cfg.invert_flags.ws_inv = false; + m_i2s_std_cfg.clk_cfg.sample_rate_hz = m_i2s_items.sampleRate; + m_i2s_std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_DEFAULT; + m_i2s_std_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256; + result = i2s_channel_init_std_mode(m_i2s_tx_handle, &m_i2s_std_cfg); + if (result != ESP_OK) { + if (result == ESP_ERR_INVALID_ARG) AUDIO_LOG_ERROR("invalid i2s configuration or i2s not standard mode"); + if (result == ESP_ERR_INVALID_STATE) AUDIO_LOG_ERROR("This i2s channel is not initialized or not stopped"); + return false; + } + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t MCLK) { + + i2s_std_gpio_config_t gpio_cfg = {}; + bool result = i2s_config(); + + gpio_cfg.bclk = (gpio_num_t)BCLK; + gpio_cfg.din = (gpio_num_t)I2S_GPIO_UNUSED; + gpio_cfg.dout = (gpio_num_t)DOUT; + gpio_cfg.mclk = (gpio_num_t)MCLK; + gpio_cfg.ws = (gpio_num_t)LRC; + +#if (ESP_ARDUINO_VERSION_MAJOR < 3) + AUDIO_LOG_ERROR("Arduino Version must be 3.0.0 or higher!"); + result = false; + goto exit; +#endif + + m_f_psramFound = psramInit(); + if (!m_f_psramFound) { + AUDIO_LOG_ERROR("PSRAM not found"); + result = false; + goto exit; + } + + m_outBuff.alloc_array(m_outbuffSize, "m_outBuff"); + m_resamplesBuff.alloc_array(m_resamplesBuffSize, "m_resamplesBuff"); + m_vu_items.delay_l.alloc_array(m_i2s_chan_cfg.dma_desc_num * m_i2s_chan_cfg.dma_frame_num, "delay_l"); + m_vu_items.delay_r.alloc_array(m_i2s_chan_cfg.dma_desc_num * m_i2s_chan_cfg.dma_frame_num, "delay_r"); + m_fft_items.buffer.alloc_array(m_fft_items.SIZE, "buffer"); + m_fft_items.window.alloc_array(m_fft_items.SIZE, "window"); + m_fft_items.work.alloc_array(m_fft_items.SIZE * 2, "work"); + m_metadataBuff.alloc(4096 + 1, "m_metadataBuff"); // max 4096 + 1 for null terminator, just to make library code 'safe' + m_httpRespHdrBuff.alloc(4096, "m_httpRespHdrBuff"); // enough space to store http response header + + if (!m_outBuff.valid() || !m_vu_items.delay_l.valid() || !m_vu_items.delay_r.valid() || !m_resamplesBuff.valid() || !m_fft_items.buffer.valid() || !m_fft_items.buffer.valid() || + !m_fft_items.work.valid()) { + result = false; + goto exit; + } + + //---------------------------- FFT INIT----------------------------------------- + for (int i = 0; i < m_fft_items.SIZE; i++) { // Hann window + m_fft_items.window[i] = 0.5f * (1.0f - cosf(2.0f * M_PI * i / (m_fft_items.SIZE - 1))); + } + + if (dsps_fft2r_init_fc32(nullptr, m_fft_items.SIZE) == ESP_OK) { + m_fft_items.initialized = true; + } else { + AUDIO_LOG_ERROR("FFT init failed (size={})", m_fft_items.SIZE); + result = false; + goto exit; + } + //----------------------------------------------------------------------------- + + I2Sstop(); + if (i2s_channel_reconfig_std_gpio(m_i2s_tx_handle, &gpio_cfg) != ESP_OK) { + result = false; + goto exit; + } + I2Sstart(); + +exit: + + calculateVolumeLimits(); // first init, vol = 21, vol_steps = 21 + startAudioTask(); + + m_f_I2S_init = result; + return m_f_I2S_init; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getFileSize() { // returns the size of webfile or local file + if (!m_audiofile) { + if (m_audioFileSize > 0) { return m_audioFileSize; } + return 0; + } + return m_audiofile.size(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getAudioFileDuration() { + if (!getBitRate()) return 0; + if (m_playlistFormat == FORMAT_M3U8) return 0; + if (!m_audioDataSize) return 0; + return m_audioFileDuration; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getAudioCurrentTime() { // return current time in seconds + return m_audioCurrentTime; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getAudioFilePosition() { + if (!m_f_stream) return 0; + if ((m_dataMode != AUDIO_LOCALFILE) && (m_streamType != ST_WEBFILE)) { + AUDIO_LOG_WARN("audio is not a file"); + return 0; + } + return m_audioFilePosition - inBufferFilled(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setAudioFilePosition(uint32_t pos) { + if (!m_f_stream) return false; + if ((m_dataMode != AUDIO_LOCALFILE) && (m_streamType != ST_WEBFILE)) { + AUDIO_LOG_WARN("audio is not a file"); + return false; + } + if ((m_streamType == ST_WEBFILE) && (!m_f_acceptRanges)) { + AUDIO_LOG_WARN("server does not accept ranges"); + return false; + } + if (pos > m_audioDataStart + m_audioDataSize) { + AUDIO_LOG_WARN("given position is too large"); + return false; + } + if (pos < m_audioDataStart) { + AUDIO_LOG_WARN("set audiodatastart at {}", m_audioDataStart); + m_resumeFilePos = m_audioDataStart; + } + m_resumeFilePos = pos; + + /* m_cat.tota_samples m_cat.sum_samples + ------------------ = ---------------------------------- + m_audioDataSize m_resumeFilePos - m_audioDataStart */ + + m_cat.sum_samples = (float)m_cat.tota_samples * ((float)(m_resumeFilePos - m_audioDataStart) / m_audioDataSize); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setAudioPlayTime(uint16_t sec) { + // e.g. setAudioPlayTime(300) sets the pointer at pos 5 min + if ((m_dataMode != AUDIO_LOCALFILE) && (m_streamType != ST_WEBFILE)) return false; // guard + if (!getBitRate()) return false; // guard + if (!m_f_running) return false; // guard + + if (sec > getAudioFileDuration()) { + AUDIO_LOG_WARN("setAudioPlayTime: {}s >= audioFileDuration: {}s -> stopSong", sec, getAudioFileDuration()); + stopSong(); + return false; + } + uint32_t filepos = m_audioDataStart + (getBitRate() * sec / 8); + m_resumeFilePos = filepos; + m_cat.sum_samples = (float)m_cat.tota_samples * ((float)(m_resumeFilePos - m_audioDataStart) / m_audioDataSize); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setTimeOffset(int sec) { // fast forward or rewind the current position in seconds + // info(*this, evt_info, "time offset {} sec", sec); + if ((m_dataMode != AUDIO_LOCALFILE) && (m_streamType != ST_WEBFILE)) { + AUDIO_LOG_WARN("{}", "not a file"); + return false; + } // guard + if (!getBitRate()) return false; // guard + if (!m_f_running) return false; // guard + + int32_t newTime = getAudioCurrentTime() + sec; + if (newTime < 0) newTime = 0; + if (newTime > getAudioFileDuration()) { + stopSong(); + return true; + } + + uint32_t oneSec = getBitRate() / 8; // bytes decoded in one sec + int32_t offset = oneSec * sec; // bytes to be wind/rewind + int32_t pos = m_audioFilePosition - inBufferFilled(); + pos += offset; + m_resumeFilePos = pos; + m_cat.sum_samples = (float)m_cat.tota_samples * ((float)(m_resumeFilePos - m_audioDataStart) / m_audioDataSize); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setVolumeSteps(uint8_t steps) { + // clamp new steps + uint8_t new_steps = max(steps, (uint8_t)21); + uint8_t old_steps = m_audio_items.volume_steps; + + if (new_steps == old_steps) return; + + // ratio OLD → NEW + float corr = (float)new_steps / (float)old_steps; + + // scale target volume + float new_volume = (float)m_audio_items.volume * corr; + + // also scale the current volume (very important!) + m_audio_items.cur_volume *= corr; + + // take over + clamp + m_audio_items.volume_steps = new_steps; + + m_audio_items.volume = (uint8_t)lroundf(new_volume); + if (m_audio_items.volume > new_steps) m_audio_items.volume = new_steps; + + if (m_audio_items.cur_volume > (float)new_steps) m_audio_items.cur_volume = (float)new_steps; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t Audio::getVolumeSteps() { + return m_audio_items.volume_steps; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setMute(bool mute) { + m_audio_items.mute = mute; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::getMute() { + return m_audio_items.mute; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::audioFileRead() { + int res = -1; + if (m_dataMode == AUDIO_LOCALFILE) { + res = m_audiofile.read(); + if (res >= 0) m_audioFilePosition++; + } else { + res = m_client->read(); + if (res >= 0) m_audioFilePosition++; + } + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::audioFileRead(uint16_t timeout_ms) { + int32_t res = -1; + uint32_t timeout = millis() + timeout_ms; + + while (true) { + res = audioFileRead(); + if (res >= 0) break; + if (timeout < millis()) { + AUDIO_LOG_ERROR("timeout"); + return -1; + } + vTaskDelay(10); + } + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::audioFileRead(uint8_t* buff, size_t len) { + if (buff && len == 0) return 0; // nothing to do + int32_t readed_bytes = 0; + uint32_t offset = 0; + int res = -1; + + // read len + if (m_dataMode == AUDIO_LOCALFILE) { + readed_bytes = m_audiofile.read(buff + offset, len); + if (readed_bytes >= 0) { + m_audioFilePosition += readed_bytes; + len -= readed_bytes; + offset += readed_bytes; + res = offset; + } + } else { + readed_bytes = m_client->read(buff + offset, len); + if (readed_bytes > 0) { + m_audioFilePosition += readed_bytes; + len -= readed_bytes; + offset += readed_bytes; + res = offset; + } + } + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::audioFileRead(uint8_t* buff, size_t len, uint16_t timeout_ms) { + + uint32_t timeout = millis() + timeout_ms; + int32_t bytes_has_read = 0; + uint8_t cnt = 0; + while (bytes_has_read < len) { + int32_t res = audioFileRead(buff + bytes_has_read, len - bytes_has_read); + if (res <= 0) { vTaskDelay(10); } + if (res > 0) { bytes_has_read += res; } + if (timeout < millis()) { + AUDIO_LOG_ERROR("timeout, len: {} != bytes_has_read: {}", len, bytes_has_read); + return -1; + } + AUDIO_LOG_DEBUG("buffFillValue {}, res {}, bytes_has_read {}", len, res, bytes_has_read); + } + AUDIO_LOG_DEBUG("len: {} != bytes_has_read: {}", len, bytes_has_read); + return bytes_has_read; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::audioFileSeek(uint32_t position, size_t len) { + int32_t res = -1; + + if (m_dataMode == AUDIO_LOCALFILE) { + uint32_t actualPos = m_audiofile.position(); // starts with 1 + if (actualPos != m_audioFilePosition) { + AUDIO_LOG_DEBUG("actualPos != m_audioFilePosition {} != {}", actualPos, m_audioFilePosition); + m_audioFilePosition = actualPos; + } + if (!m_audiofile) return -1; + if (position > m_audiofile.size()) { + AUDIO_LOG_WARN("position larger than size {} > {}", position, m_audiofile.size()); + position = m_audiofile.size(); + } + bool r = m_audiofile.seek(position); + m_audioFilePosition = m_audiofile.position(); + if (r == false) { + AUDIO_LOG_ERROR("something went wrong"); + return -1; + } else { + return position; + } + } else { + if (m_f_acceptRanges) { + bool r; + if (len == 0) len = UINT32_MAX; + r = httpRange(position, len); + if (res == false) { + AUDIO_LOG_ERROR("http range request was not successful"); + return 0; + } + r = parseHttpRangeHeader(); + if (r == false) { + AUDIO_LOG_ERROR("http range response was not successful"); + return 0; + } + m_audioFilePosition = position; + return position; + } + } + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::fsRange(uint32_t range) { + + if ((m_dataMode == AUDIO_LOCALFILE) && !m_audiofile) { + AUDIO_LOG_WARN("{}", "local file not accessibble"); + return false; + } // guard + uint32_t startAB = m_audioDataStart; // audioblock begin + uint32_t endAB = m_audioDataStart + m_audioDataSize; // audioblock end + if (range < (int32_t)startAB) { range = startAB; } + if (range >= (int32_t)endAB) { range = endAB; } + + m_validSamples = 0; + m_resumeFilePos = range; // used in processLocalFile() + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setSampleRate(uint32_t sampRate) { + + if (!sampRate) return false; + if (sampRate < 8000) { + AUDIO_LOG_WARN("Sample rate must not be smaller than 8kHz, found: {}", sampRate); + return false; + } + m_i2s_items.sampleRate = sampRate; + reconfigI2S(); + IIR_calculateCoefficients(); + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getSampleRate() { + return m_i2s_items.sampleRate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setBitsPerSample(int bits) { + if ((bits != 32) && (bits != 24) && (bits != 16) && (bits != 8)) return false; + m_bitsPerSample = bits; + return true; +} +uint8_t Audio::getBitsPerSample() { + return m_bitsPerSample; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::setChannels(int ch) { + m_channels = ch; + return true; +} +uint8_t Audio::getChannels() { + if (m_channels == 0) { // this should not happen! #209 + m_channels = 2; + } + return m_channels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getBitRate() { + if (m_nominal_bitrate) return m_nominal_bitrate; + return m_avr_bitrate; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +uint64_t Audio::getLastGranulePosition(uint8_t codec) { + if (codec != CODEC_OPUS && codec != CODEC_VORBIS) return 0; // only opus or vorbis + if (m_audioFileSize == 0) { return 0; } // only files + + uint64_t granulePos = 0; + ps_ptr buff; + buff.alloc(UINT16_MAX, "buff"); + + int rangeStart = m_audioFileSize - UINT16_MAX - 1; + audioFileSeek(rangeStart, UINT16_MAX); + audioFileRead((uint8_t*)buff.get(), UINT16_MAX, 3000); + + int32_t pos = buff.last_special_index_of("OggS", UINT16_MAX); + if (buff[pos + 5] & 0x04) { // is last page; + for (int j = 0; j < 8; j++) { granulePos |= ((uint64_t)buff[pos + 6 + j] << (j * 8)); } + } + AUDIO_LOG_DEBUG("granulePos {}", granulePos); + + m_resumeFilePos = 0; + return granulePos; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setI2SCommFMT_LSB(bool commFMT) { + // false: I2S communication format is by default I2S_COMM_FORMAT_I2S_MSB, right->left (AC101, PCM5102A) + // true: changed to I2S_COMM_FORMAT_I2S_LSB for some DACs (PT8211) + // Japanese or called LSBJ (Least Significant Bit Justified) format + + if (commFMT) { + info(*this, evt_info, "commFMT = LSBJ (Least Significant Bit Justified)"); + } else { + info(*this, evt_info, "commFMT = Philips"); + } + m_i2s_items.commFMT = commFMT; + reconfigI2S(); + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::reconfigI2S() { + + i2s_channel_disable(m_i2s_tx_handle); + + if (m_i2s_items.commFMT) { + m_i2s_std_cfg.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO); + } else { + m_i2s_std_cfg.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO); + } + i2s_channel_reconfig_std_slot(m_i2s_tx_handle, &m_i2s_std_cfg.slot_cfg); + + if (m_output_sr) { + m_resampler.phase = 0; // prepare resampler + m_resampler.phaseStep = ((uint64_t)m_i2s_items.sampleRate << 32) / m_output_sr; + m_resampler.g_lpCoeffs = makeButterworthLPF_Q31(m_i2s_items.sampleRate); + m_resampler.lpLeft = {}; + m_resampler.lpRight = {}; + m_i2s_std_cfg.clk_cfg.sample_rate_hz = m_output_sr; + AUDIO_LOG_DEBUG("output samplerate is {}", m_i2s_std_cfg.clk_cfg.sample_rate_hz); + } else { + m_i2s_std_cfg.clk_cfg.sample_rate_hz = m_i2s_items.sampleRate; + } + i2s_channel_reconfig_std_clock(m_i2s_tx_handle, &m_i2s_std_cfg.clk_cfg); + i2s_channel_enable(m_i2s_tx_handle); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::calculateVUlevel(int32_t* sample) { // Envelope-Follower + + uint16_t DELAY_BUFFER_SIZE = m_i2s_chan_cfg.dma_desc_num * m_i2s_chan_cfg.dma_frame_num; // Runtime in I2S-DMA + // delay line + m_vu_items.delay_l[m_vu_items.delay_line_index] = sample[LEFTCHANNEL]; + m_vu_items.delay_r[m_vu_items.delay_line_index] = sample[RIGHTCHANNEL]; + m_vu_items.delay_line_index++; + if (m_vu_items.delay_line_index == DELAY_BUFFER_SIZE) m_vu_items.delay_line_index = 0; + + int16_t pos = m_vu_items.delay_line_index - 1; + if (pos == -1) pos = DELAY_BUFFER_SIZE - 1; + + // FFT buffer + float mono = 0.5f * (float)((m_vu_items.delay_l[pos] >> 20) + (m_vu_items.delay_r[pos] >> 20)); + + // --- FFT analyzer AGC --- + constexpr float TARGET = 0.1f; // gewünschte RMS-Amplitude + constexpr float ATTACK = 0.05f; + constexpr float RELEASE_FFT = 0.005f; + + float level = fabsf(mono); + + if (level > 1e-6f) { + float desired = TARGET / level; + if (desired < m_fft_items.gain) + m_fft_items.gain += ATTACK * (desired - m_fft_items.gain); + else + m_fft_items.gain += RELEASE_FFT * (desired - m_fft_items.gain); + } + if (fabsf(mono) < 1e-4f) mono = 0.0f; + mono *= m_fft_items.gain; + + m_fft_items.buffer[m_fft_items.buffer_index] = mono; + m_fft_items.buffer_index++; + if (m_fft_items.buffer_index == m_fft_items.SIZE) m_fft_items.buffer_index = 0; + + uint8_t l = 0, r = 0; + l = abs(m_vu_items.delay_l[pos] >> 23); + r = abs(m_vu_items.delay_r[pos] >> 23); + + // Attack immediately + constexpr float RELEASE = 1.0f; // the bigger, the more sluggish + if (l > m_vu_items.left) { + m_vu_items.left = l; + } else if (m_vu_items.left > RELEASE) { + m_vu_items.left -= RELEASE; + } + if (r > m_vu_items.right) { + m_vu_items.right = r; + } else if (m_vu_items.right > RELEASE) { + m_vu_items.right -= RELEASE; + } + + // LEFT + if (m_vu_items.left > m_vu_items.left_peak) { + m_vu_items.left_peak = m_vu_items.left; + m_vu_items.left_hold = settings.PEAK_HOLD_SAMPLES; + } else { + if (m_vu_items.left_hold > 0) { + m_vu_items.left_hold--; + } else if (m_vu_items.left_peak > settings.PEAK_RELEASE) { + m_vu_items.left_peak -= settings.PEAK_RELEASE; + } + } + + // RIGHT + if (m_vu_items.right > m_vu_items.right_peak) { + m_vu_items.right_peak = m_vu_items.right; + m_vu_items.right_hold = settings.PEAK_HOLD_SAMPLES; + } else { + if (m_vu_items.right_hold > 0) { + m_vu_items.right_hold--; + } else if (m_vu_items.right_peak > settings.PEAK_RELEASE) { + m_vu_items.right_peak -= settings.PEAK_RELEASE; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint16_t Audio::getVUlevel() { + if (!m_f_running) return 0; + AUDIO_LOG_DEBUG("{}", m_vu_items.left); + // avg 0 ... 255 MSB LSB + return ((uint8_t)m_vu_items.right_peak << 8) + (uint8_t)m_vu_items.left_peak; // returns rrrrrrrrllllllll +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setTone(float gainLowPass, float gainBandPass, float gainHighPass) { + + // gainLowPass set between -12 ... +12 dB + // gainBandPass set between -12 ... +12 dB + // gainHighPass set between -12 ... +12 dB + + m_audio_items.gain_ls_db = fminf(fmaxf(gainLowPass, -12.0f), 12.0f); + m_audio_items.gain_peq_db = fminf(fmaxf(gainBandPass, -12.0f), 12.0f); + m_audio_items.gain_hs_db = fminf(fmaxf(gainHighPass, -12.0f), 12.0f); + + IIR_calculateCoefficients(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::forceMono(bool m) { // #100 mono option + m_f_forceMono = m; // false stereo, true mono +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setOutputSampleRate(OutputSR_t sr) { // + if (sr == SR_44100) { + m_output_sr = SR_44100; // output sr is always 44.1KHz + } else if (sr == SR_48000) { + m_output_sr = SR_48000; // output sr is always 48KHz + } else { + m_output_sr = SR_ORIGIN; // output sr is source sr + } + reconfigI2S(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setBalance(float balance) { // left -16.0dB ... 0dB ... -16.0dB right + m_audio_items.balance = fminf(fmaxf(balance, -16.0f), 16.0f); + calculateVolumeLimits(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setVolume(uint8_t volume, uint8_t curve) { + + m_audio_items.volume = min(volume, m_audio_items.volume_steps); + + // curve is obsolete + calculateVolumeLimits(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::setVolumeCurve(VolumeCurveFn curve) { + + // user defined curve, set it in youe code e.g. somewhere in setup() + // t is volume / steps; (range 0.0f … 1.0f) + // should return a value between -60.0[dB] and 0.0[dB] + // example: + // audio.setVolumeCurve([](float t) { + // return -60.0f + 60.0f * t * t; + // }); + + m_volumeCurve = curve; + calculateVolumeLimits(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t Audio::getVolume() { + return m_audio_items.volume; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::getI2sPort() { + return m_i2s_items.i2s_num; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::gain_ramp() { + settings.VOL_FADING_SPEED = std::clamp(settings.VOL_FADING_SPEED, 1.0f, 100.0f); // avoid div0 + // determine goal + float target = m_audio_items.mute ? 0.0f : (float)m_audio_items.volume; + + // maximum change per tick + float step = (float)m_audio_items.volume_steps / settings.VOL_FADING_SPEED; + + float diff = target - m_audio_items.cur_volume; + + if (fabsf(diff) <= step) { + // Goal achieved (no oscillation!) + m_audio_items.cur_volume = target; + } else { + // Ramp + m_audio_items.cur_volume += (diff > 0.0f ? step : -step); + } + + // Security-Clamp + if (m_audio_items.cur_volume < 0.0f) + m_audio_items.cur_volume = 0.0f; + else if (m_audio_items.cur_volume > m_audio_items.volume_steps) + m_audio_items.cur_volume = m_audio_items.volume_steps; + + calculateVolumeLimits(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::calculateVolumeLimits() { // is calculated when the volume or balance changes + + constexpr float BALANCE_DB = -16.0f; + constexpr float MIN_DB = -60.0f; // quiet + constexpr float MAX_DB = 0.0f; // full level + + auto volumeToLinear = [&](float volume, uint8_t steps) { + if (volume <= 0.0f) { + return 0.0f; // real silence + } + + float t = volume / (float)steps; // 0.0f … 1.0f + t = fminf(fmaxf(t, 0.0f), 1.0f); + + // float dB = MIN_DB + t * (MAX_DB - MIN_DB); + float dB = m_volumeCurve ? m_volumeCurve(t) : (-112.0f * t * t * t + 172.0f * t * t + MIN_DB); + dB = fminf(fmaxf(dB, MIN_DB), MAX_DB); + + return powf(10.0f, dB / 20.0f); + }; + + float vol = volumeToLinear(m_audio_items.cur_volume, m_audio_items.volume_steps); + + float l_db = 0.0f; + float r_db = 0.0f; + + if (m_audio_items.balance > 0.0f) { // emphasize on the right → quieter on the left + l_db = BALANCE_DB * ((float)m_audio_items.balance / 16.0f); + } else if (m_audio_items.balance < 0.0f) { // emphasize on the left → quieter on the right + r_db = BALANCE_DB * ((float)-m_audio_items.balance / 16.0f); + } + + m_audio_items.limiter[LEFTCHANNEL] = vol * powf(10.0f, l_db / 20.0f); + m_audio_items.limiter[RIGHTCHANNEL] = vol * powf(10.0f, r_db / 20.0f); + AUDIO_LOG_DEBUG("m_limiter[LEFTCHANNEL] {}, m_limiter[RIGHTCHANNEL] {}", m_audio_items.limiter[LEFTCHANNEL], m_audio_items.limiter[RIGHTCHANNEL]); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::processSpectrum() { + + // --- 10 Hz update --- + uint32_t now = millis(); + if (now - m_fft_items.last_ms < 100) return; + m_fft_items.last_ms = now; + + // --- Window + real → complex --- + for (int i = 0; i < m_fft_items.SIZE; i++) { + m_fft_items.work[2 * i] = m_fft_items.buffer[i] * m_fft_items.window[i]; + m_fft_items.work[2 * i + 1] = 0.0f; + } + + // --- FFT --- + dsps_fft2r_fc32(m_fft_items.work.get(), m_fft_items.SIZE); + dsps_bit_rev_fc32(m_fft_items.work.get(), m_fft_items.SIZE); + dsps_cplx2reC_fc32(m_fft_items.work.get(), m_fft_items.SIZE); + + const float bin_hz = (float)m_i2s_items.sampleRate / m_fft_items.SIZE; + const float norm = 2.0f / m_fft_items.SIZE; + + // --- 5 internal bands --- + float band[m_fft_items.BANDS] = {0}; + int bins[m_fft_items.BANDS] = {0}; + + for (int i = 1; i < m_fft_items.SIZE / 2; i++) { + + float re = m_fft_items.work[2 * i]; + float im = m_fft_items.work[2 * i + 1]; + float mag = sqrtf(re * re + im * im) * norm; + float f = i * bin_hz; + + int b = -1; + if (f < 250) + b = 0; + else if (f < 400) + b = -1; + else if (f < 700) + b = 1; + else if (f < 1000) + b = -1; + else if (f < 1550) + b = 2; + else if (f < 2200) + b = -1; + else if (f < 4250) + b = 3; + else if (f < 6300) + b = -1; + else if (f < 11150) + b = 4; + else if (f < 16000) + b = 5; + else + b = -1; + + if (b >= 0) { + band[b] += mag * mag; + bins[b]++; + } + } + + // --- RMS + weighting --- + for (int i = 0; i < m_fft_items.BANDS; i++) { + if (bins[i]) + band[i] = sqrtf(band[i] / bins[i]); + else + band[i] = 0.0f; + } + + // band weighting (psychoacoustic / UI) + band[0] *= 0.5f; + band[1] *= 0.8f; + band[2] *= 3.0f; + band[3] *= 2.8f; + band[4] *= 1.5f; + band[5] *= 1.5f; + + // log scale + for (int i = 0; i < m_fft_items.BANDS; i++) { band[i] = log10f(band[i] + 1e-6f); } + + // --- temporal smoothing (only displayed bands) --- + auto smooth = [](float old, float in) { + constexpr float ATTACK = 0.6f; + constexpr float RELEASE = 0.6f; + return (in > old) ? old + ATTACK * (in - old) : old + RELEASE * (in - old); + }; + + for (int i = 0; i < m_fft_items.BANDS; i++) { m_fft_items.spec_smooth[i] = smooth(m_fft_items.spec_smooth[i], band[i]); } + + // --- map to 0..255 using dB window --- + constexpr float DB_MIN = -50.0f; + constexpr float DB_MAX = 0.0f; + + for (int i = 0; i < m_fft_items.BANDS; i++) { + + float db = m_fft_items.spec_smooth[i] * 20.0f; + + if (db < DB_MIN) db = DB_MIN; + if (db > DB_MAX) db = DB_MAX; + + float norm = (db - DB_MIN) / (DB_MAX - DB_MIN); + + m_fft_items.spectrum[i] = (uint8_t)(norm * 255.0f); + } + // AUDIO_LOG_INFO("{:4}, {:4}, {:4}, {:4}, {:4}, {:4} ", m_fft_items.spectrum[0], m_fft_items.spectrum[1], m_fft_items.spectrum[2], m_fft_items.spectrum[3], m_fft_items.spectrum[4], + // m_fft_items.spectrum[3]); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::Gain(int32_t* sample) { + /* important: these multiplications must all be signed ints, or the result will be invalid */ + int32_t* s32 = (int32_t*)sample; + s32[LEFTCHANNEL] *= m_audio_items.limiter[LEFTCHANNEL]; + s32[RIGHTCHANNEL] *= m_audio_items.limiter[RIGHTCHANNEL]; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::inBufferFilled() { + // current audio input buffer fillsize in bytes + return InBuff.bufferFilled(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::inBufferFree() { + // current audio input buffer free space in bytes + return InBuff.freeSpace(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getInBufferSize() { + // current audio input buffer size in bytes + return InBuff.getBufsize(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::stereo2mono(int32_t* buff, uint16_t validSamples) { + + for (uint16_t i = 0; i < validSamples * 2; i += 2) { + int64_t l = buff[i]; + int64_t r = buff[i + 1]; + int32_t m = (int32_t)((l + r) >> 1); // average, without overflow + buff[i] = m; // Left + buff[i + 1] = m; // Right + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// *** D i g i t a l b i q u a d r a t i c f i l t e r *** +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::IIR_calculateCoefficients() { // Infinite Impulse Response (IIR) filters + + AUDIO_LOG_DEBUG("gain gain_ls_db {}, gain gain_peq_db {}, gain gain_hs_db {}", m_audio_items.gain_ls_db, m_audio_items.gain_peq_db, m_audio_items.gain_hs_db); + + const float FcLS = settings.FREQ_LS_HZ; // Frequency LowShelf(Hz) + const float FcPKEQ = settings.FREQ_PEAK_HZ; // Frequency PeakEQ(Hz) + const float FcHS = settings.FREQ_HS_HZ; // Frequency HighShelf(Hz) + const float QS = settings.QUALITY_SLOPE; // Quality Slope (Shelf) + + float normFreqLS = FcLS / m_i2s_items.sampleRate; // filter cut off frequency + float normFreqPEQ = FcPKEQ / m_i2s_items.sampleRate; // filter center frequency + float normFreqHS = FcHS / m_i2s_items.sampleRate; // filter cut off frequency + + float total_boost_db = fmax(fmax(fmax(0, m_audio_items.gain_ls_db), m_audio_items.gain_peq_db), m_audio_items.gain_hs_db); // dynamic headroom + m_audio_items.pre_gain = powf(10.0, -total_boost_db / 20); + + auto dsps_biquad_gen_peakingEQ_f32 = [&](float* c, float f, int8_t g, const float Q) -> void { + float A = powf(10.0f, g / 40.0f); + float w0 = 2.0f * M_PI * f; + float cw = cosf(w0); + float sw = sinf(w0); + float alpha = sw / (2.0f * Q); + float b0 = 1.0f + alpha * A; + float b1 = -2.0f * cw; + float b2 = 1.0f - alpha * A; + float a0 = 1.0f + alpha / A; + float a1 = -2.0f * cw; + float a2 = 1.0f - alpha / A; + c[0] = b0 / a0; + c[1] = b1 / a0; + c[2] = b2 / a0; + c[3] = a1 / a0; + c[4] = a2 / a0; + }; + + dsps_biquad_gen_lowShelf_f32(m_audio_items.coeffs[LOWSHELF], normFreqLS, m_audio_items.gain_ls_db, QS); + dsps_biquad_gen_peakingEQ_f32(m_audio_items.coeffs[PEAKINGEQ], normFreqPEQ, m_audio_items.gain_peq_db, QS); // my own calc. + dsps_biquad_gen_highShelf_f32(m_audio_items.coeffs[HIFGSHELF], normFreqHS, m_audio_items.gain_hs_db, QS); + + AUDIO_LOG_DEBUG("\n([{}, {}, {}], [1.0, {}, {}]), # LOWSHELF\n([{}, {}, {} ], [1.0, {}, {} ]), # PEAKINGEQ\n([{}, {}, {}], [1.0, {}, {}]), # HIGHSHELF\n", m_audio_items.coeffs[0][0], + m_audio_items.coeffs[0][1], m_audio_items.coeffs[0][2], m_audio_items.coeffs[0][3], m_audio_items.coeffs[0][4], m_audio_items.coeffs[1][0], m_audio_items.coeffs[1][1], + m_audio_items.coeffs[1][2], m_audio_items.coeffs[1][3], m_audio_items.coeffs[1][4], m_audio_items.coeffs[2][0], m_audio_items.coeffs[2][1], m_audio_items.coeffs[2][2], + m_audio_items.coeffs[2][3], m_audio_items.coeffs[2][4]); + AUDIO_LOG_DEBUG("m_audio_items.pre_gain {}", m_audio_items.pre_gain); + memset(m_audio_items.state_biquad, 0, sizeof(m_audio_items.state_biquad)); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::IIR_filter(int32_t* sample) { + + int32_t* s32 = sample; + float s[2]; + s[LEFTCHANNEL] = (float)(s32[LEFTCHANNEL] * m_audio_items.pre_gain); + s[RIGHTCHANNEL] = (float)(s32[RIGHTCHANNEL] * m_audio_items.pre_gain); + dsps_biquad_sf32(s, s, 1, m_audio_items.coeffs[0], m_audio_items.state_biquad[0]); + dsps_biquad_sf32(s, s, 1, m_audio_items.coeffs[1], m_audio_items.state_biquad[1]); + dsps_biquad_sf32(s, s, 1, m_audio_items.coeffs[2], m_audio_items.state_biquad[2]); + s32[LEFTCHANNEL] = (int32_t)std::clamp(s[LEFTCHANNEL], -2147483648.0f, 2147483647.0f); + s32[RIGHTCHANNEL] = (int32_t)std::clamp(s[RIGHTCHANNEL], -2147483648.0f, 2147483647.0f); + return; +} + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +// AAC - T R A N S P O R T S T R E A M +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +bool Audio::ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength) { + + bool log = false; + + const uint8_t TS_PACKET_SIZE = 188; + const uint8_t PAYLOAD_SIZE = 184; + const uint8_t PID_ARRAY_LEN = 4; + + (void)PAYLOAD_SIZE; // suppress [-Wunused-variable] + + if (packet == NULL) { + if (log) AUDIO_LOG_WARN("parseTS reset"); + m_tspp.reset(); + return true; + } + + // -------------------------------------------------------------------------------------------------------- + // 0. Byte SyncByte | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | always bit pattern of 0x47 + //--------------------------------------------------------------------------------------------------------- + // 1. Byte |PUSI|TP| |PID|PID|PID|PID|PID| + //--------------------------------------------------------------------------------------------------------- + // 2. Byte |PID|PID|PID|PID|PID|PID|PID|PID| + //--------------------------------------------------------------------------------------------------------- + // 3. Byte |TSC|TSC|AFC|AFC|CC |CC |CC |CC | + //--------------------------------------------------------------------------------------------------------- + // 4.-187. Byte |Payload data if AFC==01 or 11 | + //--------------------------------------------------------------------------------------------------------- + + // PUSI Payload unit start indicator, set when this packet contains the first byte of a new payload unit. + // The first byte of the payload will indicate where this new payload unit starts. + // TP Transport priority, set when the current packet has a higher priority than other packets with the same PID. + // PID Packet Identifier, describing the payload data. + // TSC Transport scrambling control, '00' = Not scrambled. + // AFC Adaptation field control, 01 – no adaptation field, payload only, 10 – adaptation field only, no payload, + // 11 – adaptation field followed by payload, 00 – RESERVED for future use + // CC Continuity counter, Sequence number of payload packets (0x00 to 0x0F) within each stream (except PID 8191) + + // for(int i = 1; i < 188; i++) {printf("%02X ", packet[i - 1]); if(i && (i % 16 == 0)) printf("\n");} + // printf("\n----------\n"); + + if (packet[0] != 0x47) { + AUDIO_LOG_ERROR("ts SyncByte not found, first bytes are 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X}", packet[0], packet[1], packet[2], packet[3]); + stopSong(); + return false; + } + int PID = (packet[1] & 0x1F) << 8 | (packet[2] & 0xFF); + if (log) AUDIO_LOG_DEBUG("PID: 0x{:04X} ({})", PID, PID); + int PUSI = (packet[1] & 0x40) >> 6; + if (log) AUDIO_LOG_DEBUG("Payload Unit Start Indicator: {}", PUSI); + int AFC = (packet[3] & 0x30) >> 4; + if (log) AUDIO_LOG_DEBUG("Adaption Field Control: {}", AFC); + + int AFL = -1; + if ((AFC & 0b10) == 0b10) { // AFC '11' Adaptation Field followed + AFL = packet[4] & 0xFF; // Adaptation Field Length + if (log) AUDIO_LOG_DEBUG("Adaptation Field Length: {}", AFL); + } + int PLS = PUSI ? 5 : 4; // PayLoadStart, Payload Unit Start Indicator + if (AFL > 0) PLS += AFL + 1; // skip adaption field + + if (AFC == 2) { // The TS package contains only an adaptation Field and no user data. + *packetStart = AFL + 1; + *packetLength = 0; + return true; + } + + if (PID == 0) { + // Program Association Table (PAT) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (log) AUDIO_LOG_DEBUG("PAT"); + m_tspp.pidNumber = 0; + m_tspp.pidOfAAC = 0; + + int startOfProgramNums = 8; + int lengthOfPATValue = 4; + int sectionLength = ((packet[PLS + 1] & 0x0F) << 8) | (packet[PLS + 2] & 0xFF); + if (log) AUDIO_LOG_DEBUG("Section Length: {}", sectionLength); + int program_number, program_map_PID; + int indexOfPids = 0; + (void)program_number; // [-Wunused-but-set-variable] + for (int i = startOfProgramNums; i <= sectionLength; i += lengthOfPATValue) { + program_number = ((packet[PLS + i] & 0xFF) << 8) | (packet[PLS + i + 1] & 0xFF); + program_map_PID = ((packet[PLS + i + 2] & 0x1F) << 8) | (packet[PLS + i + 3] & 0xFF); + if (log) AUDIO_LOG_DEBUG("Program Num: 0x{:04X}({}) PMT PID: 0x{:04X}({})", program_number, program_number, program_map_PID, program_map_PID); + m_tspp.pids[indexOfPids++] = program_map_PID; + } + m_tspp.pidNumber = indexOfPids; + *packetStart = 0; + *packetLength = 0; + return true; + } else if (PID == m_tspp.pidOfAAC) { + if (log) AUDIO_LOG_DEBUG("AAC"); + uint8_t posOfPacketStart = 4; + if (AFL >= 0) { + posOfPacketStart = 5 + AFL; + if (log) AUDIO_LOG_DEBUG("posOfPacketStart: {}", posOfPacketStart); + } + // Packetized Elementary Stream (PES) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (log) AUDIO_LOG_DEBUG("PES_DataLength {}", m_tspp.PES_DataLength); + if (m_tspp.PES_DataLength > 0) { + *packetStart = posOfPacketStart + m_tspp.fillData; + *packetLength = TS_PACKET_SIZE - posOfPacketStart - m_tspp.fillData; + if (log) AUDIO_LOG_DEBUG("packetlength {}", *packetLength); + m_tspp.fillData = 0; + m_tspp.PES_DataLength -= (*packetLength); + return true; + } else { + int firstByte = packet[posOfPacketStart] & 0xFF; + int secondByte = packet[posOfPacketStart + 1] & 0xFF; + int thirdByte = packet[posOfPacketStart + 2] & 0xFF; + if (log) AUDIO_LOG_DEBUG("First 3 bytes: 0x{:02X}, 0x{:02X}, 0x{:02X}", firstByte, secondByte, thirdByte); + if (firstByte == 0x00 && secondByte == 0x00 && thirdByte == 0x01) { // Packet start code prefix + // -------------------------------------------------------------------------------------------------------- + // posOfPacketStart + 0...2 0x00, 0x00, 0x01 PES-Startcode + //--------------------------------------------------------------------------------------------------------- + // posOfPacketStart + 3 0xE0 (Video) od 0xC0 (Audio) StreamID + //--------------------------------------------------------------------------------------------------------- + // posOfPacketStart + 4...5 0xLL, 0xLL PES Packet length + //--------------------------------------------------------------------------------------------------------- + // posOfPacketStart + 6...7 PTS/DTS Flags + //--------------------------------------------------------------------------------------------------------- + // posOfPacketStart + 8 0xXX header length + //--------------------------------------------------------------------------------------------------------- + + uint8_t StreamID = packet[posOfPacketStart + 3] & 0xFF; + if (StreamID >= 0xC0 && StreamID <= 0xDF) { ; } // okay ist audio stream + if (StreamID >= 0xE0 && StreamID <= 0xEF) { + AUDIO_LOG_ERROR("video stream!"); + return false; + } + int PES_PacketLength = ((packet[posOfPacketStart + 4] & 0xFF) << 8) + (packet[posOfPacketStart + 5] & 0xFF); + if (log) AUDIO_LOG_DEBUG("PES PacketLength: {}", PES_PacketLength); + bool PTS_flag = false; + bool DTS_flag = false; + int flag_byte1 = packet[posOfPacketStart + 6] & 0xFF; + int flag_byte2 = packet[posOfPacketStart + 7] & 0xFF; + (void)flag_byte2; // unused yet + if (flag_byte1 & 0b10000000) PTS_flag = true; + if (flag_byte1 & 0b00000100) DTS_flag = true; + if (log && PTS_flag) AUDIO_LOG_DEBUG("PTS_flag is set"); + if (log && DTS_flag) AUDIO_LOG_DEBUG("DTS_flag is set"); + uint8_t PES_HeaderDataLength = packet[posOfPacketStart + 8] & 0xFF; + if (log) AUDIO_LOG_DEBUG("PES_headerDataLength {}", PES_HeaderDataLength); + + m_tspp.PES_DataLength = PES_PacketLength; + int startOfData = PES_HeaderDataLength + 9; + if (posOfPacketStart + startOfData >= 188) { // only fillers in packet + if (log) AUDIO_LOG_DEBUG("posOfPacketStart + startOfData {}", posOfPacketStart + startOfData); + *packetStart = 0; + *packetLength = 0; + m_tspp.PES_DataLength -= (PES_HeaderDataLength + 3); + m_tspp.fillData = (posOfPacketStart + startOfData) - 188; + if (log) AUDIO_LOG_DEBUG("fillData {}", m_tspp.fillData); + return true; + } + if (log) AUDIO_LOG_DEBUG("First AAC data byte: {:02X}", packet[posOfPacketStart + startOfData]); + if (log) AUDIO_LOG_DEBUG("Second AAC data byte: {:02X}", packet[posOfPacketStart + startOfData + 1]); + *packetStart = posOfPacketStart + startOfData; + *packetLength = TS_PACKET_SIZE - posOfPacketStart - startOfData; + m_tspp.PES_DataLength -= (*packetLength); + m_tspp.PES_DataLength -= (PES_HeaderDataLength + 3); + return true; + } + if (firstByte == 0 && secondByte == 0 && thirdByte == 0) { + // PES packet startcode prefix is 0x000000 + // skip such packets + return true; + } + } + *packetStart = 0; + *packetLength = 0; + AUDIO_LOG_ERROR("PES not found"); + return false; + } else if (m_tspp.pidNumber) { + // Program Map Table (PMT) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + for (int i = 0; i < m_tspp.pidNumber; i++) { + if (PID == m_tspp.pids[i]) { + if (log) AUDIO_LOG_DEBUG("PMT"); + int staticLengthOfPMT = 12; + int sectionLength = ((packet[PLS + 1] & 0x0F) << 8) | (packet[PLS + 2] & 0xFF); + if (log) AUDIO_LOG_DEBUG("Section Length: {}", sectionLength); + int programInfoLength = ((packet[PLS + 10] & 0x0F) << 8) | (packet[PLS + 11] & 0xFF); + if (log) AUDIO_LOG_DEBUG("Program Info Length: {}", programInfoLength); + int cursor = staticLengthOfPMT + programInfoLength; + while (cursor < sectionLength - 1) { + int streamType = packet[PLS + cursor] & 0xFF; + int elementaryPID = ((packet[PLS + cursor + 1] & 0x1F) << 8) | (packet[PLS + cursor + 2] & 0xFF); + if (log) AUDIO_LOG_DEBUG("Stream Type: 0x{:02X} Elementary PID: 0x{:04X}", streamType, elementaryPID); + + if (streamType == 0x0F || streamType == 0x11 || streamType == 0x04) { + if (log) AUDIO_LOG_DEBUG("AAC PID discover"); + m_tspp.pidOfAAC = elementaryPID; + } + int esInfoLength = ((packet[PLS + cursor + 3] & 0x0F) << 8) | (packet[PLS + cursor + 4] & 0xFF); + if (log) AUDIO_LOG_DEBUG("ES Info Length: 0x{:04X}", esInfoLength); + cursor += 5 + esInfoLength; + } + } + } + *packetStart = 0; + *packetLength = 0; + return true; + } + // PES received before PAT and PMT seen + *packetStart = 0; + *packetLength = 0; + if (PID > 0) { return true; } + return false; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +// W E B S T R E A M - H E L P F U N C T I O N S +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +bool Audio::readMetadata(uint32_t maxBytes, uint16_t* readedBytes, bool first) { + *readedBytes = 0; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (first) { + m_rmet.pos_ml = 0; // determines the current position in metaline + m_rmet.metaDataSize = 0; + m_rmet.res = 0; + m_metadataBuff.clear(); + return true; + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (!maxBytes) return false; // guard + if (!m_rmet.metaDataSize) { + int b = audioFileRead(); // First byte of metadata? + if (b < 0) { + AUDIO_LOG_WARN("client->read() failed ({})", b); + return false; + } + m_rmet.metaDataSize = b * 16; // New count for metadata including length byte, max 4096 + m_rmet.pos_ml = 0; + m_metadataBuff[m_rmet.pos_ml] = 0; // Prepare for new line + *readedBytes = 1; + maxBytes -= 1; + } + if (!m_rmet.metaDataSize) { return *readedBytes; } // metalen is 0 + + int32_t a = audioFileRead((uint8_t*)&m_metadataBuff[m_rmet.pos_ml], min(m_rmet.metaDataSize - m_rmet.pos_ml, maxBytes)); + if (a > 0) { + m_rmet.res += a; + *readedBytes += a; + m_rmet.pos_ml += a; + } + if (m_rmet.pos_ml == m_rmet.metaDataSize) { + m_metadataBuff[m_rmet.pos_ml] = '\0'; + // m_metadataBuff.hex_dump(m_rmet.metaDataSize); + if (m_metadataBuff.strlen() > 0) { // Any info present? + // metaline contains artist and song name. For example: + // "StreamTitle='Don McLean - American Pie';StreamUrl='';" + // Sometimes it is just other info like: + // "StreamTitle='60s 03 05 Magic60s';StreamUrl='';" + // Isolate the StreamTitle, remove leading and trailing quotes if present. + latinToUTF8(m_metadataBuff); // convert to UTF-8 if necessary + int pos = m_metadataBuff.index_of_icase("song_spot", 0); // remove some irrelevant infos + if (pos > 3) { // e.g. song_spot="T" MediaBaseId="0" itunesTrackId="0" + m_metadataBuff[pos] = 0; + } + showstreamtitle(m_metadataBuff.get()); // Show artist and title if present in metadata + } + m_metacount = m_metaint; + m_rmet.metaDataSize = 0; + m_rmet.pos_ml = 0; + m_metadataBuff[m_rmet.pos_ml] = 0; // Prepare for new line + } else { + return false; // not enough data, next round + } + m_metadataBuff.clear(); + return true; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int32_t Audio::getChunkSize(uint16_t* readedBytes, bool first) { + + // \r\n + // \r\n + // hex_str; + int16_t idx1, idx2, idx3; + int32_t chunkSize = -1; + + if (first) { + m_gchs.reset(); + return 0; + } + if (!m_gchs.chunkLine.valid()) m_gchs.chunkLine.calloc(CHUNK_LINE_LENGTH, "m_gchs1.chunkLine"); + + auto hex_to_int = [&](ps_ptr hexstr) -> int32_t { + if (!hexstr.valid()) return -1; + for (int i = 0; i < hexstr.strlen(); i++) { + if (!isxdigit(hexstr[i])) return -1; + } + return hexstr.to_int32(16); + }; + + *readedBytes = 0; + + while (true) { + int16_t b = audioFileRead(); + if (b == -1) { // need mor data + chunkSize = -1; + break; + } + + m_gchs.chunkLine[m_gchs.position] = b; + *readedBytes += 1; + m_gchs.position += 1; + + if (m_gchs.chunkLine == "\r\n") { // skip CRLF + m_gchs.chunkLine.clear(); + m_gchs.position = 0; + AUDIO_LOG_DEBUG("skip CRLF"); + } + + if (m_gchs.position == CHUNK_LINE_LENGTH) { + AUDIO_LOG_ERROR("ChunkLine is too long"); + m_gchs.chunkLine.hex_dump(CHUNK_LINE_LENGTH); + goto error; + } + if (m_gchs.chunkLine.ends_with("\r\n") && m_gchs.chunkSize == -1) { + idx1 = m_gchs.chunkLine.index_of(";"); + if (idx1 > 0) { // extension follows, e.g. "AF4;test=123\r\n" + hex_str = m_gchs.chunkLine.substr(0, idx1); // "AF4;test=123\r\n" -> "AF4" + ps_ptr extension = m_gchs.chunkLine.substr(idx1 + 1); // "AF4;test=123\r\n" -> "test=123\r\n" + extension = extension.substr(0, extension.strlen() - 2); // "test=123\r\n" -> "test=123" + if (extension != m_gchs.extension) { + m_gchs.extension = extension; + AUDIO_LOG_INFO("extension {}", m_gchs.extension); + } + } else { + hex_str = m_gchs.chunkLine.substr(0, m_gchs.chunkLine.strlen() - 2); // "AF4\r\n" -> "AF4" + } + m_gchs.chunkSize = hex_to_int(hex_str); // "AF4" -> 2804 + if (m_gchs.chunkSize == -1) { + AUDIO_LOG_ERROR("Invalid char in hex_str"); + hex_str.hex_dump(20); + goto error; + } + } + if (m_gchs.chunkSize > 0) { + chunkSize = m_gchs.chunkSize; + break; + } else { // m_gchs1.chunkSize is 0 + if (m_gchs.chunkLine.ends_with("\r\n\r\n")) { + idx1 = m_gchs.chunkLine.index_of("\r\n"); + idx2 = m_gchs.chunkLine.index_of("\r\n\r"); + if (idx1 == idx2) { + // e.g. "000\r\n\r\n" or "0\r\n\r\n" or "0;end=true\r\n\r\n" + } else { // can have trailer "0\r\nContent-MD5: abcdef\r\nServer: xyz\r\n\r\n" + m_gchs.trailer = m_gchs.chunkLine.substr(idx1 + 1, idx1 - idx2); + AUDIO_LOG_INFO("trailer {}", m_gchs.trailer); + } + chunkSize = 0; + break; + } + } + } + + AUDIO_LOG_DEBUG("chunkSize {}", chunkSize); + if (chunkSize == -1) { + if (m_gchs.timeStamp + 3000 < millis()) { + AUDIO_LOG_WARN("timeout while get next chunkSize"); + m_gchs.timeStamp = millis(); + } + } + if (chunkSize >= 0) { + m_gchs.chunkSize = -1; + m_gchs.position = 0; + m_gchs.chunkLine.clear(); + m_gchs.timeStamp = millis(); + } + return chunkSize; + +error: + m_gchs.reset(); + return -100; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +bool Audio::readID3V1Tag() { + if (m_codec != CODEC_MP3) return false; + ps_ptr chBuff; + chBuff.alloc(256, "chBuff"); + + const uint8_t* p = InBuff.getReadPtr(); + + // Lambda for simplification + auto readID3Field = [&](ps_ptr& field, const uint8_t* src, size_t len, const char* label = nullptr) { + field.alloc(len + 1, "field"); + memcpy(field.get(), src, len); + field[len] = '\0'; + latinToUTF8(field); + if (field.strlen() > 0 && label) { + field.insert(label, 0); + info(*this, evt_id3data, "{}", field.get()); + } + }; + + if (InBuff.bufferFilled() == 128 && startsWith((const char*)p, "TAG")) { + ps_ptr title, artist, album, year, comment; + + readID3Field(title, p + 3, 30, "Title: "); + readID3Field(artist, p + 33, 30, "Artist: "); + readID3Field(album, p + 63, 30, "Album: "); + readID3Field(year, p + 93, 4, "Year: "); + readID3Field(comment, p + 97, 30, "Comment: "); + + uint8_t zeroByte = p[125]; + uint8_t track = p[126]; + uint8_t genre8 = p[127]; + + info(*this, evt_info, zeroByte ? "ID3 version: 1" : "ID3 Version 1.1"); + + if (zeroByte == 0) { + sprintf(chBuff.get(), "Track Number: %d", track); + info(*this, evt_id3data, "{}", chBuff.get()); + } + + if (genre8 < 192) { + sprintf(chBuff.get(), "Genre: %d", genre8); + info(*this, evt_id3data, "{}", chBuff.get()); + } + + return true; + } + + if (InBuff.bufferFilled() == 227 && startsWith((const char*)p, "TAG+")) { // "TAG+" "can exist as an extension, does not overwrite" TAG" + info(*this, evt_info, "ID3 version: 1 - Enhanced TAG"); + + ps_ptr title, artist, album, genre; + + readID3Field(title, p + 4, 60, "Title: "); + readID3Field(artist, p + 64, 60, "Artist: "); + readID3Field(album, p + 124, 60, "Album: "); + readID3Field(genre, p + 185, 30, "Genre: "); + + // optional expansion: speed, start-time, end-time + return true; + } + + return false; + // [1] https://en.wikipedia.org/wiki/List_of_ID3v1_Genres + // [2] https://en.wikipedia.org/wiki/ID3#ID3v1_and_ID3v1.1[5] +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int32_t Audio::newInBuffStart(int32_t resumeFilePos) { + + if ((m_controlCounter != 100) || (m_resumeFilePos >= (int32_t)m_audioDataStart + m_audioDataSize) || ((m_codec == CODEC_M4A) && !m_stsz_position)) { + AUDIO_LOG_WARN("timeOffset not possible"); + return 0; + } + + // keep resumeFilePos within the audio data + if (resumeFilePos < (int32_t)m_audioDataStart) resumeFilePos = m_audioDataStart; + + uint32_t buffFillValue = std::min(m_audioDataSize - resumeFilePos, UINT16_MAX); + + AUDIO_LOG_DEBUG("new InBuff start at m_resumeFilePos {}, m_audioDataStart {}", m_resumeFilePos, m_audioDataStart); + + // --- enter critical area ------------------------------------------ + xSemaphoreTake(mutex_audioTaskIsDecoding, 1 * configTICK_RATE_HZ); + m_f_lockInBuffer = true; + + // ------- prepare InBuff ------ + m_f_allDataReceived = false; + audioFileSeek(resumeFilePos); + InBuff.reset(); + int32_t bw = audioFileRead(InBuff.getWritePtr(), buffFillValue, 3000); + if (bw == buffFillValue) + InBuff.bytesWritten(bw); + else + return -1; + + int32_t offset = 0; + int32_t newFilePos = resumeFilePos; + + // --------------------------------------------------------------------------- + // codec specific handling + // --------------------------------------------------------------------------- + + auto fail = [&]() { + AUDIO_LOG_ERROR("can't set newFilePos"); + InBuff.bytesWasRead(0); + m_f_lockInBuffer = false; + xSemaphoreGive(mutex_audioTaskIsDecoding); + stopSong(); + return -1; + }; + + switch (m_codec) { + case CODEC_M4A: + offset = m4a_correctResumeFilePos(); + if (offset < 0) return fail(); + break; + + case CODEC_WAV: + // WAV have 4-Byte-Boundaries + offset = wav_correctResumeFilePos(); + if (offset < 0) return fail(); + break; + + case CODEC_MP3: + offset = mp3_correctResumeFilePos(); + if (offset < 0) return fail(); + break; + + case CODEC_FLAC: + offset = flac_correctResumeFilePos(); + if (offset < 0) return fail(); + break; + + case CODEC_VORBIS: + offset = ogg_correctResumeFilePos(); // next OggS + if (offset < 0) return fail(); + break; + + case CODEC_OPUS: + offset = ogg_correctResumeFilePos(); // next OggS + if (offset < 0) return fail(); + break; + + default: return fail(); + } + + AUDIO_LOG_DEBUG("offset {}, readSpace {}", offset, InBuff.readSpace()); + newFilePos += offset; + m_decoder->clear(); + + // --- leaf critical area ---------------------------------------------- + InBuff.bytesWasRead(offset); + m_f_lockInBuffer = false; + xSemaphoreGive(mutex_audioTaskIsDecoding); + + return newFilePos; +} + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +boolean Audio::streamDetection(uint32_t bytesAvail) { + + if (InBuff.bufferFilled() < InBuff.getMaxBlockSize()) { + if (m_sdet.cnt_slow == 0) m_sdet.tmr_slow = millis(); + m_sdet.cnt_slow++; + } else { + m_sdet.cnt_slow = 0; + m_sdet.cnt_lost = 0; + } + + // if within one second the content of the audio buffer falls below the size of an audio frame 100 times, + // issue a message + if (m_sdet.cnt_slow && m_sdet.tmr_slow + 2000 < millis()) { + m_sdet.tmr_slow = millis(); + info(*this, evt_info, "slow stream"); + m_sdet.cnt_slow = 0; + m_sdet.cnt_lost++; + } + + if (bytesAvail) { m_sdet.cnt_lost = 0; } + if (InBuff.bufferFilled() > InBuff.getMaxBlockSize() * 2) return true; // enough data available to play + + // if no audio data is received within 10 seconds, a new connection attempt is started. + if (m_sdet.cnt_lost == 5) { + info(*this, evt_info, "Stream lost"); + connecttohost(m_lastHost.get()); + m_sdet.cnt_slow = 0; + m_sdet.cnt_lost = 0; + return false; + } + return false; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +uint32_t Audio::m4a_correctResumeFilePos() { + // In order to jump within an m4a file, the exact beginning of an aac block must be found. Since m4a cannot be + // streamed, i.e. there is no syncword, an imprecise jump can lead to a crash. + + if (!m_stsz_position) return m_audioDataStart; // guard + + typedef union { + uint8_t u8[4]; + uint32_t u32; + } tu; + tu uu = {}; + + uint32_t i = 0, pos = m_audioDataStart; + uint32_t filePtr = m_audioFilePosition; + bool found = false; + audioFileSeek(m_stsz_position, m_stsz_numEntries * 4); + + auto read_next = [&]() -> int { + int r = 0; + int cnt = 0; + while (true) { + r = audioFileRead(); + if (r >= 0) break; + vTaskDelay(10); + cnt++; + if (cnt > 300) { + AUDIO_LOG_ERROR("timeout"); + break; + } + } + return r; + }; + + while (i < m_stsz_numEntries) { + i++; + uu.u8[3] = read_next(); + uu.u8[2] = read_next(); + uu.u8[1] = read_next(); + uu.u8[0] = read_next(); + + pos += uu.u32; + if (pos >= m_resumeFilePos) { + found = true; + break; + } + } + if (!found) return -1; // not found + + audioFileSeek(filePtr); // restore file pointer + return pos - m_resumeFilePos; // return the number of bytes to jump +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +uint32_t Audio::ogg_correctResumeFilePos() { + // The starting point is the next OggS magic word + if (InBuff.bufferFilled() < 0xFFFF) return 0; + vTaskDelay(1); + // // AUDIO_LOG_INFO("in_resumeFilePos {}", resumeFilePos); + + auto find_sync_word = [&](uint8_t* pos, uint32_t av) -> int { + int steps = 0; + while (av--) { + if (pos[steps] == 'O') { + if (pos[steps + 1] == 'g') { + if (pos[steps + 2] == 'g') { + if (pos[steps + 3] == 'S') { // Check for the second part of magic word + return steps; // Magic word found, return the number of steps + } + } + } + } + steps++; + } + return -1; // Return -1 if OggS magic word is not found + }; + + uint8_t* readPtr = InBuff.getReadPtr(); + size_t av = InBuff.readSpace(); + int32_t steps = 0; + + if (av < InBuff.getMaxBlockSize()) return -1; // guard + + steps = find_sync_word(readPtr, av); + if (steps == -1) return -1; + return steps; // Return the number of steps to the sync word +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int32_t Audio::flac_correctResumeFilePos() { + uint8_t* p = InBuff.getReadPtr(); + size_t av = InBuff.readSpace(); + + if (av < 32) return -1; // sicher gehen + + auto utf8_length = [&](uint8_t first) -> int { + if ((first & 0x80) == 0x00) return 1; // 0xxxxxxx + if ((first & 0xE0) == 0xC0) return 2; // 110xxxxx + if ((first & 0xF0) == 0xE0) return 3; // 1110xxxx + if ((first & 0xF8) == 0xF0) return 4; // 11110xxx + if ((first & 0xFC) == 0xF8) return 5; // 111110xx + if ((first & 0xFE) == 0xFC) return 6; // 1111110x + if (first == 0xFE) return 7; // 11111110 + return -1; // invalid UTF-8 + }; + + // FLAC CRC-8 + auto crc8_update = [](uint8_t crc, uint8_t data) -> uint8_t { + crc ^= data; + for (int i = 0; i < 8; ++i) { + if (crc & 0x80) + crc = (crc << 1) ^ 0x07; + else + crc <<= 1; + } + return crc; + }; + + for (size_t i = 0; i + 14 < av; ++i) { + // 14-Bit-Sync: 0xFFF8 oder 0xFFF9 (last 2 Bits variable!) + uint8_t b0 = p[i + 0]; // 11111111 sync + uint8_t b1 = p[i + 1]; // 111111rb sync r-reserved b-blocking strategy + if (b0 != 0xFF) continue; + if ((b1 & 0xFE) != 0xF8) continue; + + uint8_t b2 = p[i + 2]; // bbbbssss b-blocksize s samplerate + uint8_t blocksize_code = (b2 & 0xF0) >> 4; + uint8_t samplerate_code = (b2 & 0x0F); + + uint8_t b3 = p[i + 3]; // ccccsssr c-channel assignment, s sample size, r reserved + uint8_t channel_assign = (b3 & 0xF0) >> 4; + uint8_t bps_code = (b3 & 0x0E) >> 1; // bits per sample + uint8_t reserved_bit = b3 & 0x01; // has to be 0 + + if (reserved_bit != 0) continue; + if (channel_assign >= 11) continue; // 11-15 reserved + if (bps_code == 0x07) continue; // reserved + + size_t pos = i + 4; // first byte of UTF8 + int len = utf8_length(p[pos]); + if (len < 1 || pos + len >= av) continue; // invalid/incomplete header + + size_t crc_end = pos + len; // this is where the CRC byte lives + + AUDIO_LOG_DEBUG("samplerate_code {}, bps_code {} channel_assign {}, reserved_bit {}", samplerate_code, bps_code, channel_assign, reserved_bit); + AUDIO_LOG_DEBUG("b0 {}, b1 {}, b2 {}, b3 {}", b0, b1, b2, b3); + + uint8_t crc = 0; + for (size_t k = i; k < crc_end; ++k) crc = crc8_update(crc, p[k]); + + if (crc != p[crc_end]) continue; + + // === When we get here: 99.9999% certain it’s a real frame === + AUDIO_LOG_DEBUG(">>> REAL FLAC-FRAME found at offset {}", i); + return (int32_t)i; + } + + return -1; // No frame found in the first 64 KB +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int32_t Audio::mp3_correctResumeFilePos() { + + int32_t steps = 0; + int32_t sumSteps = 0; + uint8_t* pos = InBuff.getReadPtr(); + size_t av = InBuff.readSpace(); + + if (av < InBuff.getMaxBlockSize()) return -1; // guard + + while (true) { + steps = m_decoder->findSyncWord(pos, av); + if (steps == 0) break; + if (steps == -1) return -1; + pos += steps; + sumSteps += steps; + } + // AUDIO_LOG_INFO("found sync word at {} sync1 = 0x{:02X}, sync2 = 0x{;02X}", readPtr - pos, *readPtr, *(readPtr + 1)); + return sumSteps; // return the position of the first byte of the frame +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +int32_t Audio::wav_correctResumeFilePos() { + int32_t pos = m_resumeFilePos; + uint8_t offset = 0; + ; + // WAV must be on 4 byte limit + while (pos % 4 != 0) { + offset++; + pos++; + } + if (pos >= m_audioDataStart + m_audioDataSize) return 0; + return offset; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- +uint8_t Audio::determineCodec(uint8_t presumed_codec) { + if (presumed_codec == CODEC_OGG) { + // if we have contentType == application/ogg; codec cn be OPUS, FLAC or VORBIS + // let's have a look, what it is + uint8_t res = CODEC_NONE; + int idx = -1; + idx = specialIndexOf(InBuff.getReadPtr(), "OggS", 127); + AUDIO_LOG_DEBUG("idx {}", idx); + if (idx == 0) { + idx = specialIndexOf(InBuff.getReadPtr(), "OpusHead", 127); + if (idx >= 28) { res = CODEC_OPUS; } + idx = specialIndexOf(InBuff.getReadPtr(), "fLaC", 127); + if (idx >= 28) { res = CODEC_FLAC; } + idx = specialIndexOf(InBuff.getReadPtr(), "vorbis", 127); + if (idx >= 28) { res = CODEC_VORBIS; } + + m_lastGranulePosition = getLastGranulePosition(res); // VORBIS or OPUS only + audioFileSeek(0); // if isFile? + AUDIO_LOG_DEBUG("lastGranulePosition {}", m_lastGranulePosition); + } + return res; + } + + if (m_playlistFormat == FORMAT_M3U8) return presumed_codec; // HLS or TS, nothing todo + if (m_streamType != ST_WEBSTREAM) return presumed_codec; // is webfile, nothing todo + + if (presumed_codec == CODEC_AAC || presumed_codec == CODEC_MP3) { // only webstream, is AAC or MP3? + uint8_t* data = InBuff.getReadPtr(); + uint8_t b0 = data[0]; + uint8_t b1 = data[1]; + int8_t mimeType = CODEC_NONE; + if (b0 == 0xFF && (b1 & 0xF6) == 0xF0) { // AAC ADTS + mimeType = CODEC_AAC; + } + + else if (b0 == 0x56 && (b1 & 0xE0) == 0xE0) { // AAC LATM + mimeType = CODEC_AAC; + } + + else if (b0 == 0xFF && (b1 & 0xE0) == 0xE0) { // MP3 + uint8_t layer = (b1 >> 1) & 0x03; + if (layer != 0) { // layer must not be "reserved". + mimeType = CODEC_MP3; + } + } + + if (presumed_codec == mimeType) return presumed_codec; + if (mimeType == CODEC_NONE) return presumed_codec; // is not AAC or MP3 + info(*this, evt_info, "contentType is {}, but {} found", codecname[presumed_codec], codecname[mimeType]); + return mimeType; + } + + return presumed_codec; // all other (native FLAC or WAV) +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* Audio::getVersion() { + trim(audioI2SVers); + return audioI2SVers + 8; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::get_info() { + if (m_info_queue.e.size() == 0) return false; + msg_t i = {0}; + while (m_info_queue.e.size()) { + ps_ptr msg = m_info_queue.msg.back(); + i.msg = msg.c_get(); + i.e = (event_t)m_info_queue.e.back(); + ps_ptr evtstr = m_info_queue.s.back(); + i.s = evtstr.c_get(); + i.arg1 = m_info_queue.arg1.back(); + i.arg2 = m_info_queue.arg2.back(); + i.i2s_num = m_i2s_items.i2s_num; + i.vec = m_info_queue.vec.back(); + + m_info_queue.msg.pop_back(); + m_info_queue.e.pop_back(); + m_info_queue.s.pop_back(); + m_info_queue.arg1.pop_back(); + m_info_queue.arg2.pop_back(); + m_info_queue.vec.pop_back(); + audio_info_callback(i); + } + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::trim(char* str) { + char* start = str; // keep the original pointer + char* end; + while (isspace((unsigned char)*start)) start++; // find the first non-space character + + if (*start == 0) { // all characters were spaces + str[0] = '\0'; // return a empty string + return; + } + + end = start + strlen(start) - 1; // find the end of the string + + while (end > start && isspace((unsigned char)*end)) end--; + end[1] = '\0'; // Null-terminate the string after the last non-space character + + // Move the trimmed string to the beginning of the memory area + memmove(str, start, strlen(start) + 1); // +1 for '\0' +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::startsWith(const char* base, const char* str) { + // fb + char c; + while ((c = *str++) != '\0') + if (c != *base++) return false; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::indexOf(const char* base, const char* str, int startIndex) { + // fbi + const char* p = base; + for (; startIndex > 0; startIndex--) + if (*p++ == '\0') return -1; + char* pos = strstr(p, str); + if (pos == nullptr) return -1; + return pos - base; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::indexOf(const char* base, char ch, int startIndex) { + // fb + const char* p = base; + for (; startIndex > 0; startIndex--) + if (*p++ == '\0') return -1; + char* pos = strchr(p, ch); + if (pos == nullptr) return -1; + return pos - base; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int Audio::specialIndexOf(uint8_t* base, const char* str, int baselen, bool exact) { + int result = 0; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int j = 0; j < strlen(str) + exact; j++) { + if (*(base + i + j) != *(str + j)) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t Audio::min3(int32_t a, int32_t b, int32_t c) { + uint32_t min_val = a; + if (b < min_val) min_val = b; + if (c < min_val) min_val = c; + return min_val; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// some other functions +uint64_t Audio::bigEndian(uint8_t* base, uint8_t numBytes, uint8_t shiftLeft) { + uint64_t result = 0; // Use uint64_t for greater caching + if (numBytes < 1 || numBytes > 8) return 0; + for (int i = 0; i < numBytes; i++) { + result |= (uint64_t)(*(base + i)) << ((numBytes - i - 1) * shiftLeft); // Make sure the calculation is done correctly + } + if (result > SIZE_MAX) { + log_e("range overflow"); + return 0; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool Audio::b64encode(const char* source, uint16_t sourceLength, char* dest) { + size_t size = base64_encode_expected_len(sourceLength) + 1; + char* buffer = (char*)malloc(size); + if (buffer) { + base64_encodestate _state; + base64_init_encodestate(&_state); + int len = base64_encode_block(&source[0], sourceLength, &buffer[0], &_state); + base64_encode_blockend((buffer + len), &_state); + memcpy(dest, buffer, strlen(buffer)); + dest[strlen(buffer)] = '\0'; + free(buffer); + return true; + } + return false; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::vector_clear_and_shrink(std::vector>& vec) { + for (int i = 0; i < vec.size(); i++) vec[i].reset(); + vec.clear(); // unique_ptr takes care of free() + vec.shrink_to_fit(); // put back memory +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void Audio::deque_clear_and_shrink(std::deque>& deq) { + for (int i = 0; i < deq.size(); i++) deq[i].reset(); + deq.clear(); // unique_ptr takes care of free() + deq.shrink_to_fit(); // put back memory +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::simpleHash(const char* str) { + if (str == NULL) return 0; + uint32_t hash = 0; + for (int i = 0; i < strlen(str); i++) { + if (str[i] < 32) continue; // ignore control sign + hash += (str[i] - 31) * i * 32; + } + return hash; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +ps_ptr Audio::urlencode(const char* str, bool spacesOnly) { + if (!str) { return {}; } // Enter is zero + + // Reserve memory for the result (3x the length of the input string, worst-case) + size_t inputLength = strlen(str); + size_t bufferSize = inputLength * 3 + 1; // Worst-case-Szenario + ps_ptr encoded; + encoded.alloc(bufferSize, "encoded"); + if (!encoded.valid()) { return {}; } // memory allocation failed + + const char* p_input = str; // Copy of the input pointer + char* p_encoded = encoded.get(); // pointer of the output buffer + size_t remainingSpace = bufferSize; // remaining space in the output buffer + + while (*p_input) { + if (isalnum((unsigned char)*p_input)) { + // adopt alphanumeric characters directly + if (remainingSpace > 1) { + *p_encoded++ = *p_input; + remainingSpace--; + } else { + return {}; // security check failed + } + } else if (spacesOnly && *p_input != 0x20) { + // Nur Leerzeichen nicht kodieren + if (remainingSpace > 1) { + *p_encoded++ = *p_input; + remainingSpace--; + } else { + return {}; // security check failed + } + } else { + // encode unsafe characters as '%XX' + if (remainingSpace > 3) { + int written = snprintf(p_encoded, remainingSpace, "%%%02X", (unsigned char)*p_input); + if (written < 0 || written >= (int)remainingSpace) { + return {}; // error writing to buffer + } + p_encoded += written; + remainingSpace -= written; + } else { + return {}; // security check failed + } + } + p_input++; + } + + // Null-terminieren + if (remainingSpace > 0) { + *p_encoded = '\0'; + } else { + return {}; // security check failed + } + encoded.shrink_to_fit(); + return encoded; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// separate task for decoding and outputting the data. 'playAudioData()' is started periodically and fetches the data from the InBuffer. This ensures +// that the I2S-DMA is always sufficiently filled, even if the Arduino 'loop' is stuck. +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void Audio::setAudioTaskCore(uint8_t coreID) { // Recommendation:If the ARDUINO RUNNING CORE is 1, the audio task should be core 0 or vice versa + if (coreID > 1) return; + stopAudioTask(); + xSemaphoreTake(mutex_audioTask, 0.3 * configTICK_RATE_HZ); + m_audioTaskCoreId = coreID; + xSemaphoreGive(mutex_audioTask); + startAudioTask(); +} + +void Audio::startAudioTask() { + + if (m_f_audioTaskIsRunning) { + AUDIO_LOG_DEBUG("audio task is already running."); + return; + } + AUDIO_LOG_INFO("start audio task."); + m_f_audioTaskIsRunning = true; + + m_audioTaskHandle = xTaskCreateStaticPinnedToCore(&Audio::audioTaskWrapper, /* Function to implement the task */ + "PeriodicTask", /* Name of the task */ + AUDIO_STACK_SIZE, /* Stack size in words */ + this, /* Task input parameter */ + 2, /* Priority of the task */ + xAudioStack, /* Task stack */ + &xAudioTaskBuffer, /* Memory for the task's control block */ + m_audioTaskCoreId /* Core where the task should run */ + ); +} + +void Audio::stopAudioTask() { + if (!m_f_audioTaskIsRunning) { + AUDIO_LOG_DEBUG("audio task is not running."); + return; + } + AUDIO_LOG_INFO("stop audio task."); + xSemaphoreTake(mutex_audioTask, 0.3 * configTICK_RATE_HZ); + m_f_audioTaskIsRunning = false; + if (m_audioTaskHandle != nullptr) { + vTaskDelete(m_audioTaskHandle); + m_audioTaskHandle = nullptr; + } + xSemaphoreGive(mutex_audioTask); +} + +void Audio::audioTaskWrapper(void* param) { + Audio* audioRunner = static_cast(param); + audioRunner->audioTask(); +} + +void Audio::audioTask() { + while (m_f_audioTaskIsRunning) { + vTaskDelay(1 / portTICK_PERIOD_MS); // periodically every x ms + if (m_f_I2S_init) performAudioTask(); + } + vTaskDelete(nullptr); // Delete this task +} + +void Audio::performAudioTask() { + if (m_decoder) { + xSemaphoreTake(mutex_audioTask, 0.3 * configTICK_RATE_HZ); + while (m_validSamples) { + vTaskDelay(20 / portTICK_PERIOD_MS); + playChunk(); + } // I2S buffer full + playAudioData(); + xSemaphoreGive(mutex_audioTask); + gain_ramp(); + return; + } else { + int32_t c[2] = {0}; + calculateVUlevel(c); + gain_ramp(); + vTaskDelay(20); + return; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t Audio::getHighWatermark() { + UBaseType_t highWaterMark = uxTaskGetStackHighWaterMark(m_audioTaskHandle); + return highWaterMark; // dwords +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/Audio.h b/libraries/ESP32-audioI2S/src/Audio.h new file mode 100644 index 0000000..56366a0 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/Audio.h @@ -0,0 +1,811 @@ +/* + * Audio.h + * + */ + +#pragma once +#pragma GCC optimize("Ofast") +#include "audiolib_structs.hpp" +#include "esp_arduino_version.h" +#include "esp_dsp.h" +#include "psram_unique_ptr.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef I2S_GPIO_UNUSED + #define I2S_GPIO_UNUSED -1 // = I2S_PIN_NO_CHANGE in IDF < 5 +#endif + +extern __attribute__((weak)) void audio_process_raw_samples(int32_t* outBuff, int16_t validSamples); // before volume, gain and equalizer, record audiodata +extern __attribute__((weak)) void audio_process_i2s(int32_t* outBuff, int16_t validSamples, bool* continueI2S); // after volume, gain and equalizer, send via BT +extern char audioI2SVers[]; +class Decoder; // prototype + +//---------------------------------------------------------------------------------------------------------------------- +class AudioBuffer { + + public: + AudioBuffer(); // constructor + ~AudioBuffer(); // frees the buffer + size_t init(); // set default values + bool isInitialized() { return m_init; }; + size_t getBufsize(); + size_t getMaxBlockSize(); // returns maxBlockSize + void setMaxBlocksize(uint32_t mbs); + size_t freeSpace(); // number of free bytes to overwrite + size_t writeSpace(); // space fom writepointer to bufferend + size_t bufferFilled(); // returns the number of filled bytes + size_t readSpace(); // max readable bytes in one block + void bytesWritten(size_t bw); // update writepointer + void bytesWasRead(size_t br); // update readpointer + uint8_t* getWritePtr(); // returns the current writepointer + uint8_t* getReadPtr(); // returns the current readpointer + void reset(); // restore defaults + void showStatus(); + + protected: + size_t m_mainBuffSize = 0; // most webstreams limit the advance to 100...300Kbytes + size_t m_freeSpace = 0; + size_t m_writeSpace = 0; + size_t m_resBuffSize = 0; + size_t m_maxBlockSize = 0; + size_t m_readSpace = 0; + const size_t m_maxRet = UINT16_MAX; + ps_ptr m_buffer; + uint8_t* m_buffEnd = nullptr; + uint8_t* m_writePtr = nullptr; + uint8_t* m_readPtr = nullptr; + uint8_t* m_endPtr = nullptr; + uint8_t* m_startPtr = nullptr; + ps_ptr m_log; + bool m_init = false; + bool m_isEmpty = true; + bool m_isFull = false; + + private: + SemaphoreHandle_t m_mutex = nullptr; +#define ANSI_ESC_RED "\033[31m" +}; +//---------------------------------------------------------------------------------------------------------------------- + +class Audio { + private: + AudioBuffer InBuff; // instance of input buffer + + public: + Audio(uint8_t i2sPort = I2S_NUM_0); + ~Audio(); + std::mutex mutex_info; // mutex_info as member + + // callbacks --------------------------------------------------------- + typedef enum { + evt_info = 0, + evt_id3data, + evt_eof, + evt_name, + evt_icydescription, + evt_streamtitle, + evt_bitrate, + evt_icyurl, + evt_icylogo, + evt_genre, + evt_lasthost, + evt_image, + evt_lyrics, + evt_log, + } event_t; + + // Audio event type descriptions + static constexpr std::array eventStr = { + "info", // evt_info + "id3data", // evt_id3data + "eof", // evt_eof + "station_name", // evt_name + "icy_description", // evt_icydescription + "streamtitle", // evt_streamtitle + "bitrate (b/s)", // evt_bitrate + "icy_url", // evt_icyurl + "icy_logo", // evt_icylogo + "genre", // evt_genre + "lasthost", // evt_lasthost + "cover_image", // evt_image + "lyrics", // evt_lyrics + "log", // evt_log + }; + + typedef struct _msg { // used in info(audio_info_callback()); + const char* msg = nullptr; + const char* s = nullptr; + event_t e = (event_t)0; // event type + int32_t i2s_num = 0; + int32_t arg1 = 0; + int32_t arg2 = 0; + std::vector vec = {}; // apic [pos, len, pos, len, pos, len, ....] + } msg_t; + inline static std::function audio_info_callback; + using VolumeCurveFn = std::function; + // ------------------------------------------------------------------- + typedef enum : uint32_t { SR_ORIGIN = 0, SR_44100 = 44100, SR_48000 = 48000 } OutputSR_t; + + bool openai_speech(const String& api_key, const String& model, const String& input, const String& instructions, const String& voice, const String& response_format, const String& speed); + audiolib::hwoe_t dismantle_host(const char* host); + bool connecttohost(const char* host, const char* user = nullptr, const char* pwd = nullptr); + bool connecttospeech(const char* speech, const char* lang); + bool connecttoFS(fs::FS& fs, const char* path, int32_t fileStartTime = -1); + void setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl); + bool setAudioPlayTime(uint16_t sec); + bool setTimeOffset(int sec); + bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t MCLK = I2S_GPIO_UNUSED); + bool pauseResume(); + bool isRunning() { return m_f_running; } + void loop(); + uint32_t stopSong(); + void forceMono(bool m); + void setOutputSampleRate(OutputSR_t sr); + void setBalance(float balance = 0.0f); + void setVolumeSteps(uint8_t steps); + uint8_t getVolumeSteps(); + void setVolume(uint8_t vol, uint8_t curve = 0); + void setVolumeCurve(VolumeCurveFn curve); + uint8_t getVolume(); + void setMute(bool mute); + bool getMute(); + int32_t getI2sPort(); + uint32_t getFileSize(); + uint32_t getSampleRate(); + uint8_t getBitsPerSample(); + uint8_t getChannels(); + uint32_t getBitRate(); + uint32_t getAudioFileDuration(); + uint32_t getAudioCurrentTime(); + uint32_t getAudioFilePosition(); + bool setAudioFilePosition(uint32_t pos); + uint16_t getVUlevel(); + uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer + uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer + uint32_t getInBufferSize(); // returns the size of the inputbuffer in bytes + void inBufferStatus() { InBuff.showStatus(); } + void setTone(float gainLowPass, float gainBandPass, float gainHighPass); + void setI2SCommFMT_LSB(bool commFMT); + int getCodec() { return m_codec; } + const char* getCodecname() { return codecname[m_codec]; } + const char* getVersion(); + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + private: + // ------- PRIVATE MEMBERS ---------------------------------------- + bool i2s_config(); + std::unique_ptr createDecoder(const std::string& type); + void destroy_decoder(); + bool fsRange(uint32_t range); + void latinToUTF8(ps_ptr& buff, bool UTF8check = true); + void htmlToUTF8(char* str); + void setDefaults(); // free buffers and set defaults + int32_t audioFileRead(); + int32_t audioFileRead(uint16_t timeout_ms); + int32_t audioFileRead(uint8_t* buff, size_t len); + int32_t audioFileRead(uint8_t* buff, size_t len, uint16_t timeout_ms); + int32_t audioFileSeek(uint32_t position, size_t len = 0); + void initInBuff(); + bool httpPrint(const char* host); + bool httpRange(uint32_t range, uint32_t length = UINT32_MAX); + void processLocalFile(); + void processWebStream(); + void processWebFile(); + void processWebStreamTS(); + void processWebStreamHLS(); + void playAudioData(); + bool readPlayListData(); + const char* parsePlaylist_M3U(); + const char* parsePlaylist_PLS(); + const char* parsePlaylist_ASX(); + ps_ptr parsePlaylist_M3U8(); + uint16_t accomplish_m3u8_url(); + int16_t prepare_first_m3u8_url(ps_ptr& playlistBuff); + ps_ptr m3u8redirection(uint8_t* codec); + void showCodecParams(); + int findNextSync(uint8_t* data, size_t len); + uint32_t decodeError(int8_t res, uint8_t* data, int32_t bytesDecoded); + uint32_t decodeContinue(int8_t res, uint8_t* data, int32_t bytesDecoded, int32_t* bytesLeft); + int sendBytes(uint8_t* data, size_t len); + void setDecoderItems(); + void calculateAudioTime(uint16_t bytesDecoderIn, uint16_t bytesDecoderOut); + void showID3Tag(const char* tag, const char* val); + size_t readAudioHeader(uint32_t bytes); + int read_WAV_Header(uint8_t* data, size_t len); + int read_FLAC_Header(uint8_t* data, size_t len); + int read_ID3_Header(uint8_t* data, size_t len); + int read_M4A_Header(uint8_t* data, size_t len); + size_t process_m3u8_ID3_Header(uint8_t* packet); + bool setSampleRate(uint32_t hz); + bool setBitsPerSample(int bits); + bool setChannels(int channels); + uint32_t resampleI2Soutput(audiolib::resampler_t& resampler, int32_t* input, uint32_t inputSamples, int32_t* output); + void playChunk(); + void calculateVUlevel(int32_t* sample); + void processSpectrum(); + void gain_ramp(); + void calculateVolumeLimits(); + void Gain(int32_t* sample); + void showstreamtitle(char* ml); + bool parseContentType(ps_ptr ct); + bool parseHttpResponseHeader(); + bool parseHttpRangeHeader(); + bool initializeDecoder(); + esp_err_t I2Sstart(); + esp_err_t I2Sstop(); + void zeroI2Sbuff(); + void reconfigI2S(); + void stereo2mono(int32_t* buff, uint16_t validSamples); + void IIR_calculateCoefficients(); + void IIR_filter(int32_t* iir_in); + uint32_t streamavail() { return m_client ? m_client->available() : 0; } + bool ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength); + uint64_t getLastGranulePosition(uint8_t codec); + + //+++ create a T A S K for playAudioData(), output via I2S +++ + public: + void setAudioTaskCore(uint8_t coreID); + uint32_t getHighWatermark(); + + private: + void startAudioTask(); // starts a task for decode and play + void stopAudioTask(); // stops task for audio + static void audioTaskWrapper(void* param); + void audioTask(); + void performAudioTask(); + + //+++ H E L P F U N C T I O N S +++ + bool readMetadata(uint32_t b, uint16_t* readedBytes, bool first = false); + int32_t getChunkSize(uint16_t* readedBytes, bool first = false); + bool readID3V1Tag(); + int32_t newInBuffStart(int32_t resumeFilePos); + boolean streamDetection(uint32_t bytesAvail); + uint32_t m4a_correctResumeFilePos(); + uint32_t ogg_correctResumeFilePos(); + int32_t flac_correctResumeFilePos(); + int32_t mp3_correctResumeFilePos(); + int32_t wav_correctResumeFilePos(); + uint8_t determineCodec(uint8_t presumed_codec); + bool get_info(); + void trim(char* str); + bool startsWith(const char* base, const char* str); + int indexOf(const char* base, const char* str, int startIndex = 0); + int indexOf(const char* base, char ch, int startIndex = 0); + int specialIndexOf(uint8_t* base, const char* str, int baselen, bool exact = false); + int32_t min3(int32_t a, int32_t b, int32_t c); + uint64_t bigEndian(uint8_t* base, uint8_t numBytes, uint8_t shiftLeft = 8); + bool b64encode(const char* source, uint16_t sourceLength, char* dest); + void vector_clear_and_shrink(std::vector>& vec); + void deque_clear_and_shrink(std::deque>& deq); + uint32_t simpleHash(const char* str); + ps_ptr urlencode(const char* str, bool spacesOnly); + audiolib::BiquadCoeffs makeButterworthLPF_Q31(float fs); + + private: + enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 }; + enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 }; + enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4 }; // playlist formats + const char* plsFmtStr[5] = {"NONE", "M3U", "PLS", "ASX", "M3U8"}; // playlist format string + enum : int { AUDIO_NONE, HTTP_RESPONSE_HEADER, HTTP_RANGE_HEADER, AUDIO_DATA, AUDIO_LOCALFILE, AUDIO_PLAYLISTINIT, AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA }; + const char* dataModeStr[8] = {"AUDIO_NONE", "HTTP_RESPONSE_HEADER", "HTTP_RANGE_HEADER", "AUDIO_DATA", "AUDIO_LOCALFILE", "AUDIO_PLAYLISTINIT", "AUDIO_PLAYLISTHEADER", "AUDIO_PLAYLISTDATA"}; + enum : int { FLAC_BEGIN = 0, FLAC_MAGIC = 1, FLAC_MBH = 2, FLAC_SINFO = 3, FLAC_PADDING = 4, FLAC_APP = 5, FLAC_SEEK = 6, FLAC_VORBIS = 7, FLAC_CUESHEET = 8, FLAC_PICTURE = 9, FLAC_OKAY = 100 }; + enum : int { MP3_BEGIN = 0, MP3_ID3HEADER, MP3_NEXTID3, MP3_EXTHEADER, MP3_ID3FRAME, MP3_FRAMESIZE, MP3_SKIP, MP3_TAG, MP3_SYLT, MP3_ID3V22, MP3_LASTFRAMES, MP3_XING, MP3_OKAY = 100 }; + enum : int { + M4A_BEGIN = 0, + M4A_FTYP = 1, + M4A_CHK = 2, + M4A_MOOV = 3, + M4A_FREE = 4, + M4A_TRAK = 5, + M4A_MDAT = 6, + M4A_ILST = 7, + M4A_MP4A = 8, + M4A_ESDS = 9, + M4A_MDIA = 10, + M4A_MINF = 11, + M4A_STBL = 12, + M4A_STSD = 13, + M4A_UDTA = 14, + M4A_STSZ = 15, + M4A_META = 16, + M4A_MDHD = 17, + M4A_CHPL = 18, + M4A_AMRDY = 99, + M4A_OKAY = 100, + }; + enum : int { CODEC_NONE = 0, CODEC_WAV = 1, CODEC_MP3 = 2, CODEC_AAC = 3, CODEC_M4A = 4, CODEC_FLAC = 5, CODEC_OPUS = 6, CODEC_VORBIS = 7, CODEC_OGG = 8 }; + const char* codecname[10] = {"unknown", "WAV", "MP3", "AAC", "M4A", "FLAC", "OPUS", "VORBIS", "OGG"}; + enum : int { ST_NONE = 0, ST_WEBFILE = 1, ST_WEBSTREAM = 2 }; + const char* streamTypeStr[3] = {"NONE", "WEBFILE", "WEBSTREAM"}; + typedef enum { LEFTCHANNEL = 0, RIGHTCHANNEL = 1 } SampleIndex; + typedef enum { LOWSHELF = 0, PEAKINGEQ = 1, HIFGSHELF = 2 } FilterType; + + private: + typedef struct _filter { + float a0; + float a1; + float a2; + float b1; + float b2; + } filter_t; + + typedef struct _pis_array { + int number; + int pids[4]; + } pid_array; + + public: + struct audioSettings { + uint16_t DMA_DESC_NUM = 32; // number of I2S DMA buffer + uint16_t DMA_FRAME_NUM = 256; // number of frames in one DMA buffer + uint16_t FREQ_LS_HZ = 500; // IIR Filter, lowshelf + uint16_t FREQ_PEAK_HZ = 1800; // IIR Filter, peakingEQ + uint16_t FREQ_HS_HZ = 6000; // IIR Filter, highshelf + float QUALITY_SLOPE = 0.707; // Quality (all shelfes) + uint16_t PEAK_HOLD_SAMPLES = 2000; // VU_meter, (2000) ca. 20 ms @ 48 kHz + uint8_t PEAK_RELEASE = 1; // VU_meter, Fall rate + bool VU_LEVEL = true; // true: vu meter is enabled + bool IIR_FILTER = true; // true: IIR filter (highshelf, bandpass, lowshelf) are enabled + bool SPECTRUM = false; // true: spectrum analyzer is enabled + bool VOLUME_CONTROL = true; // true: volume and balance control is enabled + float VOL_FADING_SPEED = 50.0; // mute, volume fading 1.0f (fast) ... 100.0f (slow) + uint32_t BUFFER_TRESHOLD_HLS = 120000; // Level at which the HLS-TS stream starts and is reloaded + } settings; + + private: + File m_audiofile; + NetworkClient client; + NetworkClientSecure clientsecure; + NetworkClient* m_client = nullptr; + + SemaphoreHandle_t mutex_playAudioData; + SemaphoreHandle_t mutex_audioTask; + SemaphoreHandle_t mutex_audioTaskIsDecoding; + TaskHandle_t m_audioTaskHandle = nullptr; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + + i2s_chan_handle_t m_i2s_tx_handle = {}; + i2s_chan_config_t m_i2s_chan_cfg = {}; // stores I2S channel values + i2s_std_config_t m_i2s_std_cfg = {}; // stores I2S driver values + +#pragma GCC diagnostic pop + + std::vector> m_playlistContent; // m3u8 playlist buffer from responseHeader + std::vector> m_playlistURL; // m3u8 streamURLs buffer + std::deque> m_linesWithURL; // extract from m_playlistContent, contains URL and MediaSequenceNumber + std::vector> m_linesWithEXTINF; // extract from m_playlistContent, contains length and metadata + std::vector> m_syltLines; // SYLT line table + std::vector m_syltTimeStamp; // SYLT time table + + static const uint8_t m_tsPacketSize = 188; + static const uint8_t m_tsHeaderSize = 4; + + std::unique_ptr m_decoder = {}; + ps_ptr m_outBuff; // Interleaved L/R + ps_ptr m_resamplesBuff; // Interleaved L/R + ps_ptr m_metadataBuff; // icy-metadata max (16 * 256 + 1) bytes + ps_ptr m_httpRespHdrBuff; // store http response header + ps_ptr m_ibuff; // used in log_info() + ps_ptr m_lastHost; // Store the last URL to a webstream + ps_ptr m_currentHost; // can be changed by redirection or playlist + ps_ptr m_m3u8_host; + ps_ptr m_speechtxt; // stores tts text + ps_ptr m_streamTitle; // stores the last StreamTitle + ps_ptr m_streamURL; // stores the last StreamURL + ps_ptr m_playlistBuff; + VolumeCurveFn m_volumeCurve = nullptr; + + const uint16_t m_plsBuffEntryLen = 256; // length of each entry in playlistBuff + int m_LFcount = 0; // Detection of end of header + uint32_t m_avr_bitrate = 0; // average bitrate, median calculated by VBR + uint32_t m_nominal_bitrate = 0; // given br from header + uint32_t m_audioFilePosition = 0; // current position, counts every readed byte + uint32_t m_audioDataReadPtr = 0; // used in playAudioData + uint32_t m_audioFileSize = 0; // local and web files + int m_readbytes = 0; // bytes read + uint32_t m_metacount = 0; // counts down bytes between metadata + int m_controlCounter = 0; // Status within readID3data() and readWaveHeader() + uint8_t m_timeoutCounter = 0; // timeout counter + uint8_t m_bitsPerSample = 16; // bitsPerSample + uint8_t m_channels = 2; // + uint8_t m_playlistFormat = 0; // M3U, PLS, ASX + uint8_t m_codec = CODEC_NONE; // + uint8_t m_m3u8Codec = CODEC_AAC; // codec of m3u8 stream + uint8_t m_expectedCodec = CODEC_NONE; // set in connecttohost (e.g. http://url.mp3 -> CODEC_MP3) + uint8_t m_expectedPlsFmt = FORMAT_NONE; // set in connecttohost (e.g. streaming01.m3u) -> FORMAT_M3U) + uint8_t m_streamType = ST_NONE; // + uint8_t m_ID3Size = 0; // lengt of ID3frame - ID3header + uint8_t m_audioTaskCoreId = 0; // + uint8_t m_M4A_objectType = 0; // set in read_M4A_Header + uint8_t m_M4A_chConfig = 0; // set in read_M4A_Header + uint16_t m_M4A_sampleRate = 0; // set in read_M4A_Header + int16_t m_validSamples = 0; // + int16_t m_curSample = 0; // + uint16_t m_dataMode = 0; // Statemaschine + uint16_t m_streamTitleHash = 0; // remember streamtitle, ignore multiple occurence in metadata + uint16_t m_timeout_ms = 250; // + uint16_t m_timeout_ms_ssl = 2700; // + uint32_t m_metaint = 0; // Number of databytes between metadata + uint32_t m_chunkcount = 0; // Counter for chunked transfer + uint32_t m_t0 = 0; // store millis(), is needed for a small delay + uint32_t m_bytesNotConsumed = 0; // pictures or something else that comes with the stream + uint64_t m_lastGranulePosition = 0; // necessary to calculate the duration in OPUS and VORBIS + int32_t m_resumeFilePos = -1; // the return value from stopSong(), (-1) is idle + int32_t m_fileStartTime = -1; // may be set in connecttoFS() + uint16_t m_m3u8_targetDuration = 10; // + uint32_t m_stsz_numEntries = 0; // num of entries inside stsz atom (uint32_t) + uint32_t m_stsz_position = 0; // pos of stsz atom within file + uint32_t m_haveNewFilePos = 0; // user changed the file position + bool m_f_alt_user_agent = false; // use default or alternative user agent + bool m_f_I2S_init = false; // + bool m_f_unsync = false; // set within ID3 tag but not used + bool m_f_exthdr = false; // ID3 extended header + bool m_f_ssl = false; // + bool m_f_running = false; // + bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile + bool m_f_firstLoop = false; // InitSequence in loop() + bool m_f_firstPlayCall = false; // InitSequence for playAudioData + bool m_f_ID3v1TagFound = false; // ID3v1 tag found + bool m_f_chunked = false; // Station provides chunked transfer + bool m_f_firstmetabyte = false; // True if first metabyte (counter) + bool m_f_playing = false; // valid mp3 stream recognized + bool m_f_tts = false; // text to speech + bool m_f_ogg = false; // OGG stream + bool m_f_forceMono = false; // if true stereo -> mono + bool m_f_rtsp = false; // set if RTSP is used (m3u8 stream) + bool m_f_m3u8data = false; // used in processM3U8entries + bool m_f_continue = false; // next m3u8 chunk is available + bool m_f_ts = true; // transport stream + bool m_f_m4aID3dataAreRead = false; // has the m4a-ID3data already been read? + bool m_f_psramFound = false; // set in constructor, result of psramInit() + bool m_f_timeout = false; // + bool m_f_audioTaskIsRunning = false; // + bool m_f_allDataReceived = false; // + bool m_f_stream = false; // stream ready for output? + bool m_f_decode_ready = false; // if true data for decode are ready + bool m_f_eof = false; // end of file + bool m_f_lockInBuffer = false; // lock inBuffer for manipulation + bool m_f_audioTaskIsDecoding = false; // + bool m_f_acceptRanges = false; // + bool m_f_reset_m3u8Codec = true; // reset codec for m3u8 stream + bool m_f_connectionClose = false; // set in parseHttpResponseHeader + bool m_f_i2s_channel_enabled = false; // true if enabled + uint32_t m_audioFileDuration = 0; // seconds + uint32_t m_audioCurrentTime = 0; // seconds + uint32_t m_audioDataStart = 0; // in bytes + OutputSR_t m_output_sr = SR_ORIGIN; // output samplerate + size_t m_audioDataSize = 0; // + size_t m_ibuffSize = 0; // log buffer size for audio_info() + size_t m_i2s_bytesWritten = 0; // set in i2s_write() but not used + + pid_array m_pidsOfPMT; + int16_t m_pidOfAAC; + uint8_t m_packetBuff[m_tsPacketSize]; + int16_t m_pesDataLength = 0; + + // audiolib structs + audiolib::ID3Hdr_t m_ID3Hdr; + audiolib::pwsHLS_t m_pwsHLS; + audiolib::pplM3u8_t m_pplM3U8; + audiolib::m4aHdr_t m_m4aHdr; + audiolib::plCh_t m_plCh; + audiolib::lVar_t m_lVar; + audiolib::prlf_t m_prlf; + audiolib::cat_t m_cat; + audiolib::ifCh_t m_ifCh; + audiolib::tspp_t m_tspp; + audiolib::pwst_t m_pwst; + audiolib::gchs_t m_gchs; + audiolib::pwf_t m_pwf; + audiolib::pad_t m_pad; + audiolib::sbyt_t m_sbyt; + audiolib::rmet_t m_rmet; + audiolib::pwsts_t m_pwsst; + audiolib::rwh_t m_rwh; + audiolib::rflh_t m_rflh; + audiolib::phreh_t m_phreh; + audiolib::phrah_t m_phrah; + audiolib::sdet_t m_sdet; + audiolib::fnsy_t m_fnsy; + audiolib::audioItems_t m_audio_items; + audiolib::vu_items_t m_vu_items; + audiolib::fft_items_t m_fft_items; + audiolib::i2s_items_t m_i2s_items; + audiolib::resampler_t m_resampler; + audiolib::info_queue_t m_info_queue; + audiolib::icy_items_t m_icy_items; + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + public: + template static bool info(Audio& instance, event_t e, const char* fmt, Args&&... args) { + std::lock_guard lock(instance.mutex_info); + if (!fmt) return false; + if (!audio_info_callback) return false; + + ps_ptr result; + result.assignf(fmt, std::forward(args)...); + if (!result.get()) return false; + + auto extract_last_number = [](std::string_view s) -> std::optional { + auto is_space = [](char c) { return std::isspace(static_cast(c)); }; + auto is_digit = [](char c) { return std::isdigit(static_cast(c)); }; + + auto it = s.end(); + // skip trailing whitespace + while (it != s.begin() && is_space(*(it - 1))) { --it; } + auto end = it; + // Reading numbers backwards + while (it != s.begin() && is_digit(*(it - 1))) { --it; } + // optional sign + if (it != s.begin()) { + char c = *(it - 1); + if (c == '+' || c == '-') { --it; } + } + + // found nothing? + if (it == end) { return std::nullopt; } + // There must be a leading space or a space before the number + if (it != s.begin() && !is_space(*(it - 1))) { return std::nullopt; } + int32_t value{}; + auto [ptr, ec] = std::from_chars(it, end, value); + + // Was the full parse successful? + if (ec == std::errc{} && ptr == end) { return value; } + return std::nullopt; + }; + + std::vector v; + v.push_back(0); + instance.m_info_queue.msg.emplace_front(result); + instance.m_info_queue.s.emplace_front(eventStr[e]); + instance.m_info_queue.arg1.emplace_front(extract_last_number(result.c_get()).value_or(0)); + instance.m_info_queue.arg2.emplace_front(0); + instance.m_info_queue.vec.emplace_front(v); + instance.m_info_queue.e.emplace_front((uint8_t)e); + result.reset(); + return true; + } + + static bool info(Audio& instance, event_t e, std::vector& v) { + if (!audio_info_callback) return false; + std::lock_guard lock(instance.mutex_info); // lock mutex + ps_ptr apic; + apic.assignf("APIC found at pos {}", v[0]); + // msg_t i; + // i.msg = apic.c_get(); + // i.e = e; + // i.s = eventStr[e]; + // i.i2s_num = instance.m_i2s_items.i2s_num; + // i.vec = v; + // audio_info_callback(i); + + instance.m_info_queue.msg.emplace_front(apic); + instance.m_info_queue.s.emplace_front(eventStr[e]); + instance.m_info_queue.arg1.emplace_front(0); + instance.m_info_queue.arg2.emplace_front(0); + instance.m_info_queue.vec.emplace_front(v); + instance.m_info_queue.e.emplace_front((uint8_t)e); + return true; + } + //---------------------------------------------------------------------------------------------------------------------- + + template static void AUDIO_LOG_IMPL(uint8_t level, const char* path, int line, const char* func, const char* fmt, Args&&... args) { + +#define ANSI_ESC_RESET "\033[0m" +#define ANSI_ESC_BLACK "\033[30m" +#define ANSI_ESC_RED "\033[31m" +#define ANSI_ESC_GREEN "\033[32m" +#define ANSI_ESC_YELLOW "\033[33m" +#define ANSI_ESC_BLUE "\033[34m" +#define ANSI_ESC_MAGENTA "\033[35m" +#define ANSI_ESC_CYAN "\033[36m" +#define ANSI_ESC_WHITE "\033[37m" + + ps_ptr logStr = path; + while (logStr.contains("/")) { logStr.remove_before('/', false); } + logStr.appendf(":{} {}] ", line, func ? func : ""); + logStr.insert("[", 0); + + if (level == 1 && CORE_DEBUG_LEVEL >= 1) { + logStr.append(ANSI_ESC_RED); + } else if (level == 2 && CORE_DEBUG_LEVEL >= 2) { + logStr.append(ANSI_ESC_YELLOW); + } else if (level == 3 && CORE_DEBUG_LEVEL >= 3) { + logStr.append(ANSI_ESC_GREEN); + } else if (level == 4 && CORE_DEBUG_LEVEL >= 4) { + logStr.append(ANSI_ESC_CYAN); + } // debug + else if (level == 5 && CORE_DEBUG_LEVEL >= 4) { + logStr.append(ANSI_ESC_WHITE); + } // verbose + else + return; + + int add_len = std::snprintf(nullptr, 0, fmt, std::forward(args)...); + if (add_len > 0) { + logStr.appendf(fmt, std::forward(args)...); // <-- neue appendf() + } + logStr.append(ANSI_ESC_RESET); + + msg_t msg; + msg.msg = logStr.get(); + const char* tag[7] = {"", "LOGE", "LOGW", "LOGI", "LOGD", "LOGV", ""}; + msg.s = tag[level]; + msg.e = evt_log; + + if (audio_info_callback) + audio_info_callback(msg); + else { + if (level == 1) + log_e("%s", logStr.c_get()); + else if (level == 2) + log_w("%s", logStr.c_get()); + else if (level == 3) + log_i("%s", logStr.c_get()); + else if (level == 4) + log_d("%s", logStr.c_get()); + else + log_v("%s", logStr.c_get()); + } + logStr.reset(); + } + +// Macro for comfortable calls +#define AUDIO_LOG_ERROR(fmt, ...) AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AUDIO_LOG_WARN(fmt, ...) AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AUDIO_LOG_INFO(fmt, ...) AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AUDIO_LOG_DEBUG(fmt, ...) AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 D E C O D E R 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +class Decoder { + public: + virtual ~Decoder() = default; + virtual bool init() = 0; + virtual void clear() = 0; + virtual void reset() = 0; + virtual bool isValid() = 0; + virtual int32_t findSyncWord(uint8_t* buf, int32_t nBytes) = 0; + virtual uint8_t getChannels() = 0; + virtual uint32_t getSampleRate() = 0; + virtual uint8_t getBitsPerSample() = 0; + virtual uint32_t getBitRate() = 0; + virtual uint32_t getAudioDataStart() = 0; + virtual uint32_t getAudioFileDuration() = 0; + virtual uint32_t getOutputSamples() = 0; + virtual int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf1) = 0; + virtual void setRawBlockParams(uint8_t param1, uint32_t param2, uint8_t param3, uint32_t param4, uint32_t param5) = 0; + virtual const char* getStreamTitle(); + virtual const char* whoIsIt(); + virtual std::vector getMetadataBlockPicture() = 0; + virtual const char* arg1() = 0; // decoder specific + virtual const char* arg2() = 0; // decoder specific + virtual int32_t val1() = 0; // decoder specific + virtual int32_t val2() = 0; // decoder specific + + protected: + Decoder(Audio& audioRef) : audio(audioRef) {} + Audio& audio; // protected reference, usable by all subclasses + private: + Decoder() = delete; // Deactivate default constructor explicitly (optional but good against abuse) +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 A U T O L O G G E R for detecting memory leaks 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* usage + void myFunction(){ + HEAP_GUARD(); // <--- automatic check + my code ... + my code ... + } + + { // Or in small critical code blocks: + HEAP_GUARD(); + fill_content(inbuf, to_read); + } +*/ + +struct _HeapGuardSnapshot { + size_t free_dram_before{}; + size_t free_psram_before{}; + bool integrity_before{}; + const char* func{}; + bool active{false}; + + _HeapGuardSnapshot(const char* f) : func(f), active(true) { + free_dram_before = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); + free_psram_before = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + integrity_before = heap_caps_check_integrity_all(true); + if (!integrity_before) { + printf(ANSI_ESC_RED "HEAPGUARD [%s] ❌ Heap corruption detected BEFORE!" ANSI_ESC_RESET "\n", func); + } else { + printf(ANSI_ESC_GREEN "HEAPGUARD [%s] Begin: DRAM=%u, PSRAM=%u" ANSI_ESC_RESET "\n", func, (unsigned)free_dram_before, (unsigned)free_psram_before); + } + } + + ~_HeapGuardSnapshot() { + if (!active) return; // falls moved / deaktiviert + size_t free_dram_after = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); + size_t free_psram_after = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + bool ok = heap_caps_check_integrity_all(true); + + int delta_dram = (int)(free_dram_after - free_dram_before); + int delta_psram = (int)(free_psram_after - free_psram_before); + + if (!ok) { + printf(ANSI_ESC_RED "HEAPGUARD [%s] ❌ Heap corruption detected AFTER!" ANSI_ESC_RESET "\n", func); + } else { + printf(ANSI_ESC_GREEN "HEAPGUARD [%s] ✅ Heap OK | ΔDRAM=%+d | ΔPSRAM=%+d" ANSI_ESC_RESET "\n", func, delta_dram, delta_psram); + } + } +}; +#define HEAP_GUARD() _HeapGuardSnapshot _heapguard_instance_##__LINE__(__func__) +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 A U T O P R O F I L E R RAII-class for timekeeping 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* usage + void decodeNative(uint8_t* inbuf, int bytesLeft, uint8_t* outbuf) { + PROFILE_SCOPE_N(1000); // automatically measures 1000 views on average + + // ... my code ... + } + + { // Or in small critical code blocks: + PROFILE_SCOPE_N(100); // measures this block over 100 runs + do_fft_processing(data); + } +*/ +class _AutoProfiler { + public: + _AutoProfiler(const char* name, uint32_t report_interval) : tag(name), N(report_interval) { start = esp_timer_get_time(); } + + ~_AutoProfiler() { + uint64_t elapsed = esp_timer_get_time() - start; + sum += elapsed; + count++; + if(max_dt < elapsed) max_dt = elapsed; + + if (count >= N) { + double avg_us = (double)sum / count; + printf(ANSI_ESC_CYAN "PROFILER [%s] avg: %.2f µs over %lu runs, max %lu µs" ANSI_ESC_RESET "\n", tag, avg_us, count, max_dt); + sum = 0; + count = 0; + max_dt = 0; + } + } + + private: + const char* tag; + uint32_t N; + uint64_t start; + static inline uint32_t max_dt = 0; + static inline uint64_t sum = 0; + static inline uint32_t count = 0; +}; + +// Macro for automatic use with function name +#define PROFILE_SCOPE_N(N) _AutoProfiler _prof_instance_##__LINE__(__func__, N) +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp b/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp new file mode 100644 index 0000000..91cbc63 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp @@ -0,0 +1,234 @@ +/* + * aac_decoder.cpp + * faad2 - ESP32 adaptation + * Created on: 12.09.2023 + * Updated on: 26.06.2026 + */ + +#include "aac_decoder.h" +#include "Arduino.h" +#include "libfaad/neaacdec.h" +#include +#include +#include +#include +#include + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +AACDecoder::AACDecoder(Audio& audioRef) : Decoder(audioRef), audio(audioRef), m_neaacdec(std::make_unique()) {} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool AACDecoder::init() { + m_hAac = m_neaacdec->NeAACDecOpen(); + m_conf = m_neaacdec->NeAACDecGetCurrentConfiguration(m_hAac); + m_out16.alloc_array(4608 * 2, "m_out16"); + + if (m_hAac && m_out16.valid()) m_f_decoderIsInit = true; + m_f_firstCall = false; + m_f_setRaWBlockParams = false; + return m_f_decoderIsInit; +} +void AACDecoder::clear() { + m_out16.clear(); + return; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void AACDecoder::reset() { + m_neaacdec->NeAACDecClose(m_hAac); + m_hAac = NULL; + m_f_decoderIsInit = false; + m_f_firstCall = false; + m_out16.reset(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool AACDecoder::isValid() { + return m_f_decoderIsInit; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t AACDecoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + const int MIN_ADTS_HEADER_SIZE = 7; + if (buf == nullptr || nBytes < MIN_ADTS_HEADER_SIZE) { return -1; } + + auto validate = [MIN_ADTS_HEADER_SIZE](const uint8_t* buf, int32_t bytesAvailable) -> bool { // check the ADTS header for validity + if (bytesAvailable < MIN_ADTS_HEADER_SIZE) { return false; } + + // Layer (bits 14-15) must be 00 + if ((buf[1] & 0x06) != 0x00) { return false; } + + // Sampling Frequency Index (Bits 18-21) cannot be invalid + uint8_t sampling_frequency_index = (buf[2] & 0x3C) >> 2; + if (sampling_frequency_index > 12) { return false; } + + // Frame length (bits 30-42) must be at least the header size + int frame_length = ((buf[3] & 0x03) << 11) | (buf[4] << 3) | ((buf[5] & 0xE0) >> 5); + if (frame_length < MIN_ADTS_HEADER_SIZE) { return false; } + + return true; + }; + + /* find byte-aligned syncword (12 bits = 0xFFF) */ + for (int32_t i = 0; i <= nBytes - MIN_ADTS_HEADER_SIZE; i++) { + if ((buf[i + 0] & SYNCWORDH) == SYNCWORDH && (buf[i + 1] & SYNCWORDL) == SYNCWORDL) { + int32_t bytesAvailable = nBytes - i; + if (!validate(&buf[i], bytesAvailable)) { continue; } + + int frame_length = ((buf[i + 3] & 0x03) << 11) | (buf[i + 4] << 3) | ((buf[i + 5] & 0xE0) >> 5); + if (i + frame_length + 1 >= nBytes) { + return -1; // Puffergrenze überschritten, kein gültiger Header + } + /* find a second byte-aligned syncword (12 bits = 0xFFF) */ + if ((buf[i + frame_length + 0] & SYNCWORDH) == SYNCWORDH && (buf[i + frame_length + 1] & SYNCWORDL) == SYNCWORDL) { return i; } + } + } + + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t AACDecoder::getChannels() { + return m_aacChannels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t AACDecoder::getSampleRate() { + return m_aacSamplerate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t AACDecoder::getOutputSamples() { + return m_validSamples; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t AACDecoder::getBitsPerSample() { + return 16; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t AACDecoder::getBitRate() { + uint32_t br = getBitsPerSample() * getChannels() * getSampleRate(); + return (br / m_compressionRatio); + ; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t AACDecoder::getAudioDataStart() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t AACDecoder::getAudioFileDuration() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* AACDecoder::getStreamTitle() { + return nullptr; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* AACDecoder::whoIsIt() { + return "AAC"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +error_info_t AACDecoder::getErrorMessage(int8_t err) { + return m_neaacdec->NeAACDecGetErrorMessage(abs(err)); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t AACDecoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + uint8_t* ob = (uint8_t*)m_out16.get(); + if (m_f_firstCall == false) { + if (m_f_setRaWBlockParams) { // set raw AAC values, e.g. for M4A config. + m_f_setRaWBlockParams = false; + m_conf->defSampleRate = m_aacSamplerate; + m_conf->outputFormat = FAAD_FMT_16BIT; + m_conf->useOldADTSFormat = 1; + m_conf->defObjectType = 2; + int8_t ret = m_neaacdec->NeAACDecSetConfiguration(m_hAac, m_conf); + (void)ret; + + uint8_t specificInfo[2]; + createAudioSpecificConfig(specificInfo, m_aacProfile, m_neaacdec->get_sr_index(m_aacSamplerate), m_aacChannels); + int8_t err = m_neaacdec->NeAACDecInit2(m_hAac, specificInfo, 2, &m_aacSamplerate, &m_aacChannels); + (void)err; + } else { + m_neaacdec->NeAACDecSetConfiguration(m_hAac, m_conf); + int8_t err = m_neaacdec->NeAACDecInit(m_hAac, inbuf, *bytesLeft, &m_aacSamplerate, &m_aacChannels); + (void)err; + } + m_f_firstCall = true; + } + + m_neaacdec->NeAACDecDecode2(m_hAac, &m_frameInfo, inbuf, *bytesLeft, (void**)&ob, 2048 * 2 * sizeof(int16_t)); + *bytesLeft -= m_frameInfo.bytesconsumed; + m_validSamples = m_frameInfo.samples; + int8_t err = 0 - m_frameInfo.error; + m_compressionRatio = (float)m_frameInfo.samples * 2 / m_frameInfo.bytesconsumed; + if (err < 0) { + if (err == -100) return AAC_ID3_HDR; // ID3 header found + else{ + if(getErrorMessage(abs(err)).level == AAC_ERROR) AAC_LOG_ERROR("{}", getErrorMessage(abs(err)).text); + if(getErrorMessage(abs(err)).level == AAC_WARN) AAC_LOG_WARN("{}", getErrorMessage(abs(err)).text); + if(getErrorMessage(abs(err)).level == AAC_INFO) AAC_LOG_INFO("{}", getErrorMessage(abs(err)).text); + if(getErrorMessage(abs(err)).level == AAC_DEBUG) AAC_LOG_DEBUG("{}", getErrorMessage(abs(err)).text); + if(getErrorMessage(abs(err)).level == AAC_VERBOSE) AAC_LOG_VERBOSE("{}", getErrorMessage(abs(err)).text); + } + } else { + + if (m_aacChannels == 1) { + for (int i = 0; i < m_validSamples; i++) { + outbuf[i * 2] = m_out16[i] << 16; + outbuf[i * 2 + 1] = m_out16[i] << 16; + } + } + + if (m_aacChannels == 2) { + for (int i = 0; i < m_validSamples * 2; i++) { outbuf[i] = m_out16[i] << 16; } + } + } + return err; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void AACDecoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t dummy1, uint32_t profile, uint32_t dummy2) { + m_f_setRaWBlockParams = true; + m_aacChannels = channels; // 1: Mono, 2: Stereo + m_aacSamplerate = sampleRate; // 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 + m_aacProfile = profile; // 1: AAC Main, 2: AAC LC (Low Complexity), 3: AAC SSR (Scalable Sample Rate), 4: AAC LTP (Long Term Prediction) + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector AACDecoder::getMetadataBlockPicture() { + std::vector a; + return a; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* AACDecoder::arg1() { // AAC format + m_arg1.assign("AAC HeaderFormat: "); + if (m_frameInfo.header_type == 0) + m_arg1.append("RAW"); + else if (m_frameInfo.header_type == 1) + m_arg1.append("ADIF"); /* single ADIF header at the beginning of the file */ + else if (m_frameInfo.header_type == 2) + m_arg1.append("ADTS"); /* ADTS header at the beginning of each frame */ + else + m_arg1.append("unknown"); + return m_arg1.c_get(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* AACDecoder::arg2() { + if (m_frameInfo.sbr == 1) return "upsampled SBR"; + if (m_frameInfo.sbr == 2) return "downsampled SBR"; + if (m_frameInfo.sbr == 3) return "no SBR used, but file is upsampled by a factor 2"; + return "without SBR"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t AACDecoder::val1() { // Parametric Stereo + return m_frameInfo.isPS; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t AACDecoder::val2() { // Spectral Band Replication + return m_frameInfo.sbr; // NO_SBR 0 /* no SBR used in this file */ + // SBR_UPSAMPLED 1 /* upsampled SBR used */ + // SBR_DOWNSAMPLED 2 /* downsampled SBR used */ + // NO_SBR_UPSAMPLED 3 /* no SBR used, but file is upsampled by a factor 2 anyway */ +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void AACDecoder::createAudioSpecificConfig(uint8_t* config, uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration) { + config[0] = (audioObjectType << 3) | (samplingFrequencyIndex >> 1); + config[1] = (samplingFrequencyIndex << 7) | (channelConfiguration << 3); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// extern uint8_t NeaacDecoder::get_sr_index(const uint32_t samplerate); +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.h b/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.h new file mode 100644 index 0000000..a4f05d8 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/aac_decoder.h @@ -0,0 +1,82 @@ +/* + * aac_decoder.h + * faad2 - ESP32 adaptation + * Created on: 12.09.2023 + * Updated on: 13.06.2026 + */ + +#pragma once + +#include "../Audio.h" +#include "libfaad/aac_settings.h" +#include "libfaad/aac_structs.h" +#include "libfaad/aac_defines.h" +#include "libfaad/aac_tables.h" +#include "libfaad/neaacdec.h" + +#pragma GCC diagnostic warning "-Wunused-function" + +class AACDecoder : public Decoder { + + public: + enum : int8_t { + AAC_ID3_HDR = 100, + AAC_NONE = 0, + AAC_ERR = -1, + }; + + AACDecoder(Audio& audioRef); + ~AACDecoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; + const char* arg2() override; + virtual int32_t val1() override; // Paramertric Stereo + virtual int32_t val2() override; // SBR + + private: + Audio& audio; + ps_ptr m_arg1; + ps_ptr m_out16; + void createAudioSpecificConfig(uint8_t* config, uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration); + error_info_t getErrorMessage(int8_t err); + + NeAACDecHandle m_hAac; + NeAACDecFrameInfo m_frameInfo; + NeAACDecConfigurationPtr m_conf; + const uint8_t SYNCWORDH = 0xff; /* 12-bit syncword */ + const uint8_t SYNCWORDL = 0xf0; + bool m_f_decoderIsInit = false; + bool m_f_firstCall = false; + bool m_f_setRaWBlockParams = false; + uint32_t m_aacSamplerate = 0; + uint8_t m_aacChannels = 0; + uint8_t m_aacProfile = 0; + uint16_t m_validSamples = 0; + float m_compressionRatio = 1; + std::unique_ptr m_neaacdec; + + struct AudioSpecificConfig { + uint8_t audioObjectType; + uint8_t samplingFrequencyIndex; + uint8_t channelConfiguration; + }; + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_defines.h b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_defines.h new file mode 100644 index 0000000..f564962 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_defines.h @@ -0,0 +1,450 @@ +#pragma once +#include "Arduino.h" +#include "../../Audio.h" +#include "aac_settings.h" + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* defines if an object type can be decoded by this library or not */ +__unused static uint8_t ObjectTypesTable[32] = { + 0, /* 0 NULL */ +#ifdef MAIN_DEC + 1, /* 1 AAC Main */ +#else + 0, /* 1 AAC Main */ +#endif + 1, /* 2 AAC LC */ +#ifdef SSR_DEC + 1, /* 3 AAC SSR */ +#else + 0, /* 3 AAC SSR */ +#endif +#ifdef LTP_DEC + 1, /* 4 AAC LTP */ +#else + 0, /* 4 AAC LTP */ +#endif +#ifdef SBR_DEC + 1, /* 5 SBR */ +#else + 0, /* 5 SBR */ +#endif + 0, /* 6 AAC Scalable */ + 0, /* 7 TwinVQ */ + 0, /* 8 CELP */ + 0, /* 9 HVXC */ + 0, /* 10 Reserved */ + 0, /* 11 Reserved */ + 0, /* 12 TTSI */ + 0, /* 13 Main synthetic */ + 0, /* 14 Wavetable synthesis */ + 0, /* 15 General MIDI */ + 0, /* 16 Algorithmic Synthesis and Audio FX */ +/* MPEG-4 Version 2 */ +#ifdef ERROR_RESILIENCE + 1, /* 17 ER AAC LC */ + 0, /* 18 (Reserved) */ + #ifdef LTP_DEC + 1, /* 19 ER AAC LTP */ + #else + 0, /* 19 ER AAC LTP */ + #endif + 0, /* 20 ER AAC scalable */ + 0, /* 21 ER TwinVQ */ + 0, /* 22 ER BSAC */ + #ifdef LD_DEC + 1, /* 23 ER AAC LD */ + #else + 0, /* 23 ER AAC LD */ + #endif + 0, /* 24 ER CELP */ + 0, /* 25 ER HVXC */ + 0, /* 26 ER HILN */ + 0, /* 27 ER Parametric */ +#else /* No ER defined */ + 0, /* 17 ER AAC LC */ + 0, /* 18 (Reserved) */ + 0, /* 19 ER AAC LTP */ + 0, /* 20 ER AAC scalable */ + 0, /* 21 ER TwinVQ */ + 0, /* 22 ER BSAC */ + 0, /* 23 ER AAC LD */ + 0, /* 24 ER CELP */ + 0, /* 25 ER HVXC */ + 0, /* 26 ER HILN */ + 0, /* 27 ER Parametric */ +#endif + 0, /* 28 (Reserved) */ +#ifdef PS_DEC + 1, /* 29 AAC LC + SBR + PS */ +#else + 0, /* 29 AAC LC + SBR + PS */ +#endif + 0, /* 30 (Reserved) */ + 0 /* 31 (Reserved) */ +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +#define ZERO_HCB 0 +#define FIRST_PAIR_HCB 5 +#define ESC_HCB 11 +#define QUAD_LEN 4 +#define PAIR_LEN 2 +#define NOISE_HCB 13 +#define INTENSITY_HCB2 14 +#define INTENSITY_HCB 15 +#define DRC_REF_LEVEL 20 * 4 /* -20 dB */ +#define DRM_PARAMETRIC_STEREO 0 +#define DRM_NUM_SA_BANDS 8 +#define DRM_NUM_PAN_BANDS 20 +#define NUM_OF_LINKS 3 +#define NUM_OF_QMF_CHANNELS 64 +#define NUM_OF_SUBSAMPLES 30 +#define MAX_SA_BAND 46 +#define MAX_PAN_BAND 64 +#define MAX_DELAY 5 +#define EXTENSION_ID_PS 2 +#define MAX_PS_ENVELOPES 5 +#define NO_ALLPASS_LINKS 3 +#define BYTE_NUMBIT 8 +#define BYTE_NUMBIT_LD 3 +#define bit2byte(a) ((a + 7) >> BYTE_NUMBIT_LD) +#define NUM_ERROR_MESSAGES 34 +#define ESC_VAL 7 +#define SSR_BANDS 4 +#define PQFTAPS 96 + +#ifdef DRM + #define DECAY_CUTOFF 3 + #define DECAY_SLOPE 0.05f +/* type definitaions */ +typedef const int8_t (*drm_ps_huff_tab)[2]; +#endif + +#define FLOAT_SCALE (1.0f / (1 << 15)) +#define DM_MUL REAL_CONST(0.3203772410170407) // 1/(1+sqrt(2) + 1/sqrt(2)) +#define RSQRT2 REAL_CONST(0.7071067811865475244) // 1/sqrt(2) +#define NUM_CB 6 +#define NUM_CB_ER 22 +#define MAX_CB 32 +#define VCB11_FIRST 16 +#define VCB11_LAST 31 +#define TNS_MAX_ORDER 20 +#define MAIN 1 +#define LC 2 +#define SSR 3 +#define LTP 4 +#define HE_AAC 5 +#define LD 23 +#define ER_LC 17 +#define ER_LTP 19 +#define DRM_ER_LC 27 /* special object type for DRM */ +/* header types */ +#define RAW 0 +#define ADIF 1 +#define ADTS 2 +#define LATM 3 +/* SBR signalling */ +#define NO_SBR 0 +#define SBR_UPSAMPLED 1 +#define SBR_DOWNSAMPLED 2 +#define NO_SBR_UPSAMPLED 3 +/* DRM channel definitions */ +#define DRMCH_MONO 1 +#define DRMCH_STEREO 2 +#define DRMCH_SBR_MONO 3 +#define DRMCH_SBR_STEREO 4 +#define DRMCH_SBR_PS_STEREO 5 +/* First object type that has ER */ +#define ER_OBJECT_START 17 +/* Bitstream */ +#define LEN_SE_ID 3 +#define LEN_TAG 4 +#define LEN_BYTE 8 +#define EXT_FIL 0 +#define EXT_FILL_DATA 1 +#define EXT_DATA_ELEMENT 2 +#define EXT_DYNAMIC_RANGE 11 +#define ANC_DATA 0 +/* Syntax elements */ +#define ID_SCE 0x0 +#define ID_CPE 0x1 +#define ID_CCE 0x2 +#define ID_LFE 0x3 +#define ID_DSE 0x4 +#define ID_PCE 0x5 +#define ID_FIL 0x6 +#define ID_END 0x7 +#define INVALID_ELEMENT_ID 255 +#define ONLY_LONG_SEQUENCE 0x0 +#define LONG_START_SEQUENCE 0x1 +#define EIGHT_SHORT_SEQUENCE 0x2 +#define LONG_STOP_SEQUENCE 0x3 +#define ZERO_HCB 0 +#define FIRST_PAIR_HCB 5 +#define ESC_HCB 11 +#define QUAD_LEN 4 +#define PAIR_LEN 2 +#define NOISE_HCB 13 +#define INTENSITY_HCB2 14 +#define INTENSITY_HCB 15 +#define INVALID_SBR_ELEMENT 255 +#define T_HFGEN 8 +#define T_HFADJ 2 +#define EXT_SBR_DATA 13 +#define EXT_SBR_DATA_CRC 14 +#define FIXFIX 0 +#define FIXVAR 1 +#define VARFIX 2 +#define VARVAR 3 +#define LO_RES 0 +#define HI_RES 1 +#define NO_TIME_SLOTS_960 15 +#define NO_TIME_SLOTS 16 +#define RATE 2 +#define NOISE_FLOOR_OFFSET 6 + +#ifdef PS_DEC + #define NEGATE_IPD_MASK (0x1000) + #define DECAY_SLOPE FRAC_CONST(0.05) + #define COEF_SQRT2 COEF_CONST(1.4142135623731) +#endif // PS_DEC + +#define MAX_NTSRHFG 40 /* MAX_NTSRHFG: maximum of number_time_slots * rate + HFGen. 16*2+8 */ +#define MAX_NTSR 32 /* max number_time_slots * rate, ok for DRM and not DRM mode */ +#define MAX_M 49 /* MAX_M: maximum value for M */ +#define MAX_L_E 5 /* MAX_L_E: maximum value for L_E */ + +#ifdef SBR_DEC + #ifdef FIXED_POINT + #define _EPS (1) /* smallest number available in fixed point */ + #else + #define _EPS (1e-12) + #endif +#endif // SBR_DEC + +#ifdef FIXED_POINT /* int32_t */ + #define LOG2_MIN_INF REAL_CONST(-10000) + #define COEF_BITS 28 + #define COEF_PRECISION (1 << COEF_BITS) + #define REAL_BITS 14 // MAXIMUM OF 14 FOR FIXED POINT SBR + #define REAL_PRECISION (1 << REAL_BITS) + /* FRAC is the fractional only part of the fixed point number [0.0..1.0) */ + #define FRAC_SIZE 32 /* frac is a 32 bit integer */ + #define FRAC_BITS 31 + #define FRAC_PRECISION ((uint32_t)(1 << FRAC_BITS)) + #define FRAC_MAX 0x7FFFFFFF +typedef int32_t real_t; + #define REAL_CONST(A) (((A) >= 0) ? ((real_t)((A) * (REAL_PRECISION) + 0.5)) : ((real_t)((A) * (REAL_PRECISION) - 0.5))) + #define COEF_CONST(A) (((A) >= 0) ? ((real_t)((A) * (COEF_PRECISION) + 0.5)) : ((real_t)((A) * (COEF_PRECISION) - 0.5))) + #define FRAC_CONST(A) (((A) == 1.00) ? ((real_t)FRAC_MAX) : (((A) >= 0) ? ((real_t)((A) * (FRAC_PRECISION) + 0.5)) : ((real_t)((A) * (FRAC_PRECISION) - 0.5)))) + // #define FRAC_CONST(A) (((A) >= 0) ? ((real_t)((A)*(FRAC_PRECISION)+0.5)) : ((real_t)((A)*(FRAC_PRECISION)-0.5))) + #define Q2_BITS 22 + #define Q2_PRECISION (1 << Q2_BITS) + #define Q2_CONST(A) (((A) >= 0) ? ((real_t)((A) * (Q2_PRECISION) + 0.5)) : ((real_t)((A) * (Q2_PRECISION) - 0.5))) + /* multiply with real shift */ + #define MUL_R(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (REAL_BITS - 1))) >> REAL_BITS) + /* multiply with coef shift */ + #define MUL_C(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (COEF_BITS - 1))) >> COEF_BITS) + /* multiply with fractional shift */ + #define _MulHigh(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (FRAC_SIZE - 1))) >> FRAC_SIZE) + #define MUL_F(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (FRAC_BITS - 1))) >> FRAC_BITS) + #define MUL_Q2(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (Q2_BITS - 1))) >> Q2_BITS) + #define MUL_SHIFT6(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (6 - 1))) >> 6) + #define MUL_SHIFT23(A, B) (real_t)(((int64_t)(A) * (int64_t)(B) + (1 << (23 - 1))) >> 23) + #define DIV_R(A, B) (((int64_t)A << REAL_BITS) / B) + #define DIV_C(A, B) (((int64_t)A << COEF_BITS) / B) +/* Complex multiplication */ +static inline void ComplexMult(real_t* y1, real_t* y2, real_t x1, real_t x2, real_t c1, real_t c2) { // FIXED POINT + *y1 = (_MulHigh(x1, c1) + _MulHigh(x2, c2)) << (FRAC_SIZE - FRAC_BITS); + *y2 = (_MulHigh(x2, c1) - _MulHigh(x1, c2)) << (FRAC_SIZE - FRAC_BITS); +} +// static inline void ComplexMult(int32_t* y1, int32_t* y2, int32_t x1, int32_t x2, int32_t c1, int32_t c2) { // only XTENSA chips +// asm volatile ( +// // y1 = (x1 * c1) + (x2 * c2) +// "mulsh a2, %2, %4\n" // a2 = x1 * c1 (Low 32 bits) +// "mulsh a3, %3, %5\n" // a3 = x2 * c2 (Low 32 bits) +// "add a2, a2, a3\n" // a2 = (x1 * c1) + (x2 * c2) +// "slli a2, a2, 1\n" // a2 = a2 >> 31 (Fixed-Point scaling) +// "s32i a2, %0 \n" // Store result in *y1 +// // y2 = (x2 * c1) - (x1 * c2) +// "mulsh a2, %3, %4\n" // a2 = x2 * c1 (Low 32 bits) +// "mulsh a3, %2, %5\n" // a3 = x1 * c2 (Low 32 bits) +// "sub a2, a2, a3\n" // a2 = (x2 * c1) - (x1 * c2) +// "slli a2, a2, 1\n" // a2 = a2 >> 31 (Fixed-Point scaling) +// "s32i a2, %1 \n" // Store result in *y2 +// : "=m" (*y1), "=m" (*y2) // Output +// : "r" (x1), "r" (x2), "r" (c1), "r" (c2) // Input +// : "a2", "a3" // Clobbers +// ); +// } + + #define DIV(A, B) (((int64_t)A << REAL_BITS) / B) + #define step(shift) \ + if ((0x40000000l >> shift) + root <= value) { \ + value -= (0x40000000l >> shift) + root; \ + root = (root >> 1) | (0x40000000l >> shift); \ + } else { \ + root = root >> 1; \ + } + +real_t const pow2_table[] = {COEF_CONST(1.0), COEF_CONST(1.18920711500272), COEF_CONST(1.41421356237310), COEF_CONST(1.68179283050743)}; +#endif // FIXED_POINT +#ifndef FIXED_POINT + #ifdef MAIN_DEC + #define ALPHA REAL_CONST(0.90625) + #define A REAL_CONST(0.953125) + #endif + #define IQ_TABLE_SIZE 8192 + #define DIV_R(A, B) ((A) / (B)) + #define DIV_C(A, B) ((A) / (B)) + #ifdef USE_DOUBLE_PRECISION /* double */ +typedef double real_t; + #include + #define MUL_R(A, B) ((A) * (B)) + #define MUL_C(A, B) ((A) * (B)) + #define MUL_F(A, B) ((A) * (B)) + #define REAL_CONST(A) ((real_t)(A)) + #define COEF_CONST(A) ((real_t)(A)) + #define Q2_CONST(A) ((real_t)(A)) + #define FRAC_CONST(A) ((real_t)(A)) /* pure fractional part */ +/* Complex multiplication */ +static void ComplexMult(real_t* y1, real_t* y2, real_t x1, real_t x2, real_t c1, real_t c2) { + *y1 = MUL_F(x1, c1) + MUL_F(x2, c2); + *y2 = MUL_F(x2, c1) - MUL_F(x1, c2); +} + #else /* Normal floating point operation */ +typedef float real_t; + #define MUL_R(A, B) ((A) * (B)) + #define MUL_C(A, B) ((A) * (B)) + #define MUL_F(A, B) ((A) * (B)) + #define REAL_CONST(A) ((real_t)(A)) + #define COEF_CONST(A) ((real_t)(A)) + #define Q2_CONST(A) ((real_t)(A)) + #define FRAC_CONST(A) ((real_t)(A)) /* pure fractional part */ +/* Complex multiplication */ +__unused static void ComplexMult(real_t* y1, real_t* y2, real_t x1, real_t x2, real_t c1, real_t c2) { + *y1 = MUL_F(x1, c1) + MUL_F(x2, c2); + *y2 = MUL_F(x2, c1) - MUL_F(x1, c2); +} + + #endif /* USE_DOUBLE_PRECISION */ +#endif // FIXED_POINT + +#ifdef SBR_LOW_POWER + #define qmf_t real_t + #define QMF_RE(A) (A) + #define QMF_IM(A) +#else + #define qmf_t complex_t + #define QMF_RE(A) RE(A) + #define QMF_IM(A) IM(A) +#endif +typedef real_t complex_t[2]; +#define RE(A) A[0] +#define IM(A) A[1] + +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +#if !defined(max) && !defined(__cplusplus) + #define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#if !defined(min) && !defined(__cplusplus) + #define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef FAAD2_VERSION + #define FAAD2_VERSION "unknown" +#endif +/* object types for AAC */ +#define MAIN 1 +#define LC 2 +#define SSR 3 +#define LTP 4 +#define HE_AAC 5 +#define ER_LC 17 +#define ER_LTP 19 +#define LD 23 +#define DRM_ER_LC 27 /* special object type for DRM */ +/* header types */ +#define RAW 0 +#define ADIF 1 +#define ADTS 2 +#define LATM 3 +/* SBR signalling */ +#define NO_SBR 0 +#define SBR_UPSAMPLED 1 +#define SBR_DOWNSAMPLED 2 +#define NO_SBR_UPSAMPLED 3 +/* library output formats */ +#define FAAD_FMT_16BIT 1 +#define FAAD_FMT_24BIT 2 +#define FAAD_FMT_32BIT 3 +#define FAAD_FMT_FLOAT 4 +#define FAAD_FMT_FIXED FAAD_FMT_FLOAT +#define FAAD_FMT_DOUBLE 5 +/* Capabilities */ +#define LC_DEC_CAP (1 << 0) /* Can decode LC */ +#define MAIN_DEC_CAP (1 << 1) /* Can decode MAIN */ +#define LTP_DEC_CAP (1 << 2) /* Can decode LTP */ +#define LD_DEC_CAP (1 << 3) /* Can decode LD */ +#define ERROR_RESILIENCE_CAP (1 << 4) /* Can decode ER */ +#define FIXED_POINT_CAP (1 << 5) /* Fixed point */ +/* Channel definitions */ +#define FRONT_CHANNEL_CENTER (1) +#define FRONT_CHANNEL_LEFT (2) +#define FRONT_CHANNEL_RIGHT (3) +#define SIDE_CHANNEL_LEFT (4) +#define SIDE_CHANNEL_RIGHT (5) +#define BACK_CHANNEL_LEFT (6) +#define BACK_CHANNEL_RIGHT (7) +#define BACK_CHANNEL_CENTER (8) +#define LFE_CHANNEL (9) +#define UNKNOWN_CHANNEL (0) +/* DRM channel definitions */ +#define DRMCH_MONO 1 +#define DRMCH_STEREO 2 +#define DRMCH_SBR_MONO 3 +#define DRMCH_SBR_STEREO 4 +#define DRMCH_SBR_PS_STEREO 5 +/* A decode call can eat up to FAAD_MIN_STREAMSIZE bytes per decoded channel, + so at least so much bytes per channel should be available in this stream */ +#define FAAD_MIN_STREAMSIZE 768 /* 6144 bits/channel */ + +#define MAX_CHANNELS 64 +#define MAX_SYNTAX_ELEMENTS 48 +#define MAX_WINDOW_GROUPS 8 +#define MAX_SFB 51 +#define MAX_LTP_SFB 40 +#define MAX_LTP_SFB_S 8 +#define MAX_ASC_BYTES 64 + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT + #ifndef HAS_LRINTF + #define CLIP(sample, max, min) \ + if (sample >= 0.0f) { \ + sample += 0.5f; \ + if (sample >= max) sample = max; \ + } else { \ + sample += -0.5f; \ + if (sample <= min) sample = min; \ + } + #else + #define CLIP(sample, max, min) \ + if (sample >= 0.0f) { \ + if (sample >= max) sample = max; \ + } else { \ + if (sample <= min) sample = min; \ + } + #endif + #define CONV(a, b) ((a << 1) | (b & 0x1)) +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// Macro for comfortable calls +#define AAC_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AAC_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AAC_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AAC_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define AAC_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_settings.h b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_settings.h new file mode 100644 index 0000000..97578c2 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_settings.h @@ -0,0 +1,90 @@ +#pragma once + +/* ----------------------COMPILE TIME DEFINITIONS ---------------- */ +#define PREFER_POINTERS // Use if target platform has address generators with autoincrement +// #define BIG_IQ_TABLE +// #define USE_DOUBLE_PRECISION // use double precision +// #define FIXED_POINT // use fixed point reals, undefs MAIN_DEC and SSR_DEC +// #define ERROR_RESILIENCE 2 +// #define MAIN_DEC // Allow decoding of MAIN profile AAC +// #define SSR_DEC // Allow decoding of SSR profile AAC +#define LTP_DEC // Allow decoding of LTP (Long Term Prediction) profile AAC +#define LD_DEC // Allow decoding of LD (Low Delay) profile AAC +// #define DRM_SUPPORT // Allow decoding of Digital Radio Mondiale (DRM) +#if (defined CONFIG_IDF_TARGET_ESP32S3 || defined CONFIG_IDF_TARGET_ESP32P4) + #define SBR_DEC // Allow decoding of SBR (Spectral Band Replication) profile AAC + #define PS_DEC // Allow decoding of PS (Parametric Stereo) profile AAC +#endif +// #define SBR_LOW_POWER +#define ALLOW_SMALL_FRAMELENGTH +// #define LC_ONLY_DECODER // if you want a pure AAC LC decoder (independant of SBR_DEC and PS_DEC) +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +#ifdef DRM_SUPPORT // Allow decoding of Digital Radio Mondiale (DRM) + #define DRM + #define DRM_PS + #undef PS_DEC +#endif +#ifdef LD_DEC /* LD can't do without LTP */ + #ifndef ERROR_RESILIENCE + #define ERROR_RESILIENCE + #endif + #ifndef LTP_DEC + #define LTP_DEC + #endif +#endif +#ifdef LC_ONLY_DECODER + #undef LD_DEC + #undef LTP_DEC + #undef MAIN_DEC + #undef SSR_DEC + #undef DRM + #undef DRM_PS + #undef ALLOW_SMALL_FRAMELENGTH + #undef ERROR_RESILIENCE +#endif +#ifdef SBR_LOW_POWER + #undef PS_DEC +#endif +#ifdef FIXED_POINT /* No MAIN decoding */ + #ifdef MAIN_DEC + #undef MAIN_DEC + #endif +#endif // FIXED_POINT +#ifdef DRM + #ifndef ALLOW_SMALL_FRAMELENGTH + #define ALLOW_SMALL_FRAMELENGTH + #endif + #undef LD_DEC + #undef LTP_DEC + #undef MAIN_DEC + #undef SSR_DEC +#endif +/* END COMPILE TIME DEFINITIONS */ + + +#ifdef WORDS_BIGENDIAN + #define ARCH_IS_BIG_ENDIAN +#endif +/* FIXED_POINT doesn't work with MAIN and SSR yet */ +#ifdef FIXED_POINT + #undef MAIN_DEC + #undef SSR_DEC +#endif +#if defined(FIXED_POINT) +#elif defined(USE_DOUBLE_PRECISION) +#else /* Normal floating point operation */ + #ifdef HAVE_LRINTF + #define HAS_LRINTF + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + #define __USE_ISOC9X 1 + #define __USE_ISOC99 1 + #endif + + +#endif +#ifndef HAS_LRINTF +/* standard cast */ +// #define int32_t(f) ((int32_t)(f)) +#endif \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_structs.h b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_structs.h new file mode 100644 index 0000000..4124f96 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_structs.h @@ -0,0 +1,672 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: structs.h,v 1.49 2009/01/26 23:51:15 menno Exp $ +**/ +#pragma once +#include "Arduino.h" +#include "aac_defines.h" +#include "aac_settings.h" + +typedef void* NeAACDecHandle; +typedef struct mp4AudioSpecificConfig { + /* Audio Specific Info */ + unsigned char objectTypeIndex; + unsigned char samplingFrequencyIndex; + uint32_t samplingFrequency; + unsigned char channelsConfiguration; + /* GA Specific Info */ + unsigned char frameLengthFlag; + unsigned char dependsOnCoreCoder; + unsigned short coreCoderDelay; + unsigned char extensionFlag; + unsigned char aacSectionDataResilienceFlag; + unsigned char aacScalefactorDataResilienceFlag; + unsigned char aacSpectralDataResilienceFlag; + unsigned char epConfig; + char sbr_present_flag; + char forceUpSampling; + char downSampledSBR; +} mp4AudioSpecificConfig; +typedef struct NeAACDecFrameInfo { + uint32_t bytesconsumed; + uint32_t samples; + unsigned char channels; + unsigned char error; + uint32_t samplerate; + /* SBR: 0: off, 1: on; upsample, 2: on; downsampled, 3: off; upsampled */ + unsigned char sbr; + /* MPEG-4 ObjectType */ + unsigned char object_type; + /* AAC header type; MP4 will be signalled as RAW also */ + unsigned char header_type; + /* multichannel configuration */ + unsigned char num_front_channels; + unsigned char num_side_channels; + unsigned char num_back_channels; + unsigned char num_lfe_channels; + unsigned char channel_position[64]; + /* PS: 0: off, 1: on */ + unsigned char ps; + uint8_t isPS; +} NeAACDecFrameInfo; + +/* used to save the prediction state */ +typedef struct { + uint16_t n; + uint16_t ifac[15]; + complex_t* work; + complex_t* tab; +} cfft_info; +typedef struct { + int16_t r[2]; + int16_t COR[2]; + int16_t VAR[2]; +} pred_state; +typedef struct { + uint16_t N; + cfft_info* cfft; + complex_t* sincos; + int64_t cycles; + int64_t fft_cycles; +} mdct_info; +typedef struct { + const real_t* long_window[2]; + const real_t* short_window[2]; + const real_t* ld_window[2]; + int64_t cycles; +} fb_info; +typedef struct { + uint8_t present; + uint8_t num_bands; + uint8_t pce_instance_tag; + uint8_t excluded_chns_present; + uint8_t band_top[17]; + uint8_t prog_ref_level; + uint8_t dyn_rng_sgn[17]; + uint8_t dyn_rng_ctl[17]; + uint8_t exclude_mask[MAX_CHANNELS]; + uint8_t additional_excluded_chns[MAX_CHANNELS]; + real_t ctrl1; + real_t ctrl2; +} drc_info; +typedef struct { + uint8_t element_instance_tag; + uint8_t object_type; + uint8_t sf_index; + uint8_t num_front_channel_elements; + uint8_t num_side_channel_elements; + uint8_t num_back_channel_elements; + uint8_t num_lfe_channel_elements; + uint8_t num_assoc_data_elements; + uint8_t num_valid_cc_elements; + uint8_t mono_mixdown_present; + uint8_t mono_mixdown_element_number; + uint8_t stereo_mixdown_present; + uint8_t stereo_mixdown_element_number; + uint8_t matrix_mixdown_idx_present; + uint8_t pseudo_surround_enable; + uint8_t matrix_mixdown_idx; + uint8_t front_element_is_cpe[16]; + uint8_t front_element_tag_select[16]; + uint8_t side_element_is_cpe[16]; + uint8_t side_element_tag_select[16]; + uint8_t back_element_is_cpe[16]; + uint8_t back_element_tag_select[16]; + uint8_t lfe_element_tag_select[16]; + uint8_t assoc_data_element_tag_select[16]; + uint8_t cc_element_is_ind_sw[16]; + uint8_t valid_cc_element_tag_select[16]; + uint8_t channels; + uint8_t comment_field_bytes; + uint8_t comment_field_data[257]; + uint8_t num_front_channels; /* extra added values */ + uint8_t num_side_channels; + uint8_t num_back_channels; + uint8_t num_lfe_channels; + uint8_t sce_channel[16]; + uint8_t cpe_channel[16]; +} program_config; +typedef struct { + uint16_t syncword; + uint8_t id; + uint8_t layer; + uint8_t protection_absent; + uint8_t profile; + uint8_t sf_index; + uint8_t private_bit; + uint8_t channel_configuration; + uint8_t original; + uint8_t home; + uint8_t emphasis; + uint8_t copyright_identification_bit; + uint8_t copyright_identification_start; + uint16_t aac_frame_length; + uint16_t adts_buffer_fullness; + uint8_t no_raw_data_blocks_in_frame; + uint16_t crc_check; + uint8_t old_format; /* control param */ +} adts_header; +typedef struct { + uint8_t copyright_id_present; + int8_t copyright_id[10]; + uint8_t original_copy; + uint8_t home; + uint8_t bitstream_type; + uint32_t bitrate; + uint8_t num_program_config_elements; + uint32_t adif_buffer_fullness; + /* maximum of 16 PCEs */ + program_config pce[16]; +} adif_header; +typedef struct { + uint8_t last_band; + uint8_t data_present; + uint16_t lag; + uint8_t lag_update; + uint8_t coef; + uint8_t long_used[MAX_SFB]; + uint8_t short_used[8]; + uint8_t short_lag_present[8]; + uint8_t short_lag[8]; +} ltp_info; +typedef struct { + uint8_t limit; + uint8_t predictor_reset; + uint8_t predictor_reset_group_number; + uint8_t prediction_used[MAX_SFB]; +} pred_info; +typedef struct { + uint8_t number_pulse; + uint8_t pulse_start_sfb; + uint8_t pulse_offset[4]; + uint8_t pulse_amp[4]; +} pulse_info; +typedef struct { + uint8_t n_filt[8]; + uint8_t coef_res[8]; + uint8_t length[8][4]; + uint8_t order[8][4]; + uint8_t direction[8][4]; + uint8_t coef_compress[8][4]; + uint8_t coef[8][4][32]; +} tns_info; +typedef struct { + uint8_t max_band; + uint8_t adjust_num[4][8]; + uint8_t alevcode[4][8][8]; + uint8_t aloccode[4][8][8]; +} ssr_info; +typedef struct { + uint8_t max_sfb; + uint8_t num_swb; + uint8_t num_window_groups; + uint8_t num_windows; + uint8_t window_sequence; + uint8_t window_group_length[8]; + uint8_t window_shape; + uint8_t scale_factor_grouping; + uint16_t sect_sfb_offset[8][15 * 8]; + uint16_t swb_offset[52]; + uint16_t swb_offset_max; + uint8_t sect_cb[8][15 * 8]; + uint16_t sect_start[8][15 * 8]; + uint16_t sect_end[8][15 * 8]; + uint8_t sfb_cb[8][8 * 15]; + uint8_t num_sec[8]; /* number of sections in a group */ + uint8_t global_gain; + int16_t scale_factors[8][51]; /* [0..255] */ + uint8_t ms_mask_present; + uint8_t ms_used[MAX_WINDOW_GROUPS][MAX_SFB]; + uint8_t noise_used; + uint8_t is_used; + uint8_t pulse_data_present; + uint8_t tns_data_present; + uint8_t gain_control_data_present; + uint8_t predictor_data_present; + pulse_info pul; + tns_info tns; + pred_info pred; + ltp_info ltp; + ltp_info ltp2; + ssr_info ssr; + uint16_t length_of_reordered_spectral_data; /* ER HCR data */ + uint8_t length_of_longest_codeword; + uint8_t sf_concealment; /* ER RLVC data */ + uint8_t rev_global_gain; + uint16_t length_of_rvlc_sf; + uint16_t dpcm_noise_nrg; + uint8_t sf_escapes_present; + uint8_t length_of_rvlc_escapes; + uint16_t dpcm_noise_last_position; +} ic_stream; /* individual channel stream */ +typedef struct { + uint8_t channel; + int16_t paired_channel; + uint8_t element_instance_tag; + uint8_t common_window; + ic_stream ics1; + ic_stream ics2; +} element; /* syntax element (SCE, CPE, LFE) */ +typedef struct { + int inited; + int version, versionA; + int framelen_type; + int useSameStreamMux; + int allStreamsSameTimeFraming; + int numSubFrames; + int numPrograms; + int numLayers; + int otherDataPresent; + uint32_t otherDataLenBits; + uint32_t frameLength; + uint8_t ASC[MAX_ASC_BYTES]; + uint32_t ASCbits; +} latm_header; +typedef struct NeAACDecConfiguration { + unsigned char defObjectType; + unsigned long defSampleRate; + unsigned char outputFormat; + unsigned char downMatrix; + unsigned char useOldADTSFormat; + unsigned char dontUpSampleImplicitSBR; +} NeAACDecConfiguration, *NeAACDecConfigurationPtr; +typedef struct { + uint8_t drm_ps_data_available; + uint8_t bs_enable_sa; + uint8_t bs_enable_pan; + uint8_t bs_sa_dt_flag; + uint8_t bs_pan_dt_flag; + uint8_t g_last_had_sa; + uint8_t g_last_had_pan; + int8_t bs_sa_data[DRM_NUM_SA_BANDS]; + int8_t bs_pan_data[DRM_NUM_PAN_BANDS]; + int8_t g_sa_index[DRM_NUM_SA_BANDS]; + int8_t g_pan_index[DRM_NUM_PAN_BANDS]; + int8_t g_prev_sa_index[DRM_NUM_SA_BANDS]; + int8_t g_prev_pan_index[DRM_NUM_PAN_BANDS]; + int8_t sa_decode_error; + int8_t pan_decode_error; + int8_t g_last_good_sa_index[DRM_NUM_SA_BANDS]; + int8_t g_last_good_pan_index[DRM_NUM_PAN_BANDS]; + qmf_t SA[NUM_OF_SUBSAMPLES][MAX_SA_BAND]; + complex_t d_buff[2][MAX_SA_BAND]; + complex_t d2_buff[NUM_OF_LINKS][MAX_DELAY][MAX_SA_BAND]; + uint8_t delay_buf_index_ser[NUM_OF_LINKS]; + real_t prev_nrg[MAX_SA_BAND]; + real_t prev_peakdiff[MAX_SA_BAND]; + real_t peakdecay_fast[MAX_SA_BAND]; +} drm_ps_info; +typedef struct { + /* bitstream parameters */ + uint8_t enable_iid; + uint8_t enable_icc; + uint8_t enable_ext; + uint8_t iid_mode; + uint8_t icc_mode; + uint8_t nr_iid_par; + uint8_t nr_ipdopd_par; + uint8_t nr_icc_par; + uint8_t frame_class; + uint8_t num_env; + uint8_t border_position[MAX_PS_ENVELOPES + 1]; + uint8_t iid_dt[MAX_PS_ENVELOPES]; + uint8_t icc_dt[MAX_PS_ENVELOPES]; + uint8_t enable_ipdopd; + uint8_t ipd_mode; + uint8_t ipd_dt[MAX_PS_ENVELOPES]; + uint8_t opd_dt[MAX_PS_ENVELOPES]; + /* indices */ + int8_t iid_index_prev[34]; + int8_t icc_index_prev[34]; + int8_t ipd_index_prev[17]; + int8_t opd_index_prev[17]; + int8_t iid_index[MAX_PS_ENVELOPES][34]; + int8_t icc_index[MAX_PS_ENVELOPES][34]; + int8_t ipd_index[MAX_PS_ENVELOPES][17]; + int8_t opd_index[MAX_PS_ENVELOPES][17]; + int8_t ipd_index_1[17]; + int8_t opd_index_1[17]; + int8_t ipd_index_2[17]; + int8_t opd_index_2[17]; + /* ps data was correctly read */ + uint8_t ps_data_available; + /* a header has been read */ + uint8_t header_read; + /* hybrid filterbank parameters */ + void* hyb; + uint8_t use34hybrid_bands; + uint8_t numTimeSlotsRate; + /**/ + uint8_t num_groups; + uint8_t num_hybrid_groups; + uint8_t nr_par_bands; + uint8_t nr_allpass_bands; + uint8_t decay_cutoff; + uint8_t* group_border; + uint16_t* map_group2bk; + /* filter delay handling */ + uint8_t saved_delay; + uint8_t delay_buf_index_ser[NO_ALLPASS_LINKS]; + uint8_t num_sample_delay_ser[NO_ALLPASS_LINKS]; + uint8_t delay_D[64]; + uint8_t delay_buf_index_delay[64]; + complex_t delay_Qmf[14][64]; /* 14 samples delay max, 64 QMF channels */ + complex_t delay_SubQmf[2][32]; /* 2 samples delay max (SubQmf is always allpass filtered) */ + complex_t delay_Qmf_ser[NO_ALLPASS_LINKS][5][64]; /* 5 samples delay max (table 8.34), 64 QMF channels */ + complex_t delay_SubQmf_ser[NO_ALLPASS_LINKS][5][32]; /* 5 samples delay max (table 8.34) */ + /* transients */ + real_t alpha_decay; + real_t alpha_smooth; + real_t P_PeakDecayNrg[34]; + real_t P_prev[34]; + real_t P_SmoothPeakDecayDiffNrg_prev[34]; + /* mixing and phase */ + complex_t h11_prev[50]; + complex_t h12_prev[50]; + complex_t h21_prev[50]; + complex_t h22_prev[50]; + uint8_t phase_hist; + complex_t ipd_prev[20][2]; + complex_t opd_prev[20][2]; +} ps_info; +typedef struct { + real_t* x; + int16_t x_index; + uint8_t channels; +} qmfa_info; +typedef struct { + real_t* v; + int16_t v_index; + uint8_t channels; +} qmfs_info; +typedef struct { + uint32_t sample_rate; + uint32_t maxAACLine; + uint8_t rate; + uint8_t just_seeked; + uint8_t ret; + uint8_t amp_res[2]; + uint8_t k0; + uint8_t kx; + uint8_t M; + uint8_t N_master; + uint8_t N_high; + uint8_t N_low; + uint8_t N_Q; + uint8_t N_L[4]; + uint8_t n[2]; + uint8_t f_master[64]; + uint8_t f_table_res[2][64]; + uint8_t f_table_noise[64]; + uint8_t f_table_lim[4][64]; + uint8_t f_group[5][64]; + uint8_t N_G[5]; + uint8_t table_map_k_to_g[64]; + uint8_t abs_bord_lead[2]; + uint8_t abs_bord_trail[2]; + uint8_t n_rel_lead[2]; + uint8_t n_rel_trail[2]; + uint8_t L_E[2]; + uint8_t L_E_prev[2]; + uint8_t L_Q[2]; + uint8_t t_E[2][MAX_L_E + 1]; + uint8_t t_Q[2][3]; + uint8_t f[2][MAX_L_E + 1]; + uint8_t f_prev[2]; + real_t* G_temp_prev[2][5]; + real_t* Q_temp_prev[2][5]; + int8_t GQ_ringbuf_index[2]; + int16_t E[2][64][MAX_L_E]; + int16_t E_prev[2][64]; + real_t E_orig[2][64][MAX_L_E]; + real_t E_curr[2][64][MAX_L_E]; + int32_t Q[2][64][2]; + real_t Q_div[2][64][2]; + real_t Q_div2[2][64][2]; + int32_t Q_prev[2][64]; + int8_t l_A[2]; + int8_t l_A_prev[2]; + uint8_t bs_invf_mode[2][MAX_L_E]; + uint8_t bs_invf_mode_prev[2][MAX_L_E]; + real_t bwArray[2][64]; + real_t bwArray_prev[2][64]; + uint8_t noPatches; + uint8_t patchNoSubbands[64]; + uint8_t patchStartSubband[64]; + uint8_t bs_add_harmonic[2][64]; + uint8_t bs_add_harmonic_prev[2][64]; + uint16_t index_noise_prev[2]; + uint8_t psi_is_prev[2]; + uint8_t bs_start_freq_prev; + uint8_t bs_stop_freq_prev; + uint8_t bs_xover_band_prev; + uint8_t bs_freq_scale_prev; + uint8_t bs_alter_scale_prev; + uint8_t bs_noise_bands_prev; + int8_t prevEnvIsShort[2]; + int8_t kx_prev; + uint8_t bsco; + uint8_t bsco_prev; + uint8_t M_prev; + uint16_t frame_len; + uint8_t Reset; + uint32_t frame; + uint32_t header_count; + uint8_t id_aac; + qmfa_info* qmfa[2]; + qmfs_info* qmfs[2]; + qmf_t Xsbr[2][MAX_NTSRHFG][64]; + uint8_t Is_DRM_SBR; + drm_ps_info* drm_ps; + uint8_t numTimeSlotsRate; + uint8_t numTimeSlots; + uint8_t tHFGen; + uint8_t tHFAdj; + ps_info* ps; + uint8_t ps_used; + uint8_t psResetFlag; + /* to get it compiling */ + /* we'll see during the coding of all the tools, whether + these are all used or not. + */ + uint8_t bs_header_flag; + uint8_t bs_crc_flag; + uint16_t bs_sbr_crc_bits; + uint8_t bs_protocol_version; + uint8_t bs_amp_res; + uint8_t bs_start_freq; + uint8_t bs_stop_freq; + uint8_t bs_xover_band; + uint8_t bs_freq_scale; + uint8_t bs_alter_scale; + uint8_t bs_noise_bands; + uint8_t bs_limiter_bands; + uint8_t bs_limiter_gains; + uint8_t bs_interpol_freq; + uint8_t bs_smoothing_mode; + uint8_t bs_samplerate_mode; + uint8_t bs_add_harmonic_flag[2]; + uint8_t bs_add_harmonic_flag_prev[2]; + uint8_t bs_extended_data; + uint8_t bs_extension_id; + uint8_t bs_extension_data; + uint8_t bs_coupling; + uint8_t bs_frame_class[2]; + uint8_t bs_rel_bord[2][9]; + uint8_t bs_rel_bord_0[2][9]; + uint8_t bs_rel_bord_1[2][9]; + uint8_t bs_pointer[2]; + uint8_t bs_abs_bord_0[2]; + uint8_t bs_abs_bord_1[2]; + uint8_t bs_num_rel_0[2]; + uint8_t bs_num_rel_1[2]; + uint8_t bs_df_env[2][9]; + uint8_t bs_df_noise[2][3]; +} sbr_info; +typedef struct { + uint8_t adts_header_present; + uint8_t adif_header_present; + uint8_t latm_header_present; + uint8_t sf_index; + uint8_t object_type; + uint8_t channelConfiguration; + uint8_t aacSectionDataResilienceFlag; + uint8_t aacScalefactorDataResilienceFlag; + uint8_t aacSpectralDataResilienceFlag; + uint16_t frameLength; + uint8_t postSeekResetFlag; + uint32_t frame; + uint8_t downMatrix; + uint8_t upMatrix; + uint8_t first_syn_ele; + uint8_t has_lfe; + uint8_t fr_channels; /* number of channels in current frame */ + uint8_t fr_ch_ele; /* number of elements in current frame */ + uint8_t element_output_channels[MAX_SYNTAX_ELEMENTS]; /* element_output_channels: determines the number of channels the element will output */ + uint8_t element_alloced[MAX_SYNTAX_ELEMENTS]; /* element_alloced:determines whether the data needed for the element is allocated or not*/ + uint8_t alloced_channels; /* alloced_channels: determines the number of channels where output data is allocated for*/ + void* sample_buffer; /* output data buffer */ + uint8_t window_shape_prev[MAX_CHANNELS]; + uint16_t ltp_lag[MAX_CHANNELS]; + fb_info* fb; + drc_info* drc; + real_t* time_out[MAX_CHANNELS]; + real_t* fb_intermed[MAX_CHANNELS]; + int8_t sbr_present_flag; + int8_t forceUpSampling; + int8_t downSampledSBR; + uint8_t sbr_alloced[MAX_SYNTAX_ELEMENTS]; /* determines whether SBR data is allocated for the gives element */ + sbr_info* sbr[MAX_SYNTAX_ELEMENTS]; + uint8_t ps_used[MAX_SYNTAX_ELEMENTS]; + uint8_t ps_used_global; + real_t* ssr_overlap[MAX_CHANNELS]; + real_t* prev_fmd[MAX_CHANNELS]; + real_t ipqf_buffer[MAX_CHANNELS][4][96 / 4]; + pred_state* pred_stat[MAX_CHANNELS]; + int16_t* lt_pred_stat[MAX_CHANNELS]; + uint8_t error_state; + uint32_t __r1; /* RNG states */ + uint32_t __r2; + uint8_t pce_set; /* Program Config Element */ + program_config pce; + uint8_t element_id[MAX_CHANNELS]; + uint8_t internal_channel[MAX_CHANNELS]; + NeAACDecConfiguration config; /* Configuration data */ + int64_t cycles; + int64_t spectral_cycles; + int64_t output_cycles; + int64_t scalefac_cycles; + int64_t requant_cycles; + latm_header latm_config; + const uint8_t* cmes; + uint8_t isPS; +} NeAACDecStruct; +/* 1st step table */ +typedef struct { + uint8_t offset; + uint8_t extra_bits; +} hcb; +/* 2nd step table with quadruple data */ +typedef struct { + uint8_t bits; + int8_t x; + int8_t y; +} hcb_2_pair; +typedef struct { + uint8_t bits; + int8_t x; + int8_t y; + int8_t v; + int8_t w; +} hcb_2_quad; +/* binary search table */ +typedef struct { + uint8_t is_leaf; + int8_t data[4]; +} hcb_bin_quad; +typedef struct { + uint8_t is_leaf; + int8_t data[2]; +} hcb_bin_pair; +typedef struct _bitfile { + /* bit input */ + uint32_t bufa; + uint32_t bufb; + uint32_t bits_left; + uint32_t buffer_size; /* size of the buffer in bytes */ + uint32_t bytes_left; + uint8_t error; + uint32_t* tail; + uint32_t* start; + const void* buffer; +} bitfile; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +typedef struct { + /* bit input */ + uint32_t bufa; + uint32_t bufb; + int8_t len; +} bits_t; +typedef struct { + uint8_t cb; + uint8_t decoded; + uint16_t sp_offset; + bits_t bits; +} codeword_t; +typedef struct { + int8_t index; + uint8_t len; + uint32_t cw; +} rvlc_huff_table; +// ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* type definitions */ +typedef struct { + uint8_t frame_len; + uint8_t resolution20[3]; + uint8_t resolution34[5]; + qmf_t* work; + qmf_t** buffer; + qmf_t** temp; +} hyb_info; + +typedef struct { + real_t G_lim_boost[MAX_L_E][MAX_M]; + real_t Q_M_lim_boost[MAX_L_E][MAX_M]; + real_t S_M_boost[MAX_L_E][MAX_M]; +} sbr_hfadj_info; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +typedef struct { + complex_t r01; + complex_t r02; + complex_t r11; + complex_t r12; + complex_t r22; + real_t det; +} acorr_coef; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +typedef const int8_t (*ps_huff_tab)[2]; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_tables.h b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_tables.h new file mode 100644 index 0000000..d8fe469 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/aac_tables.h @@ -0,0 +1,23756 @@ +#pragma once +#pragma GCC diagnostic ignored "-Wunused-variable" +#include "aac_defines.h" +#include "aac_settings.h" +#include "aac_structs.h" + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const uint8_t tabFlipbits[256] = {0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* CRC lookup table for G8 polynome in DRM standard */ +static const uint8_t crc_table_G8[256] = { + 0x0, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e, 0x25, 0x38, 0x1f, 0x2, 0x51, 0x4c, 0x6b, 0x76, + 0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4, 0x6f, 0x72, 0x55, 0x48, 0x1b, 0x6, 0x21, 0x3c, 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x4, 0x19, 0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1, + 0x13, 0xe, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40, 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, 0xde, 0xc3, 0xe4, 0xf9, 0xaa, 0xb7, 0x90, 0x8d, 0x36, 0x2b, 0xc, 0x11, 0x42, 0x5f, 0x78, 0x65, + 0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, 0x7c, 0x61, 0x46, 0x5b, 0x8, 0x15, 0x32, 0x2f, 0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0xa, 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2, + 0x26, 0x3b, 0x1c, 0x1, 0x52, 0x4f, 0x68, 0x75, 0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d, 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, 0x3, 0x1e, 0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50, + 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2, 0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x7, 0x1a, 0x6c, 0x71, 0x56, 0x4b, 0x18, 0x5, 0x22, 0x3f, 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7, + 0x35, 0x28, 0xf, 0x12, 0x41, 0x5c, 0x7b, 0x66, 0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e, 0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab, 0x10, 0xd, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43, + 0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1, 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x9, 0x7f, 0x62, 0x45, 0x58, 0xb, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4, +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const uint8_t mes[] = {0x67, 0x20, 0x61, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x72, 0x20, 0x65, 0x20, 0x6e, 0x20, 0x20, 0x20, 0x74, + 0x20, 0x68, 0x20, 0x67, 0x20, 0x69, 0x20, 0x72, 0x20, 0x79, 0x20, 0x70, 0x20, 0x6f, 0x20, 0x63}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const uint8_t Parity[256] = { // parity + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; +/* + * This is a simple random number generator with good quality for audio purposes. + * It consists of two polycounters with opposite rotation direction and different + * periods. The periods are coprime, so the total period is the product of both. + * + * ------------------------------------------------------------------------------------------------- + * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| + * | ------------------------------------------------------------------------------------------------- + * | | | | | | | + * | +--+--+--+-XOR-+--------+ + * | | + * +--------------------------------------------------------------------------------------+ + * + * ------------------------------------------------------------------------------------------------- + * |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+ + * ------------------------------------------------------------------------------------------------- | + * | | | | | + * +--+----XOR----+--+ | + * | | + * +----------------------------------------------------------------------------------------+ + * + * + * The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481, + * which gives a period of 18.410.713.077.675.721.215. The result is the + * XORed values of both generators. + */ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +typedef enum { AAC_VERBOSE, AAC_DEBUG, AAC_INFO, AAC_WARN, AAC_ERROR } error_level_t; + +typedef struct { + const char* text; + error_level_t level; +} error_info_t; + +static error_info_t err_msg[] = { + {"No AAC_ERROR", AAC_ERROR}, /*0*/ + {"Gain control not yet implemented", AAC_ERROR}, /*1*/ + {"Pulse coding not allowed in short blocks", AAC_ERROR}, /*2*/ + {"Invalid huffman codebook", AAC_ERROR}, /*3*/ + {"Scalefactor out of range", AAC_ERROR}, /*4*/ + {"Unable to find ADTS syncword", AAC_ERROR}, /*5*/ + {"Channel coupling not yet implemented", AAC_ERROR}, /*6*/ + {"Channel configuration not allowed in AAC_ERROR resilient frame", AAC_ERROR}, /*7*/ + {"Bit AAC_ERROR in AAC_ERROR resilient scalefactor decoding", AAC_ERROR}, /*8*/ + {"AAC_ERROR decoding huffman scalefactor (bitstream AAC_ERROR)", AAC_ERROR}, /*9*/ + {"AAC_ERROR decoding huffman codeword (bitstream AAC_ERROR)", AAC_ERROR}, /*10*/ + {"Non existent huffman codebook number found", AAC_ERROR}, /*11*/ + {"Invalid number of channels", AAC_ERROR}, /*12*/ + {"Maximum number of bitstream elements exceeded", AAC_ERROR}, /*13*/ + {"Input data buffer too small", AAC_ERROR}, /*14*/ + {"Array index out of range", AAC_ERROR}, /*15*/ + {"Maximum number of scalefactor bands exceeded", AAC_ERROR}, /*16*/ + {"Quantised value out of range", AAC_ERROR}, /*17*/ + {"LTP lag out of range", AAC_ERROR}, /*18*/ + {"Invalid SBR parameter decoded", AAC_ERROR}, /*19*/ + {"SBR called without being initialised", AAC_ERROR}, /*20*/ + {"Unexpected channel configuration change", AAC_DEBUG}, /*21*/ + {"AAC_ERROR in program_config_element", AAC_ERROR}, /*22*/ + {"First SBR frame is not the same as first AAC frame", AAC_ERROR}, /*23*/ + {"Unexpected fill element with SBR data", AAC_ERROR}, /*24*/ + {"Not all elements were provided with SBR data", AAC_ERROR}, /*25*/ + {"LTP decoding not available", AAC_ERROR}, /*26*/ + {"Output data buffer too small", AAC_ERROR}, /*27*/ + {"CRC AAC_ERROR in DRM data", AAC_ERROR}, /*28*/ + {"PNS not allowed in DRM data stream", AAC_ERROR}, /*29*/ + {"No standard extension payload allowed in DRM", AAC_ERROR}, /*30*/ + {"PCE shall be the first element in a frame", AAC_ERROR}, /*31*/ + {"Bitstream value not allowed by specification", AAC_ERROR}, /*32*/ + {"MAIN prediction not initialised", AAC_ERROR}, /*33*/ + {"Unknown AAC_ERROR", AAC_ERROR}, /*34*/ +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT + #define TABLE_BITS 6 + /* just take the maximum number of bits for interpolation */ + #define INTERP_BITS (REAL_BITS - TABLE_BITS) +static const real_t pow2_tab[] = { + REAL_CONST(1.000000000000000), REAL_CONST(1.010889286051701), REAL_CONST(1.021897148654117), REAL_CONST(1.033024879021228), REAL_CONST(1.044273782427414), REAL_CONST(1.055645178360557), + REAL_CONST(1.067140400676824), REAL_CONST(1.078760797757120), REAL_CONST(1.090507732665258), REAL_CONST(1.102382583307841), REAL_CONST(1.114386742595892), REAL_CONST(1.126521618608242), + REAL_CONST(1.138788634756692), REAL_CONST(1.151189229952983), REAL_CONST(1.163724858777578), REAL_CONST(1.176396991650281), REAL_CONST(1.189207115002721), REAL_CONST(1.202156731452703), + REAL_CONST(1.215247359980469), REAL_CONST(1.228480536106870), REAL_CONST(1.241857812073484), REAL_CONST(1.255380757024691), REAL_CONST(1.269050957191733), REAL_CONST(1.282870016078778), + REAL_CONST(1.296839554651010), REAL_CONST(1.310961211524764), REAL_CONST(1.325236643159741), REAL_CONST(1.339667524053303), REAL_CONST(1.354255546936893), REAL_CONST(1.369002422974591), + REAL_CONST(1.383909881963832), REAL_CONST(1.398979672538311), REAL_CONST(1.414213562373095), REAL_CONST(1.429613338391970), REAL_CONST(1.445180806977047), REAL_CONST(1.460917794180647), + REAL_CONST(1.476826145939499), REAL_CONST(1.492907728291265), REAL_CONST(1.509164427593423), REAL_CONST(1.525598150744538), REAL_CONST(1.542210825407941), REAL_CONST(1.559004400237837), + REAL_CONST(1.575980845107887), REAL_CONST(1.593142151342267), REAL_CONST(1.610490331949254), REAL_CONST(1.628027421857348), REAL_CONST(1.645755478153965), REAL_CONST(1.663676580326736), + REAL_CONST(1.681792830507429), REAL_CONST(1.700106353718524), REAL_CONST(1.718619298122478), REAL_CONST(1.737333835273706), REAL_CONST(1.756252160373300), REAL_CONST(1.775376492526521), + REAL_CONST(1.794709075003107), REAL_CONST(1.814252175500399), REAL_CONST(1.834008086409342), REAL_CONST(1.853979125083386), REAL_CONST(1.874167634110300), REAL_CONST(1.894575981586966), + REAL_CONST(1.915206561397147), REAL_CONST(1.936061793492294), REAL_CONST(1.957144124175400), REAL_CONST(1.978456026387951), REAL_CONST(2.000000000000000)}; +static const real_t log2_tab[] = { + REAL_CONST(0.000000000000000), REAL_CONST(0.022367813028455), REAL_CONST(0.044394119358453), REAL_CONST(0.066089190457772), REAL_CONST(0.087462841250339), REAL_CONST(0.108524456778169), + REAL_CONST(0.129283016944966), REAL_CONST(0.149747119504682), REAL_CONST(0.169925001442312), REAL_CONST(0.189824558880017), REAL_CONST(0.209453365628950), REAL_CONST(0.228818690495881), + REAL_CONST(0.247927513443585), REAL_CONST(0.266786540694901), REAL_CONST(0.285402218862248), REAL_CONST(0.303780748177103), REAL_CONST(0.321928094887362), REAL_CONST(0.339850002884625), + REAL_CONST(0.357552004618084), REAL_CONST(0.375039431346925), REAL_CONST(0.392317422778760), REAL_CONST(0.409390936137702), REAL_CONST(0.426264754702098), REAL_CONST(0.442943495848728), + REAL_CONST(0.459431618637297), REAL_CONST(0.475733430966398), REAL_CONST(0.491853096329675), REAL_CONST(0.507794640198696), REAL_CONST(0.523561956057013), REAL_CONST(0.539158811108031), + REAL_CONST(0.554588851677637), REAL_CONST(0.569855608330948), REAL_CONST(0.584962500721156), REAL_CONST(0.599912842187128), REAL_CONST(0.614709844115208), REAL_CONST(0.629356620079610), + REAL_CONST(0.643856189774725), REAL_CONST(0.658211482751795), REAL_CONST(0.672425341971496), REAL_CONST(0.686500527183218), REAL_CONST(0.700439718141092), REAL_CONST(0.714245517666123), + REAL_CONST(0.727920454563199), REAL_CONST(0.741466986401147), REAL_CONST(0.754887502163469), REAL_CONST(0.768184324776926), REAL_CONST(0.781359713524660), REAL_CONST(0.794415866350106), + REAL_CONST(0.807354922057604), REAL_CONST(0.820178962415188), REAL_CONST(0.832890014164742), REAL_CONST(0.845490050944375), REAL_CONST(0.857980995127572), REAL_CONST(0.870364719583405), + REAL_CONST(0.882643049361841), REAL_CONST(0.894817763307943), REAL_CONST(0.906890595608519), REAL_CONST(0.918863237274595), REAL_CONST(0.930737337562886), REAL_CONST(0.942514505339240), + REAL_CONST(0.954196310386875), REAL_CONST(0.965784284662087), REAL_CONST(0.977279923499917), REAL_CONST(0.988684686772166), REAL_CONST(1.000000000000000)}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +static const complex_t cfft_tab_512[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999924719333649), FRAC_CONST(0.012271538376808)}, + {FRAC_CONST(0.999698817729950), FRAC_CONST(0.024541229009628)}, {FRAC_CONST(0.999322354793549), FRAC_CONST(0.036807224154472)}, + {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, {FRAC_CONST(0.998118102550507), FRAC_CONST(0.061320740729570)}, + {FRAC_CONST(0.997290432453156), FRAC_CONST(0.073564566671848)}, {FRAC_CONST(0.996312618255615), FRAC_CONST(0.085797317326069)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.993906974792480), FRAC_CONST(0.110222205519676)}, + {FRAC_CONST(0.992479562759399), FRAC_CONST(0.122410677373409)}, {FRAC_CONST(0.990902662277222), FRAC_CONST(0.134580716490746)}, + {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, {FRAC_CONST(0.987301409244537), FRAC_CONST(0.158858150243759)}, + {FRAC_CONST(0.985277652740479), FRAC_CONST(0.170961901545525)}, {FRAC_CONST(0.983105480670929), FRAC_CONST(0.183039888739586)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.978317379951477), FRAC_CONST(0.207111388444901)}, + {FRAC_CONST(0.975702106952667), FRAC_CONST(0.219101235270500)}, {FRAC_CONST(0.972939968109131), FRAC_CONST(0.231058120727539)}, + {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, {FRAC_CONST(0.966976463794708), FRAC_CONST(0.254865676164627)}, + {FRAC_CONST(0.963776051998138), FRAC_CONST(0.266712784767151)}, {FRAC_CONST(0.960430502891541), FRAC_CONST(0.278519690036774)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.953306019306183), FRAC_CONST(0.302005946636200)}, + {FRAC_CONST(0.949528157711029), FRAC_CONST(0.313681751489639)}, {FRAC_CONST(0.945607304573059), FRAC_CONST(0.325310319662094)}, + {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, {FRAC_CONST(0.937339007854462), FRAC_CONST(0.348418682813644)}, + {FRAC_CONST(0.932992815971375), FRAC_CONST(0.359895050525665)}, {FRAC_CONST(0.928506076335907), FRAC_CONST(0.371317207813263)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.919113874435425), FRAC_CONST(0.393992066383362)}, + {FRAC_CONST(0.914209723472595), FRAC_CONST(0.405241340398788)}, {FRAC_CONST(0.909167945384979), FRAC_CONST(0.416429579257965)}, + {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, {FRAC_CONST(0.898674488067627), FRAC_CONST(0.438616245985031)}, + {FRAC_CONST(0.893224298954010), FRAC_CONST(0.449611335992813)}, {FRAC_CONST(0.887639641761780), FRAC_CONST(0.460538715124130)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.876070082187653), FRAC_CONST(0.482183754444122)}, + {FRAC_CONST(0.870086967945099), FRAC_CONST(0.492898225784302)}, {FRAC_CONST(0.863972842693329), FRAC_CONST(0.503538370132446)}, + {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, {FRAC_CONST(0.851355195045471), FRAC_CONST(0.524589717388153)}, + {FRAC_CONST(0.844853579998016), FRAC_CONST(0.534997642040253)}, {FRAC_CONST(0.838224709033966), FRAC_CONST(0.545324981212616)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.824589252471924), FRAC_CONST(0.565731823444366)}, + {FRAC_CONST(0.817584812641144), FRAC_CONST(0.575808227062225)}, {FRAC_CONST(0.810457170009613), FRAC_CONST(0.585797905921936)}, + {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, {FRAC_CONST(0.795836925506592), FRAC_CONST(0.605511009693146)}, + {FRAC_CONST(0.788346409797668), FRAC_CONST(0.615231633186340)}, {FRAC_CONST(0.780737221240997), FRAC_CONST(0.624859511852264)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.765167236328125), FRAC_CONST(0.643831551074982)}, + {FRAC_CONST(0.757208824157715), FRAC_CONST(0.653172850608826)}, {FRAC_CONST(0.749136388301849), FRAC_CONST(0.662415802478790)}, + {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, {FRAC_CONST(0.732654273509979), FRAC_CONST(0.680601000785828)}, + {FRAC_CONST(0.724247097969055), FRAC_CONST(0.689540565013886)}, {FRAC_CONST(0.715730786323547), FRAC_CONST(0.698376297950745)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.698376238346100), FRAC_CONST(0.715730845928192)}, + {FRAC_CONST(0.689540505409241), FRAC_CONST(0.724247097969055)}, {FRAC_CONST(0.680601000785828), FRAC_CONST(0.732654273509979)}, + {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, {FRAC_CONST(0.662415742874146), FRAC_CONST(0.749136388301849)}, + {FRAC_CONST(0.653172791004181), FRAC_CONST(0.757208883762360)}, {FRAC_CONST(0.643831551074982), FRAC_CONST(0.765167295932770)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.624859452247620), FRAC_CONST(0.780737280845642)}, + {FRAC_CONST(0.615231573581696), FRAC_CONST(0.788346409797668)}, {FRAC_CONST(0.605511009693146), FRAC_CONST(0.795836925506592)}, + {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(0.585797846317291), FRAC_CONST(0.810457170009613)}, + {FRAC_CONST(0.575808167457581), FRAC_CONST(0.817584812641144)}, {FRAC_CONST(0.565731823444366), FRAC_CONST(0.824589312076569)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.545324981212616), FRAC_CONST(0.838224709033966)}, + {FRAC_CONST(0.534997642040253), FRAC_CONST(0.844853579998016)}, {FRAC_CONST(0.524589657783508), FRAC_CONST(0.851355195045471)}, + {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, {FRAC_CONST(0.503538429737091), FRAC_CONST(0.863972842693329)}, + {FRAC_CONST(0.492898195981979), FRAC_CONST(0.870086967945099)}, {FRAC_CONST(0.482183724641800), FRAC_CONST(0.876070141792297)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.460538715124130), FRAC_CONST(0.887639641761780)}, + {FRAC_CONST(0.449611306190491), FRAC_CONST(0.893224298954010)}, {FRAC_CONST(0.438616186380386), FRAC_CONST(0.898674488067627)}, + {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, {FRAC_CONST(0.416429549455643), FRAC_CONST(0.909168004989624)}, + {FRAC_CONST(0.405241280794144), FRAC_CONST(0.914209783077240)}, {FRAC_CONST(0.393991947174072), FRAC_CONST(0.919113874435425)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.371317148208618), FRAC_CONST(0.928506076335907)}, + {FRAC_CONST(0.359894961118698), FRAC_CONST(0.932992815971375)}, {FRAC_CONST(0.348418682813644), FRAC_CONST(0.937339007854462)}, + {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(0.325310230255127), FRAC_CONST(0.945607364177704)}, + {FRAC_CONST(0.313681662082672), FRAC_CONST(0.949528217315674)}, {FRAC_CONST(0.302005946636200), FRAC_CONST(0.953306019306183)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.278519600629807), FRAC_CONST(0.960430562496185)}, + {FRAC_CONST(0.266712754964828), FRAC_CONST(0.963776051998138)}, {FRAC_CONST(0.254865646362305), FRAC_CONST(0.966976463794708)}, + {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(0.231058135628700), FRAC_CONST(0.972939968109131)}, + {FRAC_CONST(0.219101220369339), FRAC_CONST(0.975702106952667)}, {FRAC_CONST(0.207111328840256), FRAC_CONST(0.978317379951477)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.183039888739586), FRAC_CONST(0.983105480670929)}, + {FRAC_CONST(0.170961856842041), FRAC_CONST(0.985277652740479)}, {FRAC_CONST(0.158858075737953), FRAC_CONST(0.987301409244537)}, + {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, {FRAC_CONST(0.134580686688423), FRAC_CONST(0.990902662277222)}, + {FRAC_CONST(0.122410625219345), FRAC_CONST(0.992479562759399)}, {FRAC_CONST(0.110222116112709), FRAC_CONST(0.993906974792480)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.085797272622585), FRAC_CONST(0.996312618255615)}, + {FRAC_CONST(0.073564492166042), FRAC_CONST(0.997290432453156)}, {FRAC_CONST(0.061320748180151), FRAC_CONST(0.998118102550507)}, + {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(0.036807164549828), FRAC_CONST(0.999322414398193)}, + {FRAC_CONST(0.024541135877371), FRAC_CONST(0.999698817729950)}, {FRAC_CONST(0.012271529063582), FRAC_CONST(0.999924719333649)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.012271616607904), FRAC_CONST(0.999924719333649)}, + {FRAC_CONST(-0.024541223421693), FRAC_CONST(0.999698817729950)}, {FRAC_CONST(-0.036807250231504), FRAC_CONST(0.999322354793549)}, + {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(-0.061320833861828), FRAC_CONST(0.998118102550507)}, + {FRAC_CONST(-0.073564574122429), FRAC_CONST(0.997290432453156)}, {FRAC_CONST(-0.085797362029552), FRAC_CONST(0.996312618255615)}, + {FRAC_CONST(-0.098017223179340), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(-0.110222205519676), FRAC_CONST(0.993906974792480)}, + {FRAC_CONST(-0.122410707175732), FRAC_CONST(0.992479503154755)}, {FRAC_CONST(-0.134580776095390), FRAC_CONST(0.990902602672577)}, + {FRAC_CONST(-0.146730571985245), FRAC_CONST(0.989176511764526)}, {FRAC_CONST(-0.158858165144920), FRAC_CONST(0.987301409244537)}, + {FRAC_CONST(-0.170961946249008), FRAC_CONST(0.985277652740479)}, {FRAC_CONST(-0.183039978146553), FRAC_CONST(0.983105480670929)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.207111418247223), FRAC_CONST(0.978317379951477)}, + {FRAC_CONST(-0.219101309776306), FRAC_CONST(0.975702106952667)}, {FRAC_CONST(-0.231058210134506), FRAC_CONST(0.972939908504486)}, + {FRAC_CONST(-0.242980197072029), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(-0.254865705966949), FRAC_CONST(0.966976463794708)}, + {FRAC_CONST(-0.266712844371796), FRAC_CONST(0.963776051998138)}, {FRAC_CONST(-0.278519690036774), FRAC_CONST(0.960430502891541)}, + {FRAC_CONST(-0.290284723043442), FRAC_CONST(0.956940293312073)}, {FRAC_CONST(-0.302006036043167), FRAC_CONST(0.953306019306183)}, + {FRAC_CONST(-0.313681721687317), FRAC_CONST(0.949528157711029)}, {FRAC_CONST(-0.325310319662094), FRAC_CONST(0.945607304573059)}, + {FRAC_CONST(-0.336889922618866), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(-0.348418772220612), FRAC_CONST(0.937338948249817)}, + {FRAC_CONST(-0.359895050525665), FRAC_CONST(0.932992815971375)}, {FRAC_CONST(-0.371317237615585), FRAC_CONST(0.928506076335907)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.393992036581039), FRAC_CONST(0.919113874435425)}, + {FRAC_CONST(-0.405241340398788), FRAC_CONST(0.914209723472595)}, {FRAC_CONST(-0.416429519653320), FRAC_CONST(0.909168004989624)}, + {FRAC_CONST(-0.427555084228516), FRAC_CONST(0.903989315032959)}, {FRAC_CONST(-0.438616245985031), FRAC_CONST(0.898674428462982)}, + {FRAC_CONST(-0.449611365795136), FRAC_CONST(0.893224298954010)}, {FRAC_CONST(-0.460538804531097), FRAC_CONST(0.887639582157135)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.482183903455734), FRAC_CONST(0.876070022583008)}, + {FRAC_CONST(-0.492898166179657), FRAC_CONST(0.870087027549744)}, {FRAC_CONST(-0.503538370132446), FRAC_CONST(0.863972842693329)}, + {FRAC_CONST(-0.514102756977081), FRAC_CONST(0.857728600502014)}, {FRAC_CONST(-0.524589717388153), FRAC_CONST(0.851355135440826)}, + {FRAC_CONST(-0.534997701644897), FRAC_CONST(0.844853520393372)}, {FRAC_CONST(-0.545325100421906), FRAC_CONST(0.838224649429321)}, + {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, {FRAC_CONST(-0.565731763839722), FRAC_CONST(0.824589312076569)}, + {FRAC_CONST(-0.575808167457581), FRAC_CONST(0.817584812641144)}, {FRAC_CONST(-0.585797905921936), FRAC_CONST(0.810457170009613)}, + {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(-0.605511128902435), FRAC_CONST(0.795836865901947)}, + {FRAC_CONST(-0.615231692790985), FRAC_CONST(0.788346350193024)}, {FRAC_CONST(-0.624859631061554), FRAC_CONST(0.780737102031708)}, + {FRAC_CONST(-0.634393274784088), FRAC_CONST(0.773010492324829)}, {FRAC_CONST(-0.643831551074982), FRAC_CONST(0.765167236328125)}, + {FRAC_CONST(-0.653172850608826), FRAC_CONST(0.757208824157715)}, {FRAC_CONST(-0.662415802478790), FRAC_CONST(0.749136328697205)}, + {FRAC_CONST(-0.671559035778046), FRAC_CONST(0.740951061248779)}, {FRAC_CONST(-0.680601119995117), FRAC_CONST(0.732654154300690)}, + {FRAC_CONST(-0.689540684223175), FRAC_CONST(0.724246978759766)}, {FRAC_CONST(-0.698376238346100), FRAC_CONST(0.715730845928192)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.715730845928192), FRAC_CONST(0.698376238346100)}, + {FRAC_CONST(-0.724247157573700), FRAC_CONST(0.689540505409241)}, {FRAC_CONST(-0.732654333114624), FRAC_CONST(0.680600941181183)}, + {FRAC_CONST(-0.740951240062714), FRAC_CONST(0.671558856964111)}, {FRAC_CONST(-0.749136507511139), FRAC_CONST(0.662415623664856)}, + {FRAC_CONST(-0.757208824157715), FRAC_CONST(0.653172850608826)}, {FRAC_CONST(-0.765167295932770), FRAC_CONST(0.643831551074982)}, + {FRAC_CONST(-0.773010492324829), FRAC_CONST(0.634393274784088)}, {FRAC_CONST(-0.780737280845642), FRAC_CONST(0.624859452247620)}, + {FRAC_CONST(-0.788346469402313), FRAC_CONST(0.615231513977051)}, {FRAC_CONST(-0.795836985111237), FRAC_CONST(0.605510950088501)}, + {FRAC_CONST(-0.803207635879517), FRAC_CONST(0.595699131488800)}, {FRAC_CONST(-0.810457170009613), FRAC_CONST(0.585797846317291)}, + {FRAC_CONST(-0.817584812641144), FRAC_CONST(0.575808167457581)}, {FRAC_CONST(-0.824589312076569), FRAC_CONST(0.565731763839722)}, + {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, {FRAC_CONST(-0.838224768638611), FRAC_CONST(0.545324862003326)}, + {FRAC_CONST(-0.844853639602661), FRAC_CONST(0.534997463226318)}, {FRAC_CONST(-0.851355314254761), FRAC_CONST(0.524589538574219)}, + {FRAC_CONST(-0.857728600502014), FRAC_CONST(0.514102756977081)}, {FRAC_CONST(-0.863972842693329), FRAC_CONST(0.503538370132446)}, + {FRAC_CONST(-0.870087027549744), FRAC_CONST(0.492898136377335)}, {FRAC_CONST(-0.876070141792297), FRAC_CONST(0.482183694839478)}, + {FRAC_CONST(-0.881921350955963), FRAC_CONST(0.471396625041962)}, {FRAC_CONST(-0.887639701366425), FRAC_CONST(0.460538566112518)}, + {FRAC_CONST(-0.893224298954010), FRAC_CONST(0.449611365795136)}, {FRAC_CONST(-0.898674488067627), FRAC_CONST(0.438616245985031)}, + {FRAC_CONST(-0.903989315032959), FRAC_CONST(0.427555054426193)}, {FRAC_CONST(-0.909168004989624), FRAC_CONST(0.416429489850998)}, + {FRAC_CONST(-0.914209783077240), FRAC_CONST(0.405241221189499)}, {FRAC_CONST(-0.919113874435425), FRAC_CONST(0.393991917371750)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.928506076335907), FRAC_CONST(0.371317237615585)}, + {FRAC_CONST(-0.932992815971375), FRAC_CONST(0.359895050525665)}, {FRAC_CONST(-0.937339007854462), FRAC_CONST(0.348418653011322)}, + {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, {FRAC_CONST(-0.945607364177704), FRAC_CONST(0.325310200452805)}, + {FRAC_CONST(-0.949528217315674), FRAC_CONST(0.313681602478027)}, {FRAC_CONST(-0.953306078910828), FRAC_CONST(0.302005797624588)}, + {FRAC_CONST(-0.956940352916718), FRAC_CONST(0.290284723043442)}, {FRAC_CONST(-0.960430502891541), FRAC_CONST(0.278519690036774)}, + {FRAC_CONST(-0.963776051998138), FRAC_CONST(0.266712725162506)}, {FRAC_CONST(-0.966976463794708), FRAC_CONST(0.254865586757660)}, + {FRAC_CONST(-0.970031261444092), FRAC_CONST(0.242980077862740)}, {FRAC_CONST(-0.972939968109131), FRAC_CONST(0.231057971715927)}, + {FRAC_CONST(-0.975702166557312), FRAC_CONST(0.219101071357727)}, {FRAC_CONST(-0.978317379951477), FRAC_CONST(0.207111403346062)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.983105480670929), FRAC_CONST(0.183039844036102)}, + {FRAC_CONST(-0.985277652740479), FRAC_CONST(0.170961812138557)}, {FRAC_CONST(-0.987301409244537), FRAC_CONST(0.158858031034470)}, + {FRAC_CONST(-0.989176511764526), FRAC_CONST(0.146730333566666)}, {FRAC_CONST(-0.990902662277222), FRAC_CONST(0.134580522775650)}, + {FRAC_CONST(-0.992479503154755), FRAC_CONST(0.122410699725151)}, {FRAC_CONST(-0.993906974792480), FRAC_CONST(0.110222198069096)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(0.098017096519470)}, {FRAC_CONST(-0.996312618255615), FRAC_CONST(0.085797227919102)}, + {FRAC_CONST(-0.997290492057800), FRAC_CONST(0.073564447462559)}, {FRAC_CONST(-0.998118102550507), FRAC_CONST(0.061320584267378)}, + {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067486077547)}, {FRAC_CONST(-0.999322354793549), FRAC_CONST(0.036807239055634)}, + {FRAC_CONST(-0.999698817729950), FRAC_CONST(0.024541210383177)}, {FRAC_CONST(-0.999924719333649), FRAC_CONST(0.012271485291421)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999698817729950), FRAC_CONST(0.024541229009628)}, + {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, {FRAC_CONST(0.997290432453156), FRAC_CONST(0.073564566671848)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.992479562759399), FRAC_CONST(0.122410677373409)}, + {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, {FRAC_CONST(0.985277652740479), FRAC_CONST(0.170961901545525)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.975702106952667), FRAC_CONST(0.219101235270500)}, + {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, {FRAC_CONST(0.963776051998138), FRAC_CONST(0.266712784767151)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.949528157711029), FRAC_CONST(0.313681751489639)}, + {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, {FRAC_CONST(0.932992815971375), FRAC_CONST(0.359895050525665)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.914209723472595), FRAC_CONST(0.405241340398788)}, + {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, {FRAC_CONST(0.893224298954010), FRAC_CONST(0.449611335992813)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.870086967945099), FRAC_CONST(0.492898225784302)}, + {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, {FRAC_CONST(0.844853579998016), FRAC_CONST(0.534997642040253)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.817584812641144), FRAC_CONST(0.575808227062225)}, + {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, {FRAC_CONST(0.788346409797668), FRAC_CONST(0.615231633186340)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.757208824157715), FRAC_CONST(0.653172850608826)}, + {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, {FRAC_CONST(0.724247097969055), FRAC_CONST(0.689540565013886)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.689540505409241), FRAC_CONST(0.724247097969055)}, + {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, {FRAC_CONST(0.653172791004181), FRAC_CONST(0.757208883762360)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.615231573581696), FRAC_CONST(0.788346409797668)}, + {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(0.575808167457581), FRAC_CONST(0.817584812641144)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.534997642040253), FRAC_CONST(0.844853579998016)}, + {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, {FRAC_CONST(0.492898195981979), FRAC_CONST(0.870086967945099)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.449611306190491), FRAC_CONST(0.893224298954010)}, + {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, {FRAC_CONST(0.405241280794144), FRAC_CONST(0.914209783077240)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.359894961118698), FRAC_CONST(0.932992815971375)}, + {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(0.313681662082672), FRAC_CONST(0.949528217315674)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.266712754964828), FRAC_CONST(0.963776051998138)}, + {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(0.219101220369339), FRAC_CONST(0.975702106952667)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.170961856842041), FRAC_CONST(0.985277652740479)}, + {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, {FRAC_CONST(0.122410625219345), FRAC_CONST(0.992479562759399)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.073564492166042), FRAC_CONST(0.997290432453156)}, + {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(0.024541135877371), FRAC_CONST(0.999698817729950)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.098017223179340), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(-0.146730571985245), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.242980197072029), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(-0.290284723043442), FRAC_CONST(0.956940293312073)}, {FRAC_CONST(-0.336889922618866), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.427555084228516), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.514102756977081), FRAC_CONST(0.857728600502014)}, + {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(-0.634393274784088), FRAC_CONST(0.773010492324829)}, {FRAC_CONST(-0.671559035778046), FRAC_CONST(0.740951061248779)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.740951240062714), FRAC_CONST(0.671558856964111)}, + {FRAC_CONST(-0.773010492324829), FRAC_CONST(0.634393274784088)}, {FRAC_CONST(-0.803207635879517), FRAC_CONST(0.595699131488800)}, + {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, {FRAC_CONST(-0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(-0.881921350955963), FRAC_CONST(0.471396625041962)}, {FRAC_CONST(-0.903989315032959), FRAC_CONST(0.427555054426193)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, + {FRAC_CONST(-0.956940352916718), FRAC_CONST(0.290284723043442)}, {FRAC_CONST(-0.970031261444092), FRAC_CONST(0.242980077862740)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.989176511764526), FRAC_CONST(0.146730333566666)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(0.098017096519470)}, {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067486077547)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.997290432453156), FRAC_CONST(0.073564566671848)}, + {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, {FRAC_CONST(0.975702106952667), FRAC_CONST(0.219101235270500)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.932992815971375), FRAC_CONST(0.359895050525665)}, + {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, {FRAC_CONST(0.870086967945099), FRAC_CONST(0.492898225784302)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.788346469402313), FRAC_CONST(0.615231573581696)}, + {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, {FRAC_CONST(0.689540505409241), FRAC_CONST(0.724247097969055)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.575808227062225), FRAC_CONST(0.817584812641144)}, + {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, {FRAC_CONST(0.449611306190491), FRAC_CONST(0.893224298954010)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.313681751489639), FRAC_CONST(0.949528157711029)}, + {FRAC_CONST(0.242980241775513), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(0.170961856842041), FRAC_CONST(0.985277652740479)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.024541255086660), FRAC_CONST(0.999698817729950)}, + {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(-0.122410707175732), FRAC_CONST(0.992479503154755)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.266712725162506), FRAC_CONST(0.963776051998138)}, + {FRAC_CONST(-0.336889803409576), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(-0.405241340398788), FRAC_CONST(0.914209723472595)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.534997701644897), FRAC_CONST(0.844853520393372)}, + {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(-0.653172850608826), FRAC_CONST(0.757208824157715)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.757208824157715), FRAC_CONST(0.653172850608826)}, + {FRAC_CONST(-0.803207516670227), FRAC_CONST(0.595699369907379)}, {FRAC_CONST(-0.844853520393372), FRAC_CONST(0.534997701644897)}, + {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, {FRAC_CONST(-0.914209783077240), FRAC_CONST(0.405241221189499)}, + {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, {FRAC_CONST(-0.963776051998138), FRAC_CONST(0.266712725162506)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.992479503154755), FRAC_CONST(0.122410699725151)}, + {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067724496126)}, {FRAC_CONST(-0.999698817729950), FRAC_CONST(-0.024541147053242)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, {FRAC_CONST(-0.985277652740479), FRAC_CONST(-0.170961990952492)}, + {FRAC_CONST(-0.970031261444092), FRAC_CONST(-0.242980241775513)}, {FRAC_CONST(-0.949528157711029), FRAC_CONST(-0.313681781291962)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.893224298954010), FRAC_CONST(-0.449611306190491)}, + {FRAC_CONST(-0.857728660106659), FRAC_CONST(-0.514102697372437)}, {FRAC_CONST(-0.817584872245789), FRAC_CONST(-0.575808107852936)}, + {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, {FRAC_CONST(-0.724247038364410), FRAC_CONST(-0.689540624618530)}, + {FRAC_CONST(-0.671558916568756), FRAC_CONST(-0.740951180458069)}, {FRAC_CONST(-0.615231573581696), FRAC_CONST(-0.788346469402313)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.492898195981979), FRAC_CONST(-0.870086967945099)}, + {FRAC_CONST(-0.427554935216904), FRAC_CONST(-0.903989374637604)}, {FRAC_CONST(-0.359895110130310), FRAC_CONST(-0.932992756366730)}, + {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, {FRAC_CONST(-0.219101369380951), FRAC_CONST(-0.975702106952667)}, + {FRAC_CONST(-0.146730408072472), FRAC_CONST(-0.989176511764526)}, {FRAC_CONST(-0.073564760386944), FRAC_CONST(-0.997290432453156)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.000000011924881), FRAC_CONST(-1.000000000000000)}}; +#endif // FIXED_POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT + #ifdef ALLOW_SMALL_FRAMELENGTH +static const complex_t cfft_tab_480[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999914348125458), FRAC_CONST(0.013089596293867)}, + {FRAC_CONST(0.999657332897186), FRAC_CONST(0.026176949962974)}, {FRAC_CONST(0.999229013919830), FRAC_CONST(0.039259817451239)}, + {FRAC_CONST(0.998629510402679), FRAC_CONST(0.052335958927870)}, {FRAC_CONST(0.997858941555023), FRAC_CONST(0.065403133630753)}, + {FRAC_CONST(0.996917307376862), FRAC_CONST(0.078459098935127)}, {FRAC_CONST(0.995804905891418), FRAC_CONST(0.091501623392105)}, + {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, {FRAC_CONST(0.993068456649780), FRAC_CONST(0.117537401616573)}, + {FRAC_CONST(0.991444885730743), FRAC_CONST(0.130526199936867)}, {FRAC_CONST(0.989651381969452), FRAC_CONST(0.143492624163628)}, + {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, {FRAC_CONST(0.985556066036224), FRAC_CONST(0.169349506497383)}, + {FRAC_CONST(0.983254909515381), FRAC_CONST(0.182235524058342)}, {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.975342333316803), FRAC_CONST(0.220697447657585)}, + {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, {FRAC_CONST(0.969230890274048), FRAC_CONST(0.246153295040131)}, + {FRAC_CONST(0.965925812721252), FRAC_CONST(0.258819043636322)}, {FRAC_CONST(0.962455213069916), FRAC_CONST(0.271440446376801)}, + {FRAC_CONST(0.958819746971130), FRAC_CONST(0.284015357494354)}, {FRAC_CONST(0.955019950866699), FRAC_CONST(0.296541601419449)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.946930110454559), FRAC_CONST(0.321439445018768)}, + {FRAC_CONST(0.942641496658325), FRAC_CONST(0.333806872367859)}, {FRAC_CONST(0.938191354274750), FRAC_CONST(0.346117079257965)}, + {FRAC_CONST(0.933580398559570), FRAC_CONST(0.358367949724197)}, {FRAC_CONST(0.928809583187103), FRAC_CONST(0.370557427406311)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.918791174888611), FRAC_CONST(0.394743889570236)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.908143162727356), FRAC_CONST(0.418659746646881)}, + {FRAC_CONST(0.902585268020630), FRAC_CONST(0.430511116981506)}, {FRAC_CONST(0.896872758865356), FRAC_CONST(0.442288726568222)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.884987652301788), FRAC_CONST(0.465614527463913)}, + {FRAC_CONST(0.878817081451416), FRAC_CONST(0.477158784866333)}, {FRAC_CONST(0.872496008872986), FRAC_CONST(0.488621264696121)}, + {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, {FRAC_CONST(0.859406411647797), FRAC_CONST(0.511293113231659)}, + {FRAC_CONST(0.852640151977539), FRAC_CONST(0.522498548030853)}, {FRAC_CONST(0.845727801322937), FRAC_CONST(0.533614516258240)}, + {FRAC_CONST(0.838670551776886), FRAC_CONST(0.544639050960541)}, {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, + {FRAC_CONST(0.824126183986664), FRAC_CONST(0.566406250000000)}, {FRAC_CONST(0.816641509532928), FRAC_CONST(0.577145218849182)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.801253795623779), FRAC_CONST(0.598324596881866)}, + {FRAC_CONST(0.793353319168091), FRAC_CONST(0.608761429786682)}, {FRAC_CONST(0.785316884517670), FRAC_CONST(0.619093954563141)}, + {FRAC_CONST(0.777145922183990), FRAC_CONST(0.629320383071899)}, {FRAC_CONST(0.768841803073883), FRAC_CONST(0.639438986778259)}, + {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, {FRAC_CONST(0.751839756965637), FRAC_CONST(0.659345865249634)}, + {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, {FRAC_CONST(0.734322488307953), FRAC_CONST(0.678800761699677)}, + {FRAC_CONST(0.725374400615692), FRAC_CONST(0.688354551792145)}, {FRAC_CONST(0.716301918029785), FRAC_CONST(0.697790503501892)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.697790443897247), FRAC_CONST(0.716301977634430)}, + {FRAC_CONST(0.688354551792145), FRAC_CONST(0.725374400615692)}, {FRAC_CONST(0.678800702095032), FRAC_CONST(0.734322547912598)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.659345805644989), FRAC_CONST(0.751839816570282)}, + {FRAC_CONST(0.649448037147522), FRAC_CONST(0.760405957698822)}, {FRAC_CONST(0.639438986778259), FRAC_CONST(0.768841862678528)}, + {FRAC_CONST(0.629320383071899), FRAC_CONST(0.777145981788635)}, {FRAC_CONST(0.619093954563141), FRAC_CONST(0.785316944122314)}, + {FRAC_CONST(0.608761370182037), FRAC_CONST(0.793353378772736)}, {FRAC_CONST(0.598324596881866), FRAC_CONST(0.801253855228424)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.577145159244537), FRAC_CONST(0.816641569137573)}, + {FRAC_CONST(0.566406250000000), FRAC_CONST(0.824126183986664)}, {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, + {FRAC_CONST(0.544638991355896), FRAC_CONST(0.838670611381531)}, {FRAC_CONST(0.533614516258240), FRAC_CONST(0.845727801322937)}, + {FRAC_CONST(0.522498488426209), FRAC_CONST(0.852640211582184)}, {FRAC_CONST(0.511293113231659), FRAC_CONST(0.859406411647797)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.488621175289154), FRAC_CONST(0.872496068477631)}, + {FRAC_CONST(0.477158755064011), FRAC_CONST(0.878817141056061)}, {FRAC_CONST(0.465614467859268), FRAC_CONST(0.884987652301788)}, + {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, {FRAC_CONST(0.442288666963577), FRAC_CONST(0.896872758865356)}, + {FRAC_CONST(0.430511027574539), FRAC_CONST(0.902585327625275)}, {FRAC_CONST(0.418659746646881), FRAC_CONST(0.908143162727356)}, + {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, {FRAC_CONST(0.394743800163269), FRAC_CONST(0.918791234493256)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.370557397603989), FRAC_CONST(0.928809583187103)}, + {FRAC_CONST(0.358367860317230), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(0.346117049455643), FRAC_CONST(0.938191354274750)}, + {FRAC_CONST(0.333806812763214), FRAC_CONST(0.942641496658325)}, {FRAC_CONST(0.321439474821091), FRAC_CONST(0.946930110454559)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.296541512012482), FRAC_CONST(0.955019950866699)}, + {FRAC_CONST(0.284015327692032), FRAC_CONST(0.958819746971130)}, {FRAC_CONST(0.271440386772156), FRAC_CONST(0.962455272674561)}, + {FRAC_CONST(0.258819073438644), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(0.246153265237808), FRAC_CONST(0.969230890274048)}, + {FRAC_CONST(0.233445301651955), FRAC_CONST(0.972369909286499)}, {FRAC_CONST(0.220697447657585), FRAC_CONST(0.975342333316803)}, + {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, + {FRAC_CONST(0.182235524058342), FRAC_CONST(0.983254909515381)}, {FRAC_CONST(0.169349446892738), FRAC_CONST(0.985556066036224)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(0.143492594361305), FRAC_CONST(0.989651381969452)}, + {FRAC_CONST(0.130526125431061), FRAC_CONST(0.991444885730743)}, {FRAC_CONST(0.117537401616573), FRAC_CONST(0.993068456649780)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(0.091501533985138), FRAC_CONST(0.995804905891418)}, + {FRAC_CONST(0.078459084033966), FRAC_CONST(0.996917307376862)}, {FRAC_CONST(0.065403074026108), FRAC_CONST(0.997858941555023)}, + {FRAC_CONST(0.052335973829031), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(0.039259787648916), FRAC_CONST(0.999229013919830)}, + {FRAC_CONST(0.026176875457168), FRAC_CONST(0.999657332897186)}, {FRAC_CONST(0.013089597225189), FRAC_CONST(0.999914348125458)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.013089684769511), FRAC_CONST(0.999914348125458)}, + {FRAC_CONST(-0.026176963001490), FRAC_CONST(0.999657332897186)}, {FRAC_CONST(-0.039259877055883), FRAC_CONST(0.999229013919830)}, + {FRAC_CONST(-0.052336059510708), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(-0.065403163433075), FRAC_CONST(0.997858941555023)}, + {FRAC_CONST(-0.078459173440933), FRAC_CONST(0.996917307376862)}, {FRAC_CONST(-0.091501623392105), FRAC_CONST(0.995804905891418)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.117537491023541), FRAC_CONST(0.993068456649780)}, + {FRAC_CONST(-0.130526214838028), FRAC_CONST(0.991444885730743)}, {FRAC_CONST(-0.143492683768272), FRAC_CONST(0.989651381969452)}, + {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(-0.169349536299706), FRAC_CONST(0.985556066036224)}, + {FRAC_CONST(-0.182235598564148), FRAC_CONST(0.983254909515381)}, {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, + {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, {FRAC_CONST(-0.220697522163391), FRAC_CONST(0.975342273712158)}, + {FRAC_CONST(-0.233445391058922), FRAC_CONST(0.972369909286499)}, {FRAC_CONST(-0.246153354644775), FRAC_CONST(0.969230890274048)}, + {FRAC_CONST(-0.258819162845612), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(-0.271440476179123), FRAC_CONST(0.962455213069916)}, + {FRAC_CONST(-0.284015417098999), FRAC_CONST(0.958819687366486)}, {FRAC_CONST(-0.296541571617126), FRAC_CONST(0.955019950866699)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.321439564228058), FRAC_CONST(0.946930110454559)}, + {FRAC_CONST(-0.333806872367859), FRAC_CONST(0.942641496658325)}, {FRAC_CONST(-0.346117109060287), FRAC_CONST(0.938191294670105)}, + {FRAC_CONST(-0.358367949724197), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(-0.370557487010956), FRAC_CONST(0.928809523582459)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.394743859767914), FRAC_CONST(0.918791234493256)}, + {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, {FRAC_CONST(-0.418659836053848), FRAC_CONST(0.908143103122711)}, + {FRAC_CONST(-0.430511116981506), FRAC_CONST(0.902585268020630)}, {FRAC_CONST(-0.442288637161255), FRAC_CONST(0.896872758865356)}, + {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, {FRAC_CONST(-0.465614557266235), FRAC_CONST(0.884987592697144)}, + {FRAC_CONST(-0.477158725261688), FRAC_CONST(0.878817141056061)}, {FRAC_CONST(-0.488621354103088), FRAC_CONST(0.872495949268341)}, + {FRAC_CONST(-0.500000059604645), FRAC_CONST(0.866025388240814)}, {FRAC_CONST(-0.511293053627014), FRAC_CONST(0.859406411647797)}, + {FRAC_CONST(-0.522498667240143), FRAC_CONST(0.852640092372894)}, {FRAC_CONST(-0.533614575862885), FRAC_CONST(0.845727801322937)}, + {FRAC_CONST(-0.544639050960541), FRAC_CONST(0.838670551776886)}, {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, + {FRAC_CONST(-0.566406309604645), FRAC_CONST(0.824126124382019)}, {FRAC_CONST(-0.577145218849182), FRAC_CONST(0.816641569137573)}, + {FRAC_CONST(-0.587785184383392), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(-0.598324656486511), FRAC_CONST(0.801253736019135)}, + {FRAC_CONST(-0.608761429786682), FRAC_CONST(0.793353319168091)}, {FRAC_CONST(-0.619093894958496), FRAC_CONST(0.785316944122314)}, + {FRAC_CONST(-0.629320502281189), FRAC_CONST(0.777145862579346)}, {FRAC_CONST(-0.639439046382904), FRAC_CONST(0.768841803073883)}, + {FRAC_CONST(-0.649448037147522), FRAC_CONST(0.760405957698822)}, {FRAC_CONST(-0.659345924854279), FRAC_CONST(0.751839697360992)}, + {FRAC_CONST(-0.669130682945251), FRAC_CONST(0.743144810199738)}, {FRAC_CONST(-0.678800761699677), FRAC_CONST(0.734322488307953)}, + {FRAC_CONST(-0.688354671001434), FRAC_CONST(0.725374281406403)}, {FRAC_CONST(-0.697790503501892), FRAC_CONST(0.716301858425140)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.716302037239075), FRAC_CONST(0.697790324687958)}, + {FRAC_CONST(-0.725374460220337), FRAC_CONST(0.688354492187500)}, {FRAC_CONST(-0.734322547912598), FRAC_CONST(0.678800702095032)}, + {FRAC_CONST(-0.743144929409027), FRAC_CONST(0.669130444526672)}, {FRAC_CONST(-0.751839876174927), FRAC_CONST(0.659345746040344)}, + {FRAC_CONST(-0.760406017303467), FRAC_CONST(0.649448037147522)}, {FRAC_CONST(-0.768841803073883), FRAC_CONST(0.639439046382904)}, + {FRAC_CONST(-0.777146041393280), FRAC_CONST(0.629320263862610)}, {FRAC_CONST(-0.785316944122314), FRAC_CONST(0.619093894958496)}, + {FRAC_CONST(-0.793353319168091), FRAC_CONST(0.608761429786682)}, {FRAC_CONST(-0.801253914833069), FRAC_CONST(0.598324477672577)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.816641569137573), FRAC_CONST(0.577145218849182)}, + {FRAC_CONST(-0.824126303195953), FRAC_CONST(0.566406130790710)}, {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, + {FRAC_CONST(-0.838670551776886), FRAC_CONST(0.544639050960541)}, {FRAC_CONST(-0.845727920532227), FRAC_CONST(0.533614337444305)}, + {FRAC_CONST(-0.852640211582184), FRAC_CONST(0.522498488426209)}, {FRAC_CONST(-0.859406411647797), FRAC_CONST(0.511293053627014)}, + {FRAC_CONST(-0.866025388240814), FRAC_CONST(0.500000059604645)}, {FRAC_CONST(-0.872496068477631), FRAC_CONST(0.488621145486832)}, + {FRAC_CONST(-0.878817141056061), FRAC_CONST(0.477158725261688)}, {FRAC_CONST(-0.884987652301788), FRAC_CONST(0.465614557266235)}, + {FRAC_CONST(-0.891006588935852), FRAC_CONST(0.453990370035172)}, {FRAC_CONST(-0.896872758865356), FRAC_CONST(0.442288637161255)}, + {FRAC_CONST(-0.902585268020630), FRAC_CONST(0.430511116981506)}, {FRAC_CONST(-0.908143222332001), FRAC_CONST(0.418659597635269)}, + {FRAC_CONST(-0.913545489311218), FRAC_CONST(0.406736582517624)}, {FRAC_CONST(-0.918791234493256), FRAC_CONST(0.394743859767914)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.928809583187103), FRAC_CONST(0.370557337999344)}, + {FRAC_CONST(-0.933580458164215), FRAC_CONST(0.358367919921875)}, {FRAC_CONST(-0.938191413879395), FRAC_CONST(0.346116900444031)}, + {FRAC_CONST(-0.942641556262970), FRAC_CONST(0.333806753158569)}, {FRAC_CONST(-0.946930170059204), FRAC_CONST(0.321439445018768)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.955020010471344), FRAC_CONST(0.296541452407837)}, + {FRAC_CONST(-0.958819746971130), FRAC_CONST(0.284015297889709)}, {FRAC_CONST(-0.962455213069916), FRAC_CONST(0.271440476179123)}, + {FRAC_CONST(-0.965925872325897), FRAC_CONST(0.258818924427032)}, {FRAC_CONST(-0.969230949878693), FRAC_CONST(0.246153235435486)}, + {FRAC_CONST(-0.972369909286499), FRAC_CONST(0.233445376157761)}, {FRAC_CONST(-0.975342333316803), FRAC_CONST(0.220697283744812)}, + {FRAC_CONST(-0.978147625923157), FRAC_CONST(0.207911610603333)}, {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, + {FRAC_CONST(-0.983254909515381), FRAC_CONST(0.182235360145569)}, {FRAC_CONST(-0.985556066036224), FRAC_CONST(0.169349402189255)}, + {FRAC_CONST(-0.987688362598419), FRAC_CONST(0.156434446573257)}, {FRAC_CONST(-0.989651441574097), FRAC_CONST(0.143492430448532)}, + {FRAC_CONST(-0.991444885730743), FRAC_CONST(0.130526080727577)}, {FRAC_CONST(-0.993068456649780), FRAC_CONST(0.117537356913090)}, + {FRAC_CONST(-0.994521915912628), FRAC_CONST(0.104528494179249)}, {FRAC_CONST(-0.995804965496063), FRAC_CONST(0.091501489281654)}, + {FRAC_CONST(-0.996917366981506), FRAC_CONST(0.078459039330482)}, {FRAC_CONST(-0.997858941555023), FRAC_CONST(0.065403148531914)}, + {FRAC_CONST(-0.998629570007324), FRAC_CONST(0.052335809916258)}, {FRAC_CONST(-0.999229013919830), FRAC_CONST(0.039259742945433)}, + {FRAC_CONST(-0.999657332897186), FRAC_CONST(0.026176951825619)}, {FRAC_CONST(-0.999914348125458), FRAC_CONST(0.013089434243739)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999657332897186), FRAC_CONST(0.026176949962974)}, + {FRAC_CONST(0.998629510402679), FRAC_CONST(0.052335958927870)}, {FRAC_CONST(0.996917307376862), FRAC_CONST(0.078459098935127)}, + {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, {FRAC_CONST(0.991444885730743), FRAC_CONST(0.130526199936867)}, + {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, {FRAC_CONST(0.983254909515381), FRAC_CONST(0.182235524058342)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.965925812721252), FRAC_CONST(0.258819043636322)}, {FRAC_CONST(0.958819746971130), FRAC_CONST(0.284015357494354)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.942641496658325), FRAC_CONST(0.333806872367859)}, + {FRAC_CONST(0.933580398559570), FRAC_CONST(0.358367949724197)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.902585268020630), FRAC_CONST(0.430511116981506)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.878817081451416), FRAC_CONST(0.477158784866333)}, + {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, {FRAC_CONST(0.852640151977539), FRAC_CONST(0.522498548030853)}, + {FRAC_CONST(0.838670551776886), FRAC_CONST(0.544639050960541)}, {FRAC_CONST(0.824126183986664), FRAC_CONST(0.566406250000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.793353319168091), FRAC_CONST(0.608761429786682)}, + {FRAC_CONST(0.777145922183990), FRAC_CONST(0.629320383071899)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, {FRAC_CONST(0.725374400615692), FRAC_CONST(0.688354551792145)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.688354551792145), FRAC_CONST(0.725374400615692)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.649448037147522), FRAC_CONST(0.760405957698822)}, + {FRAC_CONST(0.629320383071899), FRAC_CONST(0.777145981788635)}, {FRAC_CONST(0.608761370182037), FRAC_CONST(0.793353378772736)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.566406250000000), FRAC_CONST(0.824126183986664)}, + {FRAC_CONST(0.544638991355896), FRAC_CONST(0.838670611381531)}, {FRAC_CONST(0.522498488426209), FRAC_CONST(0.852640211582184)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.477158755064011), FRAC_CONST(0.878817141056061)}, + {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, {FRAC_CONST(0.430511027574539), FRAC_CONST(0.902585327625275)}, + {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.358367860317230), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(0.333806812763214), FRAC_CONST(0.942641496658325)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.284015327692032), FRAC_CONST(0.958819746971130)}, + {FRAC_CONST(0.258819073438644), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(0.233445301651955), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, {FRAC_CONST(0.182235524058342), FRAC_CONST(0.983254909515381)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(0.130526125431061), FRAC_CONST(0.991444885730743)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(0.078459084033966), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(0.052335973829031), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(0.026176875457168), FRAC_CONST(0.999657332897186)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.026176963001490), FRAC_CONST(0.999657332897186)}, + {FRAC_CONST(-0.052336059510708), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(-0.078459173440933), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.130526214838028), FRAC_CONST(0.991444885730743)}, + {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(-0.182235598564148), FRAC_CONST(0.983254909515381)}, + {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, {FRAC_CONST(-0.233445391058922), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(-0.258819162845612), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(-0.284015417098999), FRAC_CONST(0.958819687366486)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.333806872367859), FRAC_CONST(0.942641496658325)}, + {FRAC_CONST(-0.358367949724197), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, {FRAC_CONST(-0.430511116981506), FRAC_CONST(0.902585268020630)}, + {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, {FRAC_CONST(-0.477158725261688), FRAC_CONST(0.878817141056061)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.998629510402679), FRAC_CONST(0.052335958927870)}, + {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.965925812721252), FRAC_CONST(0.258819043636322)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.933580398559570), FRAC_CONST(0.358367949724197)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, + {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, {FRAC_CONST(0.838670551776886), FRAC_CONST(0.544639050960541)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.777145922183990), FRAC_CONST(0.629320383071899)}, + {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.629320383071899), FRAC_CONST(0.777145981788635)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.544638991355896), FRAC_CONST(0.838670611381531)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, + {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, {FRAC_CONST(0.358367860317230), FRAC_CONST(0.933580458164215)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.258819073438644), FRAC_CONST(0.965925812721252)}, + {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(0.052335973829031), FRAC_CONST(0.998629510402679)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.052336059510708), FRAC_CONST(0.998629510402679)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, {FRAC_CONST(-0.258819162845612), FRAC_CONST(0.965925812721252)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.358367949724197), FRAC_CONST(0.933580458164215)}, + {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, + {FRAC_CONST(-0.500000059604645), FRAC_CONST(0.866025388240814)}, {FRAC_CONST(-0.544639050960541), FRAC_CONST(0.838670551776886)}, + {FRAC_CONST(-0.587785184383392), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(-0.629320502281189), FRAC_CONST(0.777145862579346)}, + {FRAC_CONST(-0.669130682945251), FRAC_CONST(0.743144810199738)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.743144929409027), FRAC_CONST(0.669130444526672)}, {FRAC_CONST(-0.777146041393280), FRAC_CONST(0.629320263862610)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.838670551776886), FRAC_CONST(0.544639050960541)}, + {FRAC_CONST(-0.866025388240814), FRAC_CONST(0.500000059604645)}, {FRAC_CONST(-0.891006588935852), FRAC_CONST(0.453990370035172)}, + {FRAC_CONST(-0.913545489311218), FRAC_CONST(0.406736582517624)}, {FRAC_CONST(-0.933580458164215), FRAC_CONST(0.358367919921875)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.965925872325897), FRAC_CONST(0.258818924427032)}, + {FRAC_CONST(-0.978147625923157), FRAC_CONST(0.207911610603333)}, {FRAC_CONST(-0.987688362598419), FRAC_CONST(0.156434446573257)}, + {FRAC_CONST(-0.994521915912628), FRAC_CONST(0.104528494179249)}, {FRAC_CONST(-0.998629570007324), FRAC_CONST(0.052335809916258)}, + {FRAC_CONST(-1.000000000000000), FRAC_CONST(-0.000000087422777)}, {FRAC_CONST(-0.998629510402679), FRAC_CONST(-0.052335985004902)}, + {FRAC_CONST(-0.994521856307983), FRAC_CONST(-0.104528672993183)}, {FRAC_CONST(-0.987688302993774), FRAC_CONST(-0.156434610486031)}, + {FRAC_CONST(-0.978147566318512), FRAC_CONST(-0.207911789417267)}, {FRAC_CONST(-0.965925812721252), FRAC_CONST(-0.258819073438644)}, + {FRAC_CONST(-0.951056540012360), FRAC_CONST(-0.309016972780228)}, {FRAC_CONST(-0.933580398559570), FRAC_CONST(-0.358368098735809)}, + {FRAC_CONST(-0.913545429706573), FRAC_CONST(-0.406736731529236)}, {FRAC_CONST(-0.891006529331207), FRAC_CONST(-0.453990548849106)}, + {FRAC_CONST(-0.866025269031525), FRAC_CONST(-0.500000178813934)}, {FRAC_CONST(-0.838670492172241), FRAC_CONST(-0.544639170169830)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(-0.777145922183990), FRAC_CONST(-0.629320442676544)}, + {FRAC_CONST(-0.743144810199738), FRAC_CONST(-0.669130623340607)}, {FRAC_CONST(-0.707106649875641), FRAC_CONST(-0.707106888294220)}, + {FRAC_CONST(-0.669130504131317), FRAC_CONST(-0.743144869804382)}, {FRAC_CONST(-0.629320323467255), FRAC_CONST(-0.777145981788635)}, + {FRAC_CONST(-0.587785065174103), FRAC_CONST(-0.809017121791840)}, {FRAC_CONST(-0.544639110565186), FRAC_CONST(-0.838670551776886)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.996917307376862), FRAC_CONST(0.078459098935127)}, + {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.852640151977539), FRAC_CONST(0.522498548030853)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.649448037147522), FRAC_CONST(0.760405957698822)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.522498488426209), FRAC_CONST(0.852640211582184)}, + {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.233445301651955), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(0.078459084033966), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, + {FRAC_CONST(-0.587785184383392), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.891006588935852), FRAC_CONST(0.453990370035172)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.987688362598419), FRAC_CONST(0.156434446573257)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(-0.078459173440933), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.522498667240143), FRAC_CONST(0.852640092372894)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.852640211582184), FRAC_CONST(0.522498488426209)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.996917366981506), FRAC_CONST(0.078459039330482)}, + {FRAC_CONST(-0.987688302993774), FRAC_CONST(-0.156434610486031)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(-0.649447917938232), FRAC_CONST(-0.760406076908112)}, + {FRAC_CONST(-0.453990221023560), FRAC_CONST(-0.891006648540497)}, {FRAC_CONST(-0.233445450663567), FRAC_CONST(-0.972369909286499)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.309017121791840), FRAC_CONST(-0.951056480407715)}}; + #endif // ALLOW_SMALL_FRAMELENGTH +#endif // FIXED_POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +static const complex_t cfft_tab_64[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.000000011924881), FRAC_CONST(-1.000000000000000)}}; +#endif // FIXED POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT + #ifdef ALLOW_SMALL_FRAMELENGTH +static const complex_t cfft_tab_60[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, + {FRAC_CONST(-0.500000059604645), FRAC_CONST(0.866025388240814)}, {FRAC_CONST(-0.669130682945251), FRAC_CONST(0.743144810199738)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.913545489311218), FRAC_CONST(0.406736582517624)}, + {FRAC_CONST(-0.978147625923157), FRAC_CONST(0.207911610603333)}, {FRAC_CONST(-1.000000000000000), FRAC_CONST(-0.000000087422777)}, + {FRAC_CONST(-0.978147566318512), FRAC_CONST(-0.207911789417267)}, {FRAC_CONST(-0.913545429706573), FRAC_CONST(-0.406736731529236)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(-0.669130504131317), FRAC_CONST(-0.743144869804382)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.309017121791840), FRAC_CONST(-0.951056480407715)}}; + #endif // ALLOW_SMALL_FRAMELENGTH +#endif // FIXED POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT + #ifdef LD_DEC +static const complex_t cfft_tab_256[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999698817729950), FRAC_CONST(0.024541229009628)}, + {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, {FRAC_CONST(0.997290432453156), FRAC_CONST(0.073564566671848)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.992479562759399), FRAC_CONST(0.122410677373409)}, + {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, {FRAC_CONST(0.985277652740479), FRAC_CONST(0.170961901545525)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.975702106952667), FRAC_CONST(0.219101235270500)}, + {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, {FRAC_CONST(0.963776051998138), FRAC_CONST(0.266712784767151)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.949528157711029), FRAC_CONST(0.313681751489639)}, + {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, {FRAC_CONST(0.932992815971375), FRAC_CONST(0.359895050525665)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.914209723472595), FRAC_CONST(0.405241340398788)}, + {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, {FRAC_CONST(0.893224298954010), FRAC_CONST(0.449611335992813)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.870086967945099), FRAC_CONST(0.492898225784302)}, + {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, {FRAC_CONST(0.844853579998016), FRAC_CONST(0.534997642040253)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.817584812641144), FRAC_CONST(0.575808227062225)}, + {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, {FRAC_CONST(0.788346409797668), FRAC_CONST(0.615231633186340)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.757208824157715), FRAC_CONST(0.653172850608826)}, + {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, {FRAC_CONST(0.724247097969055), FRAC_CONST(0.689540565013886)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.689540505409241), FRAC_CONST(0.724247097969055)}, + {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, {FRAC_CONST(0.653172791004181), FRAC_CONST(0.757208883762360)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.615231573581696), FRAC_CONST(0.788346409797668)}, + {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(0.575808167457581), FRAC_CONST(0.817584812641144)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.534997642040253), FRAC_CONST(0.844853579998016)}, + {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, {FRAC_CONST(0.492898195981979), FRAC_CONST(0.870086967945099)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.449611306190491), FRAC_CONST(0.893224298954010)}, + {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, {FRAC_CONST(0.405241280794144), FRAC_CONST(0.914209783077240)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.359894961118698), FRAC_CONST(0.932992815971375)}, + {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(0.313681662082672), FRAC_CONST(0.949528217315674)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.266712754964828), FRAC_CONST(0.963776051998138)}, + {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(0.219101220369339), FRAC_CONST(0.975702106952667)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.170961856842041), FRAC_CONST(0.985277652740479)}, + {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, {FRAC_CONST(0.122410625219345), FRAC_CONST(0.992479562759399)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.073564492166042), FRAC_CONST(0.997290432453156)}, + {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(0.024541135877371), FRAC_CONST(0.999698817729950)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.098017223179340), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(-0.146730571985245), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.242980197072029), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(-0.290284723043442), FRAC_CONST(0.956940293312073)}, {FRAC_CONST(-0.336889922618866), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.427555084228516), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.514102756977081), FRAC_CONST(0.857728600502014)}, + {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(-0.634393274784088), FRAC_CONST(0.773010492324829)}, {FRAC_CONST(-0.671559035778046), FRAC_CONST(0.740951061248779)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.740951240062714), FRAC_CONST(0.671558856964111)}, + {FRAC_CONST(-0.773010492324829), FRAC_CONST(0.634393274784088)}, {FRAC_CONST(-0.803207635879517), FRAC_CONST(0.595699131488800)}, + {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, {FRAC_CONST(-0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(-0.881921350955963), FRAC_CONST(0.471396625041962)}, {FRAC_CONST(-0.903989315032959), FRAC_CONST(0.427555054426193)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, + {FRAC_CONST(-0.956940352916718), FRAC_CONST(0.290284723043442)}, {FRAC_CONST(-0.970031261444092), FRAC_CONST(0.242980077862740)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.989176511764526), FRAC_CONST(0.146730333566666)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(0.098017096519470)}, {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067486077547)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.997290432453156), FRAC_CONST(0.073564566671848)}, + {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, {FRAC_CONST(0.975702106952667), FRAC_CONST(0.219101235270500)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.932992815971375), FRAC_CONST(0.359895050525665)}, + {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, {FRAC_CONST(0.870086967945099), FRAC_CONST(0.492898225784302)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.788346469402313), FRAC_CONST(0.615231573581696)}, + {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, {FRAC_CONST(0.689540505409241), FRAC_CONST(0.724247097969055)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.575808227062225), FRAC_CONST(0.817584812641144)}, + {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, {FRAC_CONST(0.449611306190491), FRAC_CONST(0.893224298954010)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.313681751489639), FRAC_CONST(0.949528157711029)}, + {FRAC_CONST(0.242980241775513), FRAC_CONST(0.970031261444092)}, {FRAC_CONST(0.170961856842041), FRAC_CONST(0.985277652740479)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.024541255086660), FRAC_CONST(0.999698817729950)}, + {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, {FRAC_CONST(-0.122410707175732), FRAC_CONST(0.992479503154755)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.266712725162506), FRAC_CONST(0.963776051998138)}, + {FRAC_CONST(-0.336889803409576), FRAC_CONST(0.941544055938721)}, {FRAC_CONST(-0.405241340398788), FRAC_CONST(0.914209723472595)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.534997701644897), FRAC_CONST(0.844853520393372)}, + {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, {FRAC_CONST(-0.653172850608826), FRAC_CONST(0.757208824157715)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.757208824157715), FRAC_CONST(0.653172850608826)}, + {FRAC_CONST(-0.803207516670227), FRAC_CONST(0.595699369907379)}, {FRAC_CONST(-0.844853520393372), FRAC_CONST(0.534997701644897)}, + {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, {FRAC_CONST(-0.914209783077240), FRAC_CONST(0.405241221189499)}, + {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, {FRAC_CONST(-0.963776051998138), FRAC_CONST(0.266712725162506)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.992479503154755), FRAC_CONST(0.122410699725151)}, + {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067724496126)}, {FRAC_CONST(-0.999698817729950), FRAC_CONST(-0.024541147053242)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, {FRAC_CONST(-0.985277652740479), FRAC_CONST(-0.170961990952492)}, + {FRAC_CONST(-0.970031261444092), FRAC_CONST(-0.242980241775513)}, {FRAC_CONST(-0.949528157711029), FRAC_CONST(-0.313681781291962)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.893224298954010), FRAC_CONST(-0.449611306190491)}, + {FRAC_CONST(-0.857728660106659), FRAC_CONST(-0.514102697372437)}, {FRAC_CONST(-0.817584872245789), FRAC_CONST(-0.575808107852936)}, + {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, {FRAC_CONST(-0.724247038364410), FRAC_CONST(-0.689540624618530)}, + {FRAC_CONST(-0.671558916568756), FRAC_CONST(-0.740951180458069)}, {FRAC_CONST(-0.615231573581696), FRAC_CONST(-0.788346469402313)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.492898195981979), FRAC_CONST(-0.870086967945099)}, + {FRAC_CONST(-0.427554935216904), FRAC_CONST(-0.903989374637604)}, {FRAC_CONST(-0.359895110130310), FRAC_CONST(-0.932992756366730)}, + {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, {FRAC_CONST(-0.219101369380951), FRAC_CONST(-0.975702106952667)}, + {FRAC_CONST(-0.146730408072472), FRAC_CONST(-0.989176511764526)}, {FRAC_CONST(-0.073564760386944), FRAC_CONST(-0.997290432453156)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.000000011924881), FRAC_CONST(-1.000000000000000)}}; + #endif // LD_DEC +#endif // FIXED POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT + #ifdef LD_DEC + #ifdef ALLOW_SMALL_FRAMELENGTH +static const complex_t cfft_tab_240[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.999657332897186), FRAC_CONST(0.026176949962974)}, + {FRAC_CONST(0.998629510402679), FRAC_CONST(0.052335958927870)}, {FRAC_CONST(0.996917307376862), FRAC_CONST(0.078459098935127)}, + {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, {FRAC_CONST(0.991444885730743), FRAC_CONST(0.130526199936867)}, + {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, {FRAC_CONST(0.983254909515381), FRAC_CONST(0.182235524058342)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.965925812721252), FRAC_CONST(0.258819043636322)}, {FRAC_CONST(0.958819746971130), FRAC_CONST(0.284015357494354)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.942641496658325), FRAC_CONST(0.333806872367859)}, + {FRAC_CONST(0.933580398559570), FRAC_CONST(0.358367949724197)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.902585268020630), FRAC_CONST(0.430511116981506)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.878817081451416), FRAC_CONST(0.477158784866333)}, + {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, {FRAC_CONST(0.852640151977539), FRAC_CONST(0.522498548030853)}, + {FRAC_CONST(0.838670551776886), FRAC_CONST(0.544639050960541)}, {FRAC_CONST(0.824126183986664), FRAC_CONST(0.566406250000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.793353319168091), FRAC_CONST(0.608761429786682)}, + {FRAC_CONST(0.777145922183990), FRAC_CONST(0.629320383071899)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, {FRAC_CONST(0.725374400615692), FRAC_CONST(0.688354551792145)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.688354551792145), FRAC_CONST(0.725374400615692)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.649448037147522), FRAC_CONST(0.760405957698822)}, + {FRAC_CONST(0.629320383071899), FRAC_CONST(0.777145981788635)}, {FRAC_CONST(0.608761370182037), FRAC_CONST(0.793353378772736)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.566406250000000), FRAC_CONST(0.824126183986664)}, + {FRAC_CONST(0.544638991355896), FRAC_CONST(0.838670611381531)}, {FRAC_CONST(0.522498488426209), FRAC_CONST(0.852640211582184)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.477158755064011), FRAC_CONST(0.878817141056061)}, + {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, {FRAC_CONST(0.430511027574539), FRAC_CONST(0.902585327625275)}, + {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.358367860317230), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(0.333806812763214), FRAC_CONST(0.942641496658325)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.284015327692032), FRAC_CONST(0.958819746971130)}, + {FRAC_CONST(0.258819073438644), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(0.233445301651955), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, {FRAC_CONST(0.182235524058342), FRAC_CONST(0.983254909515381)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(0.130526125431061), FRAC_CONST(0.991444885730743)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(0.078459084033966), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(0.052335973829031), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(0.026176875457168), FRAC_CONST(0.999657332897186)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.026176963001490), FRAC_CONST(0.999657332897186)}, + {FRAC_CONST(-0.052336059510708), FRAC_CONST(0.998629510402679)}, {FRAC_CONST(-0.078459173440933), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.130526214838028), FRAC_CONST(0.991444885730743)}, + {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(-0.182235598564148), FRAC_CONST(0.983254909515381)}, + {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, {FRAC_CONST(-0.233445391058922), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(-0.258819162845612), FRAC_CONST(0.965925812721252)}, {FRAC_CONST(-0.284015417098999), FRAC_CONST(0.958819687366486)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.333806872367859), FRAC_CONST(0.942641496658325)}, + {FRAC_CONST(-0.358367949724197), FRAC_CONST(0.933580458164215)}, {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, {FRAC_CONST(-0.430511116981506), FRAC_CONST(0.902585268020630)}, + {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, {FRAC_CONST(-0.477158725261688), FRAC_CONST(0.878817141056061)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.998629510402679), FRAC_CONST(0.052335958927870)}, + {FRAC_CONST(0.994521915912628), FRAC_CONST(0.104528464376926)}, {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, + {FRAC_CONST(0.978147625923157), FRAC_CONST(0.207911700010300)}, {FRAC_CONST(0.965925812721252), FRAC_CONST(0.258819043636322)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.933580398559570), FRAC_CONST(0.358367949724197)}, + {FRAC_CONST(0.913545429706573), FRAC_CONST(0.406736642122269)}, {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, + {FRAC_CONST(0.866025388240814), FRAC_CONST(0.500000000000000)}, {FRAC_CONST(0.838670551776886), FRAC_CONST(0.544639050960541)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.777145922183990), FRAC_CONST(0.629320383071899)}, + {FRAC_CONST(0.743144810199738), FRAC_CONST(0.669130623340607)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(0.669130563735962), FRAC_CONST(0.743144869804382)}, {FRAC_CONST(0.629320383071899), FRAC_CONST(0.777145981788635)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.544638991355896), FRAC_CONST(0.838670611381531)}, + {FRAC_CONST(0.499999970197678), FRAC_CONST(0.866025447845459)}, {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, + {FRAC_CONST(0.406736612319946), FRAC_CONST(0.913545489311218)}, {FRAC_CONST(0.358367860317230), FRAC_CONST(0.933580458164215)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.258819073438644), FRAC_CONST(0.965925812721252)}, + {FRAC_CONST(0.207911655306816), FRAC_CONST(0.978147625923157)}, {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(0.104528419673443), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(0.052335973829031), FRAC_CONST(0.998629510402679)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.052336059510708), FRAC_CONST(0.998629510402679)}, + {FRAC_CONST(-0.104528509080410), FRAC_CONST(0.994521915912628)}, {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.207911744713783), FRAC_CONST(0.978147566318512)}, {FRAC_CONST(-0.258819162845612), FRAC_CONST(0.965925812721252)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.358367949724197), FRAC_CONST(0.933580458164215)}, + {FRAC_CONST(-0.406736701726913), FRAC_CONST(0.913545429706573)}, {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, + {FRAC_CONST(-0.500000059604645), FRAC_CONST(0.866025388240814)}, {FRAC_CONST(-0.544639050960541), FRAC_CONST(0.838670551776886)}, + {FRAC_CONST(-0.587785184383392), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(-0.629320502281189), FRAC_CONST(0.777145862579346)}, + {FRAC_CONST(-0.669130682945251), FRAC_CONST(0.743144810199738)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.743144929409027), FRAC_CONST(0.669130444526672)}, {FRAC_CONST(-0.777146041393280), FRAC_CONST(0.629320263862610)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.838670551776886), FRAC_CONST(0.544639050960541)}, + {FRAC_CONST(-0.866025388240814), FRAC_CONST(0.500000059604645)}, {FRAC_CONST(-0.891006588935852), FRAC_CONST(0.453990370035172)}, + {FRAC_CONST(-0.913545489311218), FRAC_CONST(0.406736582517624)}, {FRAC_CONST(-0.933580458164215), FRAC_CONST(0.358367919921875)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.965925872325897), FRAC_CONST(0.258818924427032)}, + {FRAC_CONST(-0.978147625923157), FRAC_CONST(0.207911610603333)}, {FRAC_CONST(-0.987688362598419), FRAC_CONST(0.156434446573257)}, + {FRAC_CONST(-0.994521915912628), FRAC_CONST(0.104528494179249)}, {FRAC_CONST(-0.998629570007324), FRAC_CONST(0.052335809916258)}, + {FRAC_CONST(-1.000000000000000), FRAC_CONST(-0.000000087422777)}, {FRAC_CONST(-0.998629510402679), FRAC_CONST(-0.052335985004902)}, + {FRAC_CONST(-0.994521856307983), FRAC_CONST(-0.104528672993183)}, {FRAC_CONST(-0.987688302993774), FRAC_CONST(-0.156434610486031)}, + {FRAC_CONST(-0.978147566318512), FRAC_CONST(-0.207911789417267)}, {FRAC_CONST(-0.965925812721252), FRAC_CONST(-0.258819073438644)}, + {FRAC_CONST(-0.951056540012360), FRAC_CONST(-0.309016972780228)}, {FRAC_CONST(-0.933580398559570), FRAC_CONST(-0.358368098735809)}, + {FRAC_CONST(-0.913545429706573), FRAC_CONST(-0.406736731529236)}, {FRAC_CONST(-0.891006529331207), FRAC_CONST(-0.453990548849106)}, + {FRAC_CONST(-0.866025269031525), FRAC_CONST(-0.500000178813934)}, {FRAC_CONST(-0.838670492172241), FRAC_CONST(-0.544639170169830)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(-0.777145922183990), FRAC_CONST(-0.629320442676544)}, + {FRAC_CONST(-0.743144810199738), FRAC_CONST(-0.669130623340607)}, {FRAC_CONST(-0.707106649875641), FRAC_CONST(-0.707106888294220)}, + {FRAC_CONST(-0.669130504131317), FRAC_CONST(-0.743144869804382)}, {FRAC_CONST(-0.629320323467255), FRAC_CONST(-0.777145981788635)}, + {FRAC_CONST(-0.587785065174103), FRAC_CONST(-0.809017121791840)}, {FRAC_CONST(-0.544639110565186), FRAC_CONST(-0.838670551776886)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.996917307376862), FRAC_CONST(0.078459098935127)}, + {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.852640151977539), FRAC_CONST(0.522498548030853)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.649448037147522), FRAC_CONST(0.760405957698822)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.522498488426209), FRAC_CONST(0.852640211582184)}, + {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.233445301651955), FRAC_CONST(0.972369909286499)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(0.078459084033966), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.987688362598419), FRAC_CONST(0.156434476375580)}, + {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.453990519046783), FRAC_CONST(0.891006529331207)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.156434446573257), FRAC_CONST(0.987688362598419)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.453990608453751), FRAC_CONST(0.891006469726563)}, + {FRAC_CONST(-0.587785184383392), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, {FRAC_CONST(-0.891006588935852), FRAC_CONST(0.453990370035172)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.987688362598419), FRAC_CONST(0.156434446573257)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.972369909286499), FRAC_CONST(0.233445376157761)}, + {FRAC_CONST(0.891006529331207), FRAC_CONST(0.453990519046783)}, {FRAC_CONST(0.760405957698822), FRAC_CONST(0.649448096752167)}, + {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(0.156434372067451), FRAC_CONST(0.987688362598419)}, {FRAC_CONST(-0.078459173440933), FRAC_CONST(0.996917307376862)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.522498667240143), FRAC_CONST(0.852640092372894)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.852640211582184), FRAC_CONST(0.522498488426209)}, + {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, {FRAC_CONST(-0.996917366981506), FRAC_CONST(0.078459039330482)}, + {FRAC_CONST(-0.987688302993774), FRAC_CONST(-0.156434610486031)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(-0.649447917938232), FRAC_CONST(-0.760406076908112)}, + {FRAC_CONST(-0.453990221023560), FRAC_CONST(-0.891006648540497)}, {FRAC_CONST(-0.233445450663567), FRAC_CONST(-0.972369909286499)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.951056540012360), FRAC_CONST(0.309017002582550)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(0.809017002582550), FRAC_CONST(0.587785243988037)}, {FRAC_CONST(0.309016972780228), FRAC_CONST(0.951056540012360)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.809017062187195), FRAC_CONST(0.587785184383392)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.587785243988037), FRAC_CONST(0.809017002582550)}, + {FRAC_CONST(-0.309017032384872), FRAC_CONST(0.951056480407715)}, {FRAC_CONST(-0.951056599617004), FRAC_CONST(0.309016793966293)}, + {FRAC_CONST(-0.809016942977905), FRAC_CONST(-0.587785363197327)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.309017121791840), FRAC_CONST(-0.951056480407715)}}; + #endif // ALLOW_SMALL_FRAMELENGTH + #endif // LD_DEC +#endif // FIXED POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +static const complex_t cfft_tab_128[] = {{FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.998795449733734), FRAC_CONST(0.049067676067352)}, + {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, {FRAC_CONST(0.989176511764526), FRAC_CONST(0.146730467677116)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.970031261444092), FRAC_CONST(0.242980197072029)}, + {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, {FRAC_CONST(0.941544055938721), FRAC_CONST(0.336889863014221)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.903989315032959), FRAC_CONST(0.427555084228516)}, + {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, {FRAC_CONST(0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.803207516670227), FRAC_CONST(0.595699310302734)}, + {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, {FRAC_CONST(0.740951120853424), FRAC_CONST(0.671558976173401)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.671558916568756), FRAC_CONST(0.740951180458069)}, + {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, {FRAC_CONST(0.595699310302734), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.514102697372437), FRAC_CONST(0.857728660106659)}, + {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, {FRAC_CONST(0.427555114030838), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.336889833211899), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, {FRAC_CONST(0.242980122566223), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.146730497479439), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(0.049067649990320), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.049067739397287), FRAC_CONST(0.998795449733734)}, + {FRAC_CONST(-0.098017223179340), FRAC_CONST(0.995184719562531)}, {FRAC_CONST(-0.146730571985245), FRAC_CONST(0.989176511764526)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.242980197072029), FRAC_CONST(0.970031261444092)}, + {FRAC_CONST(-0.290284723043442), FRAC_CONST(0.956940293312073)}, {FRAC_CONST(-0.336889922618866), FRAC_CONST(0.941544055938721)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.427555084228516), FRAC_CONST(0.903989315032959)}, + {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, {FRAC_CONST(-0.514102756977081), FRAC_CONST(0.857728600502014)}, + {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, {FRAC_CONST(-0.595699369907379), FRAC_CONST(0.803207516670227)}, + {FRAC_CONST(-0.634393274784088), FRAC_CONST(0.773010492324829)}, {FRAC_CONST(-0.671559035778046), FRAC_CONST(0.740951061248779)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.740951240062714), FRAC_CONST(0.671558856964111)}, + {FRAC_CONST(-0.773010492324829), FRAC_CONST(0.634393274784088)}, {FRAC_CONST(-0.803207635879517), FRAC_CONST(0.595699131488800)}, + {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, {FRAC_CONST(-0.857728600502014), FRAC_CONST(0.514102756977081)}, + {FRAC_CONST(-0.881921350955963), FRAC_CONST(0.471396625041962)}, {FRAC_CONST(-0.903989315032959), FRAC_CONST(0.427555054426193)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.941544115543365), FRAC_CONST(0.336889803409576)}, + {FRAC_CONST(-0.956940352916718), FRAC_CONST(0.290284723043442)}, {FRAC_CONST(-0.970031261444092), FRAC_CONST(0.242980077862740)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.989176511764526), FRAC_CONST(0.146730333566666)}, + {FRAC_CONST(-0.995184719562531), FRAC_CONST(0.098017096519470)}, {FRAC_CONST(-0.998795449733734), FRAC_CONST(0.049067486077547)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.995184719562531), FRAC_CONST(0.098017141222954)}, + {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.881921231746674), FRAC_CONST(0.471396744251251)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.773010432720184), FRAC_CONST(0.634393334388733)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, {FRAC_CONST(0.471396654844284), FRAC_CONST(0.881921291351318)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.290284633636475), FRAC_CONST(0.956940352916718)}, + {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.980785250663757), FRAC_CONST(0.195090323686600)}, + {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.555570185184479), FRAC_CONST(0.831469655036926)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.195090234279633), FRAC_CONST(0.980785310268402)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, + {FRAC_CONST(-0.382683515548706), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(-0.555570363998413), FRAC_CONST(0.831469535827637)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.831469655036926), FRAC_CONST(0.555570185184479)}, + {FRAC_CONST(-0.923879623413086), FRAC_CONST(0.382683277130127)}, {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.956940352916718), FRAC_CONST(0.290284663438797)}, + {FRAC_CONST(0.831469595432281), FRAC_CONST(0.555570244789124)}, {FRAC_CONST(0.634393274784088), FRAC_CONST(0.773010432720184)}, + {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, {FRAC_CONST(0.098017133772373), FRAC_CONST(0.995184719562531)}, + {FRAC_CONST(-0.195090323686600), FRAC_CONST(0.980785250663757)}, {FRAC_CONST(-0.471396833658218), FRAC_CONST(0.881921231746674)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.881921231746674), FRAC_CONST(0.471396833658218)}, + {FRAC_CONST(-0.980785310268402), FRAC_CONST(0.195090308785439)}, {FRAC_CONST(-0.995184719562531), FRAC_CONST(-0.098017267882824)}, + {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, {FRAC_CONST(-0.773010551929474), FRAC_CONST(-0.634393215179443)}, + {FRAC_CONST(-0.555570006370544), FRAC_CONST(-0.831469774246216)}, {FRAC_CONST(-0.290284544229507), FRAC_CONST(-0.956940352916718)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.923879504203796), FRAC_CONST(0.382683455944061)}, + {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(-0.000000043711388), FRAC_CONST(1.000000000000000)}, {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.382683426141739), FRAC_CONST(0.923879504203796)}, + {FRAC_CONST(-0.707106769084930), FRAC_CONST(0.707106769084930)}, {FRAC_CONST(-0.923879504203796), FRAC_CONST(-0.382683426141739)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, + {FRAC_CONST(1.000000000000000), FRAC_CONST(0.000000000000000)}, {FRAC_CONST(0.000000011924881), FRAC_CONST(-1.000000000000000)}}; +#endif // FIXED_POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +static const real_t drc_pow2_table[] = {COEF_CONST(0.5146511183), COEF_CONST(0.5297315472), COEF_CONST(0.5452538663), COEF_CONST(0.5612310242), COEF_CONST(0.5776763484), COEF_CONST(0.5946035575), + COEF_CONST(0.6120267717), COEF_CONST(0.6299605249), COEF_CONST(0.6484197773), COEF_CONST(0.6674199271), COEF_CONST(0.6869768237), COEF_CONST(0.7071067812), + COEF_CONST(0.7278265914), COEF_CONST(0.7491535384), COEF_CONST(0.7711054127), COEF_CONST(0.7937005260), COEF_CONST(0.8169577266), COEF_CONST(0.8408964153), + COEF_CONST(0.8655365610), COEF_CONST(0.8908987181), COEF_CONST(0.9170040432), COEF_CONST(0.9438743127), COEF_CONST(0.9715319412), COEF_CONST(1.0000000000), + COEF_CONST(1.0293022366), COEF_CONST(1.0594630944), COEF_CONST(1.0905077327), COEF_CONST(1.1224620483), COEF_CONST(1.1553526969), COEF_CONST(1.1892071150), + COEF_CONST(1.2240535433), COEF_CONST(1.2599210499), COEF_CONST(1.2968395547), COEF_CONST(1.3348398542), COEF_CONST(1.3739536475), COEF_CONST(1.4142135624), + COEF_CONST(1.4556531828), COEF_CONST(1.4983070769), COEF_CONST(1.5422108254), COEF_CONST(1.5874010520), COEF_CONST(1.6339154532), COEF_CONST(1.6817928305), + COEF_CONST(1.7310731220), COEF_CONST(1.7817974363), COEF_CONST(1.8340080864), COEF_CONST(1.8877486254), COEF_CONST(1.9430638823)}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* binary search huffman tables */ +static const int8_t f_huffman_sa[][2] = { + {/*0*/ -15, 1}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 1x */ + {/*7*/ -8, 4}, /* index 2: 3 bits: 10x */ + {5, 6}, /* index 3: 3 bits: 11x */ + {/*1*/ -14, /*-1*/ -16}, /* index 4: 4 bits: 101x */ + {/*-2*/ -17, 7}, /* index 5: 4 bits: 110x */ + {8, 9}, /* index 6: 4 bits: 111x */ + {/*2*/ -13, /*-3*/ -18}, /* index 7: 5 bits: 1101x */ + {/*3*/ -12, 10}, /* index 8: 5 bits: 1110x */ + {11, 12}, /* index 9: 5 bits: 1111x */ + {/*4*/ -11, /*5*/ -10}, /* index 10: 6 bits: 11101x */ + {/*-4*/ -19, /*-5*/ -20}, /* index 11: 6 bits: 11110x */ + {/*6*/ -9, 13}, /* index 12: 6 bits: 11111x */ + {/*-7*/ -22, /*-6*/ -21} /* index 13: 7 bits: 111111x */ +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const int8_t t_huffman_sa[][2] = { + {/*0*/ -15, 1}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 1x */ + {/*-1*/ -16, /*1*/ -14}, /* index 2: 3 bits: 10x */ + {4, 5}, /* index 3: 3 bits: 11x */ + {/*-2*/ -17, /*2*/ -13}, /* index 4: 4 bits: 110x */ + {6, 7}, /* index 5: 4 bits: 111x */ + {/*-3*/ -18, /*3*/ -12}, /* index 6: 5 bits: 1110x */ + {8, 9}, /* index 7: 5 bits: 1111x */ + {/*-4*/ -19, /*4*/ -11}, /* index 8: 6 bits: 11110x */ + {10, 11}, /* index 9: 6 bits: 11111x */ + {/*-5*/ -20, /*5*/ -10}, /* index 10: 7 bits: 111110x */ + {/*-6*/ -21, 12}, /* index 11: 7 bits: 111111x */ + {/*-7*/ -22, 13}, /* index 12: 8 bits: 1111111x */ + {/*6*/ -9, /*7*/ -8} /* index 13: 9 bits: 11111111x */ +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const int8_t f_huffman_pan[][2] = { + {/*0*/ -15, 1}, /* index 0: 1 bits: x */ + {/*-1*/ -16, 2}, /* index 1: 2 bits: 1x */ + {/*1*/ -14, 3}, /* index 2: 3 bits: 11x */ + {4, 5}, /* index 3: 4 bits: 111x */ + {/*-2*/ -17, /*2*/ -13}, /* index 4: 5 bits: 1110x */ + {6, 7}, /* index 5: 5 bits: 1111x */ + {/*-3*/ -18, /*3*/ -12}, /* index 6: 6 bits: 11110x */ + {8, 9}, /* index 7: 6 bits: 11111x */ + {/*-4*/ -19, /*4*/ -11}, /* index 8: 7 bits: 111110x */ + {10, 11}, /* index 9: 7 bits: 111111x */ + {/*-5*/ -20, /*5*/ -10}, /* index 10: 8 bits: 1111110x */ + {12, 13}, /* index 11: 8 bits: 1111111x */ + {/*-6*/ -21, /*6*/ -9}, /* index 12: 9 bits: 11111110x */ + {/*-7*/ -22, 14}, /* index 13: 9 bits: 11111111x */ + {/*7*/ -8, 15}, /* index 14: 10 bits: 111111111x */ + {16, 17}, /* index 15: 11 bits: 1111111111x */ + {/*-8*/ -23, /*8*/ -7}, /* index 16: 12 bits: 11111111110x */ + {18, 19}, /* index 17: 12 bits: 11111111111x */ + {/*-10*/ -25, 20}, /* index 18: 13 bits: 111111111110x */ + {21, 22}, /* index 19: 13 bits: 111111111111x */ + {/*-9*/ -24, /*9*/ -6}, /* index 20: 14 bits: 1111111111101x */ + {/*10*/ -5, 23}, /* index 21: 14 bits: 1111111111110x */ + {24, 25}, /* index 22: 14 bits: 1111111111111x */ + {/*-13*/ -28, /*-11*/ -26}, /* index 23: 15 bits: 11111111111101x */ + {/*11*/ -4, /*13*/ -2}, /* index 24: 15 bits: 11111111111110x */ + {26, 27}, /* index 25: 15 bits: 11111111111111x */ + {/*-14*/ -29, /*-12*/ -27}, /* index 26: 16 bits: 111111111111110x */ + {/*12*/ -3, /*14*/ -1} /* index 27: 16 bits: 111111111111111x */ +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const int8_t t_huffman_pan[][2] = { + {/*0*/ -15, 1}, /* index 0: 1 bits: x */ + {/*-1*/ -16, 2}, /* index 1: 2 bits: 1x */ + {/*1*/ -14, 3}, /* index 2: 3 bits: 11x */ + {/*-2*/ -17, 4}, /* index 3: 4 bits: 111x */ + {/*2*/ -13, 5}, /* index 4: 5 bits: 1111x */ + {/*-3*/ -18, 6}, /* index 5: 6 bits: 11111x */ + {/*3*/ -12, 7}, /* index 6: 7 bits: 111111x */ + {/*-4*/ -19, 8}, /* index 7: 8 bits: 1111111x */ + {/*4*/ -11, 9}, /* index 8: 9 bits: 11111111x */ + {10, 11}, /* index 9: 10 bits: 111111111x */ + {/*-5*/ -20, /*5*/ -10}, /* index 10: 11 bits: 1111111110x */ + {12, 13}, /* index 11: 11 bits: 1111111111x */ + {/*-6*/ -21, /*6*/ -9}, /* index 12: 12 bits: 11111111110x */ + {14, 15}, /* index 13: 12 bits: 11111111111x */ + {/*-7*/ -22, /*7*/ -8}, /* index 14: 13 bits: 111111111110x */ + {16, 17}, /* index 15: 13 bits: 111111111111x */ + {/*-8*/ -23, /*8*/ -7}, /* index 16: 14 bits: 1111111111110x */ + {18, 19}, /* index 17: 14 bits: 1111111111111x */ + {/*-10*/ -25, /*10*/ -5}, /* index 18: 15 bits: 11111111111110x */ + {20, 21}, /* index 19: 15 bits: 11111111111111x */ + {/*-9*/ -24, /*9*/ -6}, /* index 20: 16 bits: 111111111111110x */ + {22, 23}, /* index 21: 16 bits: 111111111111111x */ + {24, 25}, /* index 22: 17 bits: 1111111111111110x */ + {26, 27}, /* index 23: 17 bits: 1111111111111111x */ + {/*-14*/ -29, /*-13*/ -28}, /* index 24: 18 bits: 11111111111111100x */ + {/*-12*/ -27, /*-11*/ -26}, /* index 25: 18 bits: 11111111111111101x */ + {/*11*/ -4, /*12*/ -3}, /* index 26: 18 bits: 11111111111111110x */ + {/*13*/ -2, /*14*/ -1} /* index 27: 18 bits: 11111111111111111x */ +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* There are 3 classes in the standard but the last 2 are identical */ +static const real_t sa_quant[8][2] = { + {FRAC_CONST(0.0000), FRAC_CONST(0.0000)}, {FRAC_CONST(0.0501), FRAC_CONST(0.1778)}, {FRAC_CONST(0.0706), FRAC_CONST(0.2818)}, {FRAC_CONST(0.0995), FRAC_CONST(0.4467)}, + {FRAC_CONST(0.1399), FRAC_CONST(0.5623)}, {FRAC_CONST(0.1957), FRAC_CONST(0.7079)}, {FRAC_CONST(0.2713), FRAC_CONST(0.8913)}, {FRAC_CONST(0.3699), FRAC_CONST(1.0000)}, +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM + /* We don't need the actual quantizer values */ + #if 0 +static const real_t pan_quant[8][5] = +{ + { COEF_CONST(0.0000), COEF_CONST(0.0000), COEF_CONST(0.0000), COEF_CONST(0.0000), COEF_CONST(0.0000) }, + { COEF_CONST(0.1661), COEF_CONST(0.1661), COEF_CONST(0.3322), COEF_CONST(0.3322), COEF_CONST(0.3322) }, + { COEF_CONST(0.3322), COEF_CONST(0.3322), COEF_CONST(0.6644), COEF_CONST(0.8305), COEF_CONST(0.8305) }, + { COEF_CONST(0.4983), COEF_CONST(0.6644), COEF_CONST(0.9966), COEF_CONST(1.4949), COEF_CONST(1.6610) }, + { COEF_CONST(0.6644), COEF_CONST(0.9966), COEF_CONST(1.4949), COEF_CONST(2.1593), COEF_CONST(2.4914) }, + { COEF_CONST(0.8305), COEF_CONST(1.3288), COEF_CONST(2.1593), COEF_CONST(2.9897), COEF_CONST(3.4880) }, + { COEF_CONST(0.9966), COEF_CONST(1.8271), COEF_CONST(2.8236), COEF_CONST(3.8202), COEF_CONST(4.6507) }, + { COEF_CONST(1.3288), COEF_CONST(2.3253), COEF_CONST(3.4880), COEF_CONST(4.6507), COEF_CONST(5.8134) }, +}; + #endif +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* 2^(pan_quant[x][y] */ +static const real_t pan_pow_2_pos[8][5] = {{REAL_CONST(1.0000000), REAL_CONST(1.0000000), REAL_CONST(1.0000000), REAL_CONST(1.0000000), REAL_CONST(1.0000000)}, + {REAL_CONST(1.1220021), REAL_CONST(1.1220021), REAL_CONST(1.2589312), REAL_CONST(1.2589312), REAL_CONST(1.2589312)}, + {REAL_CONST(1.2589312), REAL_CONST(1.2589312), REAL_CONST(1.5849090), REAL_CONST(1.7783016), REAL_CONST(1.7783016)}, + {REAL_CONST(1.4125481), REAL_CONST(1.5849090), REAL_CONST(1.9952921), REAL_CONST(2.8184461), REAL_CONST(3.1623565)}, + {REAL_CONST(1.5849090), REAL_CONST(1.9952922), REAL_CONST(2.8184461), REAL_CONST(4.4669806), REAL_CONST(5.6232337)}, + {REAL_CONST(1.7783016), REAL_CONST(2.5119365), REAL_CONST(4.4669806), REAL_CONST(7.9430881), REAL_CONST(11.219994)}, + {REAL_CONST(1.9952921), REAL_CONST(3.5482312), REAL_CONST(7.0792671), REAL_CONST(14.125206), REAL_CONST(25.118876)}, + {REAL_CONST(2.5119365), REAL_CONST(5.0116998), REAL_CONST(11.219994), REAL_CONST(25.118876), REAL_CONST(56.235140)}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* 2^(-pan_quant[x][y] */ +static const real_t pan_pow_2_neg[8][5] = {{REAL_CONST(1), REAL_CONST(1), REAL_CONST(1), REAL_CONST(1), REAL_CONST(1)}, + {REAL_CONST(0.8912487), REAL_CONST(0.8912487), REAL_CONST(0.7943242), REAL_CONST(0.7943242), REAL_CONST(0.7943242)}, + {REAL_CONST(0.7943242), REAL_CONST(0.7943242), REAL_CONST(0.6309511), REAL_CONST(0.5623344), REAL_CONST(0.5623344)}, + {REAL_CONST(0.7079405), REAL_CONST(0.6309511), REAL_CONST(0.5011797), REAL_CONST(0.3548054), REAL_CONST(0.3162199)}, + {REAL_CONST(0.6309511), REAL_CONST(0.5011797), REAL_CONST(0.3548054), REAL_CONST(0.2238649), REAL_CONST(0.1778336)}, + {REAL_CONST(0.5623343), REAL_CONST(0.3980992), REAL_CONST(0.2238649), REAL_CONST(0.1258956), REAL_CONST(0.0891266)}, + {REAL_CONST(0.5011797), REAL_CONST(0.2818306), REAL_CONST(0.1412576), REAL_CONST(0.0707954), REAL_CONST(0.0398107)}, + {REAL_CONST(0.3980992), REAL_CONST(0.1995331), REAL_CONST(0.0891267), REAL_CONST(0.0398107), REAL_CONST(0.0177825)}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* 2^(pan_quant[x][y]/30) */ +static const real_t pan_pow_2_30_pos[8][5] = {{COEF_CONST(1), COEF_CONST(1), COEF_CONST(1), COEF_CONST(1), COEF_CONST(1)}, + {COEF_CONST(1.003845098), COEF_CONST(1.003845098), COEF_CONST(1.007704982), COEF_CONST(1.007704982), COEF_CONST(1.007704982)}, + {COEF_CONST(1.007704982), COEF_CONST(1.007704982), COEF_CONST(1.01546933), COEF_CONST(1.019373909), COEF_CONST(1.019373909)}, + {COEF_CONST(1.011579706), COEF_CONST(1.01546933), COEF_CONST(1.023293502), COEF_CONST(1.035142941), COEF_CONST(1.039123167)}, + {COEF_CONST(1.01546933), COEF_CONST(1.023293502), COEF_CONST(1.035142941), COEF_CONST(1.051155908), COEF_CONST(1.059252598)}, + {COEF_CONST(1.019373909), COEF_CONST(1.03117796), COEF_CONST(1.051155908), COEF_CONST(1.071518432), COEF_CONST(1.0839263)}, + {COEF_CONST(1.023293502), COEF_CONST(1.043118698), COEF_CONST(1.067414119), COEF_CONST(1.092277933), COEF_CONST(1.113439626)}, + {COEF_CONST(1.03117796), COEF_CONST(1.055195268), COEF_CONST(1.0839263), COEF_CONST(1.113439626), COEF_CONST(1.143756546)}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* 2^(-pan_quant[x][y]/30) */ +static const real_t pan_pow_2_30_neg[8][5] = {{COEF_CONST(1), COEF_CONST(1), COEF_CONST(1), COEF_CONST(1), COEF_CONST(1)}, + {COEF_CONST(0.99616963), COEF_CONST(0.99616963), COEF_CONST(0.992353931), COEF_CONST(0.992353931), COEF_CONST(0.99235393)}, + {COEF_CONST(0.992353931), COEF_CONST(0.992353931), COEF_CONST(0.984766325), COEF_CONST(0.980994305), COEF_CONST(0.980994305)}, + {COEF_CONST(0.988552848), COEF_CONST(0.984766325), COEF_CONST(0.977236734), COEF_CONST(0.966050157), COEF_CONST(0.962349827)}, + {COEF_CONST(0.984766325), COEF_CONST(0.977236734), COEF_CONST(0.966050157), COEF_CONST(0.951333663), COEF_CONST(0.944061881)}, + {COEF_CONST(0.980994305), COEF_CONST(0.969764715), COEF_CONST(0.951333663), COEF_CONST(0.933255062), COEF_CONST(0.922571949)}, + {COEF_CONST(0.977236734), COEF_CONST(0.958663671), COEF_CONST(0.936843519), COEF_CONST(0.915517901), COEF_CONST(0.898117847)}, + {COEF_CONST(0.969764715), COEF_CONST(0.947691892), COEF_CONST(0.922571949), COEF_CONST(0.898117847), COEF_CONST(0.874311936)}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const real_t g_decayslope[MAX_SA_BAND] = {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.95), FRAC_CONST(0.9), FRAC_CONST(0.85), FRAC_CONST(0.8), FRAC_CONST(0.75), + FRAC_CONST(0.7), FRAC_CONST(0.65), FRAC_CONST(0.6), FRAC_CONST(0.55), FRAC_CONST(0.5), FRAC_CONST(0.45), FRAC_CONST(0.4), FRAC_CONST(0.35), + FRAC_CONST(0.3), FRAC_CONST(0.25), FRAC_CONST(0.2), FRAC_CONST(0.15), FRAC_CONST(0.1), FRAC_CONST(0.05), FRAC_CONST(0), FRAC_CONST(0), + FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), + FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), + FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0), FRAC_CONST(0)}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const real_t sa_sqrt_1_minus[8][2] = {{FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.998744206), FRAC_CONST(0.984066644)}, + {FRAC_CONST(0.997504707), FRAC_CONST(0.959473168)}, + {FRAC_CONST(0.995037562), FRAC_CONST(0.894683804)}, + {FRAC_CONST(0.990165638), FRAC_CONST(0.826933317)}, + {FRAC_CONST(0.980663811), FRAC_CONST(0.706312672)}, + {FRAC_CONST(0.962494836), FRAC_CONST(0.45341406)}, + {FRAC_CONST(0.929071574), FRAC_CONST(0)}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +static const uint8_t sa_freq_scale[9] = {0, 1, 2, 3, 5, 7, 10, 13, 23}; +static const uint8_t pan_freq_scale[21] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 22, 26, 32, 64}; +static const uint8_t pan_quant_class[20] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4}; +/* Inverse mapping lookup */ +static const uint8_t pan_inv_freq[64] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19}; +static const uint8_t sa_inv_freq[MAX_SA_BAND] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; +static const real_t filter_coeff[] = {FRAC_CONST(0.65143905754106), FRAC_CONST(0.56471812200776), FRAC_CONST(0.48954165955695)}; +static const uint8_t delay_length[3] = {3, 4, 5}; +static const real_t delay_fraction[] = {FRAC_CONST(0.43), FRAC_CONST(0.75), FRAC_CONST(0.347)}; +static const real_t peak_decay = FRAC_CONST(0.76592833836465); +static const real_t smooth_coeff = FRAC_CONST(0.25); +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#if defined(DRM) || defined(PS_DEC) +/* Please note that these are the same tables as in plain PS */ +static const complex_t Q_Fract_allpass_Qmf[][3] = { + {{FRAC_CONST(0.7804303765), FRAC_CONST(0.6252426505)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.8550928831), FRAC_CONST(0.5184748173)}}, + {{FRAC_CONST(-0.4399392009), FRAC_CONST(0.8980275393)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.0643581524), FRAC_CONST(0.9979268909)}}, + {{FRAC_CONST(-0.9723699093), FRAC_CONST(-0.2334454209)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.9146071672), FRAC_CONST(0.4043435752)}}, + {{FRAC_CONST(0.0157073960), FRAC_CONST(-0.9998766184)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.7814115286), FRAC_CONST(-0.6240159869)}}, + {{FRAC_CONST(0.9792228341), FRAC_CONST(-0.2027871907)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.1920081824), FRAC_CONST(-0.9813933372)}}, + {{FRAC_CONST(0.4115142524), FRAC_CONST(0.9114032984)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.9589683414), FRAC_CONST(-0.2835132182)}}, + {{FRAC_CONST(-0.7996847630), FRAC_CONST(0.6004201174)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.6947838664), FRAC_CONST(0.7192186117)}}, + {{FRAC_CONST(-0.7604058385), FRAC_CONST(-0.6494481564)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.3164770305), FRAC_CONST(0.9486001730)}}, + {{FRAC_CONST(0.4679299891), FRAC_CONST(-0.8837655187)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.9874414206), FRAC_CONST(0.1579856575)}}, + {{FRAC_CONST(0.9645573497), FRAC_CONST(0.2638732493)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.5966450572), FRAC_CONST(-0.8025052547)}}, + {{FRAC_CONST(-0.0471066870), FRAC_CONST(0.9988898635)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.4357025325), FRAC_CONST(-0.9000906944)}}, + {{FRAC_CONST(-0.9851093888), FRAC_CONST(0.1719288528)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.9995546937), FRAC_CONST(-0.0298405960)}}, + {{FRAC_CONST(-0.3826831877), FRAC_CONST(-0.9238796234)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.4886211455), FRAC_CONST(0.8724960685)}}, + {{FRAC_CONST(0.8181498647), FRAC_CONST(-0.5750049949)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.5477093458), FRAC_CONST(0.8366686702)}}, + {{FRAC_CONST(0.7396308780), FRAC_CONST(0.6730127335)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.9951074123), FRAC_CONST(-0.0987988561)}}, + {{FRAC_CONST(-0.4954589605), FRAC_CONST(0.8686313629)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.3725017905), FRAC_CONST(-0.9280315042)}}, + {{FRAC_CONST(-0.9557929039), FRAC_CONST(-0.2940406799)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.6506417990), FRAC_CONST(-0.7593847513)}}, + {{FRAC_CONST(0.0784594864), FRAC_CONST(-0.9969173074)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.9741733670), FRAC_CONST(0.2258014232)}}, + {{FRAC_CONST(0.9900237322), FRAC_CONST(-0.1409008205)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.2502108514), FRAC_CONST(0.9681913853)}}, + {{FRAC_CONST(0.3534744382), FRAC_CONST(0.9354441762)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.7427945137), FRAC_CONST(0.6695194840)}}, + {{FRAC_CONST(-0.8358076215), FRAC_CONST(0.5490224361)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.9370992780), FRAC_CONST(-0.3490629196)}}, + {{FRAC_CONST(-0.7181259394), FRAC_CONST(-0.6959131360)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.1237744763), FRAC_CONST(-0.9923103452)}}, + {{FRAC_CONST(0.5224990249), FRAC_CONST(-0.8526399136)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.8226406574), FRAC_CONST(-0.5685616732)}}, + {{FRAC_CONST(0.9460852146), FRAC_CONST(0.3239179254)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.8844994903), FRAC_CONST(0.4665412009)}}, + {{FRAC_CONST(-0.1097348556), FRAC_CONST(0.9939609170)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.0047125919), FRAC_CONST(0.9999889135)}}, + {{FRAC_CONST(-0.9939610362), FRAC_CONST(0.1097337380)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.8888573647), FRAC_CONST(0.4581840038)}}, + {{FRAC_CONST(-0.3239168525), FRAC_CONST(-0.9460855722)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.8172453642), FRAC_CONST(-0.5762898922)}}, + {{FRAC_CONST(0.8526405096), FRAC_CONST(-0.5224980116)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.1331215799), FRAC_CONST(-0.9910997152)}}, + {{FRAC_CONST(0.6959123611), FRAC_CONST(0.7181267142)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.9403476119), FRAC_CONST(-0.3402152061)}}, + {{FRAC_CONST(-0.5490233898), FRAC_CONST(0.8358070254)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.7364512086), FRAC_CONST(0.6764906645)}}, + {{FRAC_CONST(-0.9354437590), FRAC_CONST(-0.3534754813)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.2593250275), FRAC_CONST(0.9657900929)}}, + {{FRAC_CONST(0.1409019381), FRAC_CONST(-0.9900235534)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.9762582779), FRAC_CONST(0.2166097313)}}, + {{FRAC_CONST(0.9969173670), FRAC_CONST(-0.0784583688)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.6434556246), FRAC_CONST(-0.7654833794)}}, + {{FRAC_CONST(0.2940396070), FRAC_CONST(0.9557932615)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.3812320232), FRAC_CONST(-0.9244794250)}}, + {{FRAC_CONST(-0.8686318994), FRAC_CONST(0.4954580069)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.9959943891), FRAC_CONST(-0.0894154981)}}, + {{FRAC_CONST(-0.6730118990), FRAC_CONST(-0.7396316528)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.5397993922), FRAC_CONST(0.8417937160)}}, + {{FRAC_CONST(0.5750059485), FRAC_CONST(-0.8181492686)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.4968227744), FRAC_CONST(0.8678520322)}}, + {{FRAC_CONST(0.9238792062), FRAC_CONST(0.3826842010)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.9992290139), FRAC_CONST(-0.0392601527)}}, + {{FRAC_CONST(-0.1719299555), FRAC_CONST(0.9851091504)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.4271997511), FRAC_CONST(-0.9041572809)}}, + {{FRAC_CONST(-0.9988899231), FRAC_CONST(0.0471055657)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.6041822433), FRAC_CONST(-0.7968461514)}}, + {{FRAC_CONST(-0.2638721764), FRAC_CONST(-0.9645576477)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.9859085083), FRAC_CONST(0.1672853529)}}, + {{FRAC_CONST(0.8837660551), FRAC_CONST(-0.4679289758)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.3075223565), FRAC_CONST(0.9515408874)}}, + {{FRAC_CONST(0.6494473219), FRAC_CONST(0.7604066133)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.7015317082), FRAC_CONST(0.7126382589)}}, + {{FRAC_CONST(-0.6004210114), FRAC_CONST(0.7996840477)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.9562535882), FRAC_CONST(-0.2925389707)}}, + {{FRAC_CONST(-0.9114028811), FRAC_CONST(-0.4115152657)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.1827499419), FRAC_CONST(-0.9831594229)}}, + {{FRAC_CONST(0.2027882934), FRAC_CONST(-0.9792225957)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.7872582674), FRAC_CONST(-0.6166234016)}}, + {{FRAC_CONST(0.9998766780), FRAC_CONST(-0.0157062728)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.9107555747), FRAC_CONST(0.4129458666)}}, + {{FRAC_CONST(0.2334443331), FRAC_CONST(0.9723701477)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.0549497530), FRAC_CONST(0.9984891415)}}, + {{FRAC_CONST(-0.8980280757), FRAC_CONST(0.4399381876)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.8599416018), FRAC_CONST(0.5103924870)}}, + {{FRAC_CONST(-0.6252418160), FRAC_CONST(-0.7804310918)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(-0.8501682281), FRAC_CONST(-0.5265110731)}}, + {{FRAC_CONST(0.6252435446), FRAC_CONST(-0.7804297209)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.0737608299), FRAC_CONST(-0.9972759485)}}, + {{FRAC_CONST(0.8980270624), FRAC_CONST(0.4399402142)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.9183775187), FRAC_CONST(-0.3957053721)}}, + {{FRAC_CONST(-0.2334465086), FRAC_CONST(0.9723696709)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.7754954696), FRAC_CONST(0.6313531399)}}, + {{FRAC_CONST(-0.9998766184), FRAC_CONST(-0.0157085191)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.2012493610), FRAC_CONST(0.9795400500)}}, + {{FRAC_CONST(-0.2027861029), FRAC_CONST(-0.9792230725)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.9615978599), FRAC_CONST(0.2744622827)}}, + {{FRAC_CONST(0.9114037752), FRAC_CONST(-0.4115132093)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.6879743338), FRAC_CONST(-0.7257350087)}}, + {{FRAC_CONST(0.6004192233), FRAC_CONST(0.7996854186)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(0.3254036009), FRAC_CONST(-0.9455752373)}}, + {{FRAC_CONST(-0.6494490504), FRAC_CONST(0.7604051232)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.9888865948), FRAC_CONST(-0.1486719251)}}, + {{FRAC_CONST(-0.8837650418), FRAC_CONST(-0.4679309726)}, {FRAC_CONST(0.9238795042), FRAC_CONST(-0.3826834261)}, {FRAC_CONST(0.5890548825), FRAC_CONST(0.8080930114)}}, + {{FRAC_CONST(0.2638743520), FRAC_CONST(-0.9645570517)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.4441666007), FRAC_CONST(0.8959442377)}}, + {{FRAC_CONST(0.9988898039), FRAC_CONST(0.0471078083)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(-0.9997915030), FRAC_CONST(0.0204183888)}}, + {{FRAC_CONST(0.1719277352), FRAC_CONST(0.9851095676)}, {FRAC_CONST(0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.4803760946), FRAC_CONST(-0.8770626187)}}, + {{FRAC_CONST(-0.9238800406), FRAC_CONST(0.3826821446)}, {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(0.5555707216), FRAC_CONST(-0.8314692974)}}, + {{FRAC_CONST(-0.5750041008), FRAC_CONST(-0.8181505203)}, {FRAC_CONST(0.3826834261), FRAC_CONST(-0.9238795042)}, {FRAC_CONST(0.9941320419), FRAC_CONST(0.1081734300)}}}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const complex_t Phi_Fract_Qmf[] = { + {FRAC_CONST(0.8181497455), FRAC_CONST(0.5750052333)}, {FRAC_CONST(-0.2638730407), FRAC_CONST(0.9645574093)}, {FRAC_CONST(-0.9969173074), FRAC_CONST(0.0784590989)}, + {FRAC_CONST(-0.4115143716), FRAC_CONST(-0.9114032984)}, {FRAC_CONST(0.7181262970), FRAC_CONST(-0.6959127784)}, {FRAC_CONST(0.8980275989), FRAC_CONST(0.4399391711)}, + {FRAC_CONST(-0.1097343117), FRAC_CONST(0.9939609766)}, {FRAC_CONST(-0.9723699093), FRAC_CONST(0.2334453613)}, {FRAC_CONST(-0.5490227938), FRAC_CONST(-0.8358073831)}, + {FRAC_CONST(0.6004202366), FRAC_CONST(-0.7996846437)}, {FRAC_CONST(0.9557930231), FRAC_CONST(0.2940403223)}, {FRAC_CONST(0.0471064523), FRAC_CONST(0.9988898635)}, + {FRAC_CONST(-0.9238795042), FRAC_CONST(0.3826834261)}, {FRAC_CONST(-0.6730124950), FRAC_CONST(-0.7396311164)}, {FRAC_CONST(0.4679298103), FRAC_CONST(-0.8837656379)}, + {FRAC_CONST(0.9900236726), FRAC_CONST(0.1409012377)}, {FRAC_CONST(0.2027872950), FRAC_CONST(0.9792228341)}, {FRAC_CONST(-0.8526401520), FRAC_CONST(0.5224985480)}, + {FRAC_CONST(-0.7804304361), FRAC_CONST(-0.6252426505)}, {FRAC_CONST(0.3239174187), FRAC_CONST(-0.9460853338)}, {FRAC_CONST(0.9998766184), FRAC_CONST(-0.0157073177)}, + {FRAC_CONST(0.3534748554), FRAC_CONST(0.9354440570)}, {FRAC_CONST(-0.7604059577), FRAC_CONST(0.6494480371)}, {FRAC_CONST(-0.8686315417), FRAC_CONST(-0.4954586625)}, + {FRAC_CONST(0.1719291061), FRAC_CONST(-0.9851093292)}, {FRAC_CONST(0.9851093292), FRAC_CONST(-0.1719291061)}, {FRAC_CONST(0.4954586625), FRAC_CONST(0.8686315417)}, + {FRAC_CONST(-0.6494480371), FRAC_CONST(0.7604059577)}, {FRAC_CONST(-0.9354440570), FRAC_CONST(-0.3534748554)}, {FRAC_CONST(0.0157073177), FRAC_CONST(-0.9998766184)}, + {FRAC_CONST(0.9460853338), FRAC_CONST(-0.3239174187)}, {FRAC_CONST(0.6252426505), FRAC_CONST(0.7804304361)}, {FRAC_CONST(-0.5224985480), FRAC_CONST(0.8526401520)}, + {FRAC_CONST(-0.9792228341), FRAC_CONST(-0.2027872950)}, {FRAC_CONST(-0.1409012377), FRAC_CONST(-0.9900236726)}, {FRAC_CONST(0.8837656379), FRAC_CONST(-0.4679298103)}, + {FRAC_CONST(0.7396311164), FRAC_CONST(0.6730124950)}, {FRAC_CONST(-0.3826834261), FRAC_CONST(0.9238795042)}, {FRAC_CONST(-0.9988898635), FRAC_CONST(-0.0471064523)}, + {FRAC_CONST(-0.2940403223), FRAC_CONST(-0.9557930231)}, {FRAC_CONST(0.7996846437), FRAC_CONST(-0.6004202366)}, {FRAC_CONST(0.8358073831), FRAC_CONST(0.5490227938)}, + {FRAC_CONST(-0.2334453613), FRAC_CONST(0.9723699093)}, {FRAC_CONST(-0.9939609766), FRAC_CONST(0.1097343117)}, {FRAC_CONST(-0.4399391711), FRAC_CONST(-0.8980275989)}, + {FRAC_CONST(0.6959127784), FRAC_CONST(-0.7181262970)}, {FRAC_CONST(0.9114032984), FRAC_CONST(0.4115143716)}, {FRAC_CONST(-0.0784590989), FRAC_CONST(0.9969173074)}, + {FRAC_CONST(-0.9645574093), FRAC_CONST(0.2638730407)}, {FRAC_CONST(-0.5750052333), FRAC_CONST(-0.8181497455)}, {FRAC_CONST(0.5750052333), FRAC_CONST(-0.8181497455)}, + {FRAC_CONST(0.9645574093), FRAC_CONST(0.2638730407)}, {FRAC_CONST(0.0784590989), FRAC_CONST(0.9969173074)}, {FRAC_CONST(-0.9114032984), FRAC_CONST(0.4115143716)}, + {FRAC_CONST(-0.6959127784), FRAC_CONST(-0.7181262970)}, {FRAC_CONST(0.4399391711), FRAC_CONST(-0.8980275989)}, {FRAC_CONST(0.9939609766), FRAC_CONST(0.1097343117)}, + {FRAC_CONST(0.2334453613), FRAC_CONST(0.9723699093)}, {FRAC_CONST(-0.8358073831), FRAC_CONST(0.5490227938)}, {FRAC_CONST(-0.7996846437), FRAC_CONST(-0.6004202366)}, + {FRAC_CONST(0.2940403223), FRAC_CONST(-0.9557930231)}, {FRAC_CONST(0.9988898635), FRAC_CONST(-0.0471064523)}, {FRAC_CONST(0.3826834261), FRAC_CONST(0.9238795042)}, + {FRAC_CONST(-0.7396311164), FRAC_CONST(0.6730124950)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +static const hcb hcb1_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, + {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, + {/* 10000 */ 1, 0}, {/* 10001 */ 2, 0}, {/* 10010 */ 3, 0}, {/* 10011 */ 4, 0}, {/* 10100 */ 5, 0}, {/* 10101 */ 6, 0}, {/* 10110 */ 7, 0}, {/* 10111 */ 8, 0}, + {/* 11000 */ 9, 2}, {/* 11001 */ 13, 2}, {/* 11010 */ 17, 2}, {/* 11011 */ 21, 2}, {/* 11100 */ 25, 2}, {/* 11101 */ 29, 2}, {/* 11110 */ 33, 4}, {/* 11111 */ 49, 6}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* defines whether a huffman codebook is unsigned or not */ +/* Table 4.6.2 */ +static const uint8_t unsigned_cb[] = { + 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; +static const int hcb_2_quad_table_size[] = {0, 114, 86, 0, 185, 0, 0, 0, 0, 0, 0, 0}; +static const int hcb_2_pair_table_size[] = {0, 0, 0, 0, 0, 0, 126, 0, 83, 0, 210, 373}; +static const int hcb_bin_table_size[] = {0, 0, 0, 161, 0, 161, 0, 127, 0, 337, 0, 0}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_quad hcb1_2[] = { + {1, 0, 0, 0, 0}, {5, 1, 0, 0, 0}, {5, -1, 0, 0, 0}, {5, 0, 0, 0, -1}, {5, 0, 1, 0, 0}, {5, 0, 0, 0, 1}, {5, 0, 0, -1, 0}, {5, 0, 0, 1, 0}, {5, 0, -1, 0, 0}, + {7, 1, -1, 0, 0}, {7, -1, 1, 0, 0}, {7, 0, 0, -1, 1}, {7, 0, 1, -1, 0}, {7, 0, -1, 1, 0}, {7, 0, 0, 1, -1}, {7, 1, 1, 0, 0}, {7, 0, 0, -1, -1}, {7, -1, -1, 0, 0}, + {7, 0, -1, -1, 0}, {7, 1, 0, -1, 0}, {7, 0, 1, 0, -1}, {7, -1, 0, 1, 0}, {7, 0, 0, 1, 1}, {7, 1, 0, 1, 0}, {7, 0, -1, 0, 1}, {7, 0, 1, 1, 0}, {7, 0, 1, 0, 1}, + {7, -1, 0, -1, 0}, {7, 1, 0, 0, 1}, {7, -1, 0, 0, -1}, {7, 1, 0, 0, -1}, {7, -1, 0, 0, 1}, {7, 0, -1, 0, -1}, {9, 1, 1, -1, 0}, {9, -1, 1, -1, 0}, {9, 1, -1, 1, 0}, + {9, 0, 1, 1, -1}, {9, 0, 1, -1, 1}, {9, 0, -1, 1, 1}, {9, 0, -1, 1, -1}, {9, 1, -1, -1, 0}, {9, 1, 0, -1, 1}, {9, 0, 1, -1, -1}, {9, -1, 1, 1, 0}, {9, -1, 0, 1, -1}, + {9, -1, -1, 1, 0}, {9, 0, -1, -1, 1}, {9, 1, -1, 0, 1}, {9, 1, -1, 0, -1}, {9, -1, 1, 0, -1}, {9, -1, 1, 0, -1}, {9, -1, 1, 0, -1}, {9, -1, 1, 0, -1}, {9, -1, -1, -1, 0}, + {9, -1, -1, -1, 0}, {9, -1, -1, -1, 0}, {9, -1, -1, -1, 0}, {9, 0, -1, -1, -1}, {9, 0, -1, -1, -1}, {9, 0, -1, -1, -1}, {9, 0, -1, -1, -1}, {9, 0, 1, 1, 1}, {9, 0, 1, 1, 1}, + {9, 0, 1, 1, 1}, {9, 0, 1, 1, 1}, {9, 1, 0, 1, -1}, {9, 1, 0, 1, -1}, {9, 1, 0, 1, -1}, {9, 1, 0, 1, -1}, {9, 1, 1, 0, 1}, {9, 1, 1, 0, 1}, {9, 1, 1, 0, 1}, + {9, 1, 1, 0, 1}, {9, -1, 1, 0, 1}, {9, -1, 1, 0, 1}, {9, -1, 1, 0, 1}, {9, -1, 1, 0, 1}, {9, 1, 1, 1, 0}, {9, 1, 1, 1, 0}, {9, 1, 1, 1, 0}, {9, 1, 1, 1, 0}, + {10, -1, -1, 0, 1}, {10, -1, -1, 0, 1}, {10, -1, 0, -1, -1}, {10, -1, 0, -1, -1}, {10, 1, 1, 0, -1}, {10, 1, 1, 0, -1}, {10, 1, 0, -1, -1}, {10, 1, 0, -1, -1}, {10, -1, 0, -1, 1}, + {10, -1, 0, -1, 1}, {10, -1, -1, 0, -1}, {10, -1, -1, 0, -1}, {10, -1, 0, 1, 1}, {10, -1, 0, 1, 1}, {10, 1, 0, 1, 1}, {10, 1, 0, 1, 1}, {11, 1, -1, 1, -1}, {11, -1, 1, -1, 1}, + {11, -1, 1, 1, -1}, {11, 1, -1, -1, 1}, {11, 1, 1, 1, 1}, {11, -1, -1, 1, 1}, {11, 1, 1, -1, -1}, {11, -1, -1, 1, -1}, {11, -1, -1, -1, -1}, {11, 1, 1, -1, 1}, {11, 1, -1, 1, 1}, + {11, -1, 1, 1, 1}, {11, -1, 1, -1, -1}, {11, -1, -1, -1, 1}, {11, 1, -1, -1, -1}, {11, 1, 1, 1, -1}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb2_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* 00100 */ 1, 0}, {/* */ 1, 0}, {/* 00110 */ 2, 0}, {/* 00111 */ 3, 0}, + {/* 01000 */ 4, 0}, {/* 01001 */ 5, 0}, {/* 01010 */ 6, 0}, {/* 01011 */ 7, 0}, {/* 01100 */ 8, 0}, {/* 01101 */ 9, 1}, {/* 01110 */ 11, 1}, {/* 01111 */ 13, 1}, + {/* 10000 */ 15, 1}, {/* 10001 */ 17, 1}, {/* 10010 */ 19, 1}, {/* 10011 */ 21, 1}, {/* 10100 */ 23, 1}, {/* 10101 */ 25, 1}, {/* 10110 */ 27, 1}, {/* 10111 */ 29, 1}, + {/* 11000 */ 31, 1}, {/* 11001 */ 33, 2}, {/* 11010 */ 37, 2}, {/* 11011 */ 41, 2}, {/* 11100 */ 45, 3}, {/* 11101 */ 53, 3}, {/* 11110 */ 61, 3}, {/* 11111 */ 69, 4}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_quad hcb2_2[] = {{3, 0, 0, 0, 0}, {4, 1, 0, 0, 0}, {5, -1, 0, 0, 0}, {5, 0, 0, 0, 1}, {5, 0, 0, -1, 0}, {5, 0, 0, 0, -1}, {5, 0, -1, 0, 0}, {5, 0, 0, 1, 0}, + {5, 0, 1, 0, 0}, {6, 0, -1, 1, 0}, {6, -1, 1, 0, 0}, {6, 0, 1, -1, 0}, {6, 0, 0, 1, -1}, {6, 0, 1, 0, -1}, {6, 0, 0, -1, 1}, {6, -1, 0, 0, -1}, + {6, 1, -1, 0, 0}, {6, 1, 0, -1, 0}, {6, -1, -1, 0, 0}, {6, 0, 0, -1, -1}, {6, 1, 0, 1, 0}, {6, 1, 0, 0, 1}, {6, 0, -1, 0, 1}, {6, -1, 0, 1, 0}, + {6, 0, 1, 0, 1}, {6, 0, -1, -1, 0}, {6, -1, 0, 0, 1}, {6, 0, -1, 0, -1}, {6, -1, 0, -1, 0}, {6, 1, 1, 0, 0}, {6, 0, 1, 1, 0}, {6, 0, 0, 1, 1}, + {6, 1, 0, 0, -1}, {7, 0, 1, -1, 1}, {7, 1, 0, -1, 1}, {7, -1, 1, -1, 0}, {7, 0, -1, 1, -1}, {7, 1, -1, 1, 0}, {7, 1, 1, 0, -1}, {7, 1, 0, 1, 1}, + {7, -1, 1, 1, 0}, {7, 0, -1, -1, 1}, {7, 1, 1, 1, 0}, {7, -1, 0, 1, -1}, {7, -1, -1, -1, 0}, {7, -1, 0, -1, 1}, {7, -1, 0, -1, 1}, {7, 1, -1, -1, 0}, + {7, 1, -1, -1, 0}, {7, 1, 1, -1, 0}, {7, 1, 1, -1, 0}, {8, 1, -1, 0, 1}, {8, -1, 1, 0, -1}, {8, -1, -1, 1, 0}, {8, -1, 0, 1, 1}, {8, -1, -1, 0, 1}, + {8, -1, -1, 0, -1}, {8, 0, -1, -1, -1}, {8, 1, 0, 1, -1}, {8, 1, 0, -1, -1}, {8, 0, 1, -1, -1}, {8, 0, 1, 1, 1}, {8, -1, 1, 0, 1}, {8, -1, 0, -1, -1}, + {8, 0, 1, 1, -1}, {8, 1, -1, 0, -1}, {8, 0, -1, 1, 1}, {8, 1, 1, 0, 1}, {8, 1, -1, 1, -1}, {8, -1, 1, -1, 1}, {8, -1, 1, -1, 1}, {9, 1, -1, -1, 1}, + {9, -1, -1, -1, -1}, {9, -1, 1, 1, -1}, {9, -1, 1, 1, 1}, {9, 1, 1, 1, 1}, {9, -1, -1, 1, -1}, {9, 1, -1, 1, 1}, {9, -1, 1, -1, -1}, {9, -1, -1, 1, 1}, + {9, 1, 1, -1, -1}, {9, 1, -1, -1, -1}, {9, -1, -1, -1, 1}, {9, 1, 1, -1, 1}, {9, 1, 1, 1, -1}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb_bin_quad hcb3[] = { + {/* 0 */ 0, {1, 2, 0, 0}}, {/* 1 */ 1, {0, 0, 0, 0}}, /* 0 */ + {/* 2 */ 0, {1, 2, 0, 0}}, {/* 3 */ 0, {2, 3, 0, 0}}, {/* 4 */ 0, {3, 4, 0, 0}}, {/* 5 */ 0, {4, 5, 0, 0}}, {/* 6 */ 0, {5, 6, 0, 0}}, {/* 7 */ 0, {6, 7, 0, 0}}, + {/* 8 */ 0, {7, 8, 0, 0}}, {/* 9 */ 1, {1, 0, 0, 0}}, /* 1000 */ + {/* 10 */ 1, {0, 0, 0, 1}}, /* 1001 */ + {/* 11 */ 1, {0, 1, 0, 0}}, /* 1010 */ + {/* 12 */ 1, {0, 0, 1, 0}}, /* 1011 */ + {/* 13 */ 0, {4, 5, 0, 0}}, {/* 14 */ 0, {5, 6, 0, 0}}, {/* 15 */ 0, {6, 7, 0, 0}}, {/* 16 */ 0, {7, 8, 0, 0}}, {/* 17 */ 1, {1, 1, 0, 0}}, {/* 18 */ 1, {0, 0, 1, 1}}, + {/* 19 */ 0, {6, 7, 0, 0}}, {/* 20 */ 0, {7, 8, 0, 0}}, {/* 21 */ 0, {8, 9, 0, 0}}, {/* 22 */ 0, {9, 10, 0, 0}}, {/* 23 */ 0, {10, 11, 0, 0}}, {/* 24 */ 0, {11, 12, 0, 0}}, + {/* 25 */ 1, {0, 1, 1, 0}}, /* 110100 */ + {/* 26 */ 1, {0, 1, 0, 1}}, /* 110101 */ + {/* 27 */ 1, {1, 0, 1, 0}}, /* 110110 */ + {/* 28 */ 1, {0, 1, 1, 1}}, /* 110111 */ + {/* 29 */ 1, {1, 0, 0, 1}}, /* 111000 */ + {/* 30 */ 1, {1, 1, 1, 0}}, /* 111001 */ + {/* 31 */ 0, {6, 7, 0, 0}}, {/* 32 */ 0, {7, 8, 0, 0}}, {/* 33 */ 0, {8, 9, 0, 0}}, {/* 34 */ 0, {9, 10, 0, 0}}, {/* 35 */ 0, {10, 11, 0, 0}}, {/* 36 */ 0, {11, 12, 0, 0}}, + {/* 37 */ 1, {1, 1, 1, 1}}, /* 1110100 */ + {/* 38 */ 1, {1, 0, 1, 1}}, /* 1110101 */ + {/* 39 */ 1, {1, 1, 0, 1}}, /* 1110110 */ + {/* 40 */ 0, {9, 10, 0, 0}}, {/* 41 */ 0, {10, 11, 0, 0}}, {/* 42 */ 0, {11, 12, 0, 0}}, {/* 43 */ 0, {12, 13, 0, 0}}, {/* 44 */ 0, {13, 14, 0, 0}}, {/* 45 */ 0, {14, 15, 0, 0}}, + {/* 46 */ 0, {15, 16, 0, 0}}, {/* 47 */ 0, {16, 17, 0, 0}}, {/* 48 */ 0, {17, 18, 0, 0}}, {/* 49 */ 1, {2, 0, 0, 0}}, /* 11101110 */ + {/* 50 */ 1, {0, 0, 0, 2}}, /* 11101111 */ + {/* 51 */ 1, {0, 0, 1, 2}}, /* 11110000 */ + {/* 52 */ 1, {2, 1, 0, 0}}, /* 11110001 */ + {/* 53 */ 1, {1, 2, 1, 0}}, /* 11110010 */ + {/* 54 */ 0, {13, 14, 0, 0}}, {/* 55 */ 0, {14, 15, 0, 0}}, {/* 56 */ 0, {15, 16, 0, 0}}, {/* 57 */ 0, {16, 17, 0, 0}}, {/* 58 */ 0, {17, 18, 0, 0}}, {/* 59 */ 0, {18, 19, 0, 0}}, + {/* 60 */ 0, {19, 20, 0, 0}}, {/* 61 */ 0, {20, 21, 0, 0}}, {/* 62 */ 0, {21, 22, 0, 0}}, {/* 63 */ 0, {22, 23, 0, 0}}, {/* 64 */ 0, {23, 24, 0, 0}}, {/* 65 */ 0, {24, 25, 0, 0}}, + {/* 66 */ 0, {25, 26, 0, 0}}, {/* 67 */ 1, {0, 0, 2, 1}}, {/* 68 */ 1, {0, 1, 2, 1}}, {/* 69 */ 1, {1, 2, 0, 0}}, {/* 70 */ 1, {0, 1, 1, 2}}, {/* 71 */ 1, {2, 1, 1, 0}}, + {/* 72 */ 1, {0, 0, 2, 0}}, {/* 73 */ 1, {0, 2, 1, 0}}, {/* 74 */ 1, {0, 1, 2, 0}}, {/* 75 */ 1, {0, 2, 0, 0}}, {/* 76 */ 1, {0, 1, 0, 2}}, {/* 77 */ 1, {2, 0, 1, 0}}, + {/* 78 */ 1, {1, 2, 1, 1}}, {/* 79 */ 1, {0, 2, 1, 1}}, {/* 80 */ 1, {1, 1, 2, 0}}, {/* 81 */ 1, {1, 1, 2, 1}}, {/* 82 */ 0, {11, 12, 0, 0}}, {/* 83 */ 0, {12, 13, 0, 0}}, + {/* 84 */ 0, {13, 14, 0, 0}}, {/* 85 */ 0, {14, 15, 0, 0}}, {/* 86 */ 0, {15, 16, 0, 0}}, {/* 87 */ 0, {16, 17, 0, 0}}, {/* 88 */ 0, {17, 18, 0, 0}}, {/* 89 */ 0, {18, 19, 0, 0}}, + {/* 90 */ 0, {19, 20, 0, 0}}, {/* 91 */ 0, {20, 21, 0, 0}}, {/* 92 */ 0, {21, 22, 0, 0}}, {/* 93 */ 1, {1, 2, 0, 1}}, /* 1111101010 */ + {/* 94 */ 1, {1, 0, 2, 0}}, /* 1111101011 */ + {/* 95 */ 1, {1, 0, 2, 1}}, /* 1111101100 */ + {/* 96 */ 1, {0, 2, 0, 1}}, /* 1111101101 */ + {/* 97 */ 1, {2, 1, 1, 1}}, /* 1111101110 */ + {/* 98 */ 1, {1, 1, 1, 2}}, /* 1111101111 */ + {/* 99 */ 1, {2, 1, 0, 1}}, /* 1111110000 */ + {/* 00 */ 1, {1, 0, 1, 2}}, /* 1111110001 */ + {/* 01 */ 1, {0, 0, 2, 2}}, /* 1111110010 */ + {/* 02 */ 1, {0, 1, 2, 2}}, /* 1111110011 */ + {/* 03 */ 1, {2, 2, 1, 0}}, /* 1111110100 */ + {/* 04 */ 1, {1, 2, 2, 0}}, /* 1111110101 */ + {/* 05 */ 1, {1, 0, 0, 2}}, /* 1111110110 */ + {/* 06 */ 1, {2, 0, 0, 1}}, /* 1111110111 */ + {/* 07 */ 1, {0, 2, 2, 1}}, /* 1111111000 */ + {/* 08 */ 0, {7, 8, 0, 0}}, {/* 09 */ 0, {8, 9, 0, 0}}, {/* 10 */ 0, {9, 10, 0, 0}}, {/* 11 */ 0, {10, 11, 0, 0}}, {/* 12 */ 0, {11, 12, 0, 0}}, {/* 13 */ 0, {12, 13, 0, 0}}, + {/* 14 */ 0, {13, 14, 0, 0}}, {/* 15 */ 1, {2, 2, 0, 0}}, /* 11111110010 */ + {/* 16 */ 1, {1, 2, 2, 1}}, /* 11111110011 */ + {/* 17 */ 1, {1, 1, 0, 2}}, /* 11111110100 */ + {/* 18 */ 1, {2, 0, 1, 1}}, /* 11111110101 */ + {/* 19 */ 1, {1, 1, 2, 2}}, /* 11111110110 */ + {/* 20 */ 1, {2, 2, 1, 1}}, /* 11111110111 */ + {/* 21 */ 1, {0, 2, 2, 0}}, /* 11111111000 */ + {/* 22 */ 1, {0, 2, 1, 2}}, /* 11111111001 */ + {/* 23 */ 0, {6, 7, 0, 0}}, {/* 24 */ 0, {7, 8, 0, 0}}, {/* 25 */ 0, {8, 9, 0, 0}}, {/* 26 */ 0, {9, 10, 0, 0}}, {/* 27 */ 0, {10, 11, 0, 0}}, {/* 28 */ 0, {11, 12, 0, 0}}, + {/* 29 */ 1, {1, 0, 2, 2}}, /* 111111110100 */ + {/* 30 */ 1, {2, 2, 0, 1}}, /* 111111110101 */ + {/* 31 */ 1, {2, 1, 2, 0}}, /* 111111110110 */ + {/* 32 */ 1, {2, 2, 2, 0}}, /* 111111110111 */ + {/* 33 */ 1, {0, 2, 2, 2}}, /* 111111111000 */ + {/* 34 */ 1, {2, 2, 2, 1}}, /* 111111111001 */ + {/* 35 */ 1, {2, 1, 2, 1}}, /* 111111111010 */ + {/* 36 */ 1, {1, 2, 1, 2}}, /* 111111111011 */ + {/* 37 */ 1, {1, 2, 2, 2}}, /* 111111111100 */ + {/* 38 */ 0, {3, 4, 0, 0}}, {/* 39 */ 0, {4, 5, 0, 0}}, {/* 40 */ 0, {5, 6, 0, 0}}, {/* 41 */ 1, {0, 2, 0, 2}}, /* 1111111111010 */ + {/* 42 */ 1, {2, 0, 2, 0}}, /* 1111111111011 */ + {/* 43 */ 1, {1, 2, 0, 2}}, /* 1111111111100 */ + {/* 44 */ 0, {3, 4, 0, 0}}, {/* 45 */ 0, {4, 5, 0, 0}}, {/* 46 */ 0, {5, 6, 0, 0}}, {/* 47 */ 1, {2, 0, 2, 1}}, /* 11111111111010 */ + {/* 48 */ 1, {2, 1, 1, 2}}, /* 11111111111011 */ + {/* 49 */ 1, {2, 1, 0, 2}}, /* 11111111111100 */ + {/* 50 */ 0, {3, 4, 0, 0}}, {/* 51 */ 0, {4, 5, 0, 0}}, {/* 52 */ 0, {5, 6, 0, 0}}, {/* 53 */ 1, {2, 2, 2, 2}}, /* 111111111111010 */ + {/* 54 */ 1, {2, 2, 1, 2}}, /* 111111111111011 */ + {/* 55 */ 1, {2, 1, 2, 2}}, /* 111111111111100 */ + {/* 56 */ 1, {2, 0, 1, 2}}, /* 111111111111101 */ + {/* 57 */ 1, {2, 0, 0, 2}}, /* 111111111111110 */ + {/* 58 */ 0, {1, 2, 0, 0}}, {/* 59 */ 1, {2, 2, 0, 2}}, /* 1111111111111110 */ + {/* 60 */ 1, {2, 0, 2, 2}} /* 1111111111111111 */ +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb4_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* 00010 */ 1, 0}, {/* */ 1, 0}, {/* 00100 */ 2, 0}, {/* */ 2, 0}, {/* 00110 */ 3, 0}, {/* */ 3, 0}, + {/* 01000 */ 4, 0}, {/* */ 4, 0}, {/* 01010 */ 5, 0}, {/* */ 5, 0}, {/* 01100 */ 6, 0}, {/* */ 6, 0}, {/* 01110 */ 7, 0}, {/* */ 7, 0}, + {/* 10000 */ 8, 0}, {/* */ 8, 0}, {/* 10010 */ 9, 0}, {/* */ 9, 0}, {/* 10100 */ 10, 0}, {/* 10101 */ 11, 0}, {/* 10110 */ 12, 0}, {/* 10111 */ 13, 0}, + {/* 11000 */ 14, 0}, {/* 11001 */ 15, 0}, {/* 11010 */ 16, 2}, {/* 11011 */ 20, 2}, {/* 11100 */ 24, 3}, {/* 11101 */ 32, 3}, {/* 11110 */ 40, 4}, {/* 11111 */ 56, 7}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_quad hcb4_2[] = { + {4, 1, 1, 1, 1}, {4, 0, 1, 1, 1}, {4, 1, 1, 0, 1}, {4, 1, 1, 1, 0}, {4, 1, 0, 1, 1}, {4, 1, 0, 0, 0}, {4, 1, 1, 0, 0}, {4, 0, 0, 0, 0}, {4, 0, 0, 1, 1}, {4, 1, 0, 1, 0}, + {5, 1, 0, 0, 1}, {5, 0, 1, 1, 0}, {5, 0, 0, 0, 1}, {5, 0, 1, 0, 1}, {5, 0, 0, 1, 0}, {5, 0, 1, 0, 0}, {7, 2, 1, 1, 1}, {7, 1, 1, 2, 1}, {7, 1, 2, 1, 1}, {7, 1, 1, 1, 2}, + {7, 2, 1, 1, 0}, {7, 2, 1, 0, 1}, {7, 1, 2, 1, 0}, {7, 2, 0, 1, 1}, {7, 0, 1, 2, 1}, {7, 0, 1, 2, 1}, {8, 0, 1, 1, 2}, {8, 1, 1, 2, 0}, {8, 0, 2, 1, 1}, {8, 1, 0, 1, 2}, + {8, 1, 2, 0, 1}, {8, 1, 1, 0, 2}, {8, 1, 0, 2, 1}, {8, 2, 1, 0, 0}, {8, 2, 0, 1, 0}, {8, 1, 2, 0, 0}, {8, 2, 0, 0, 1}, {8, 0, 1, 0, 2}, {8, 0, 2, 1, 0}, {8, 0, 0, 1, 2}, + {8, 0, 1, 2, 0}, {8, 0, 1, 2, 0}, {8, 0, 2, 0, 1}, {8, 0, 2, 0, 1}, {8, 1, 0, 0, 2}, {8, 1, 0, 0, 2}, {8, 0, 0, 2, 1}, {8, 0, 0, 2, 1}, {8, 1, 0, 2, 0}, {8, 1, 0, 2, 0}, + {8, 2, 0, 0, 0}, {8, 2, 0, 0, 0}, {8, 0, 0, 0, 2}, {8, 0, 0, 0, 2}, {9, 0, 2, 0, 0}, {9, 0, 0, 2, 0}, {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, + {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, {9, 1, 2, 2, 1}, {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, + {9, 2, 2, 1, 1}, {9, 2, 2, 1, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, {9, 2, 1, 2, 1}, + {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 1, 2, 2}, {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, + {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, {9, 1, 2, 1, 2}, {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, + {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, {9, 2, 1, 1, 2}, {10, 1, 2, 2, 0}, {10, 1, 2, 2, 0}, {10, 1, 2, 2, 0}, {10, 1, 2, 2, 0}, {10, 2, 2, 1, 0}, {10, 2, 2, 1, 0}, + {10, 2, 2, 1, 0}, {10, 2, 2, 1, 0}, {10, 2, 1, 2, 0}, {10, 2, 1, 2, 0}, {10, 2, 1, 2, 0}, {10, 2, 1, 2, 0}, {10, 0, 2, 2, 1}, {10, 0, 2, 2, 1}, {10, 0, 2, 2, 1}, {10, 0, 2, 2, 1}, + {10, 0, 1, 2, 2}, {10, 0, 1, 2, 2}, {10, 0, 1, 2, 2}, {10, 0, 1, 2, 2}, {10, 2, 2, 0, 1}, {10, 2, 2, 0, 1}, {10, 2, 2, 0, 1}, {10, 2, 2, 0, 1}, {10, 0, 2, 1, 2}, {10, 0, 2, 1, 2}, + {10, 0, 2, 1, 2}, {10, 0, 2, 1, 2}, {10, 2, 0, 2, 1}, {10, 2, 0, 2, 1}, {10, 2, 0, 2, 1}, {10, 2, 0, 2, 1}, {10, 1, 0, 2, 2}, {10, 1, 0, 2, 2}, {10, 1, 0, 2, 2}, {10, 1, 0, 2, 2}, + {10, 2, 2, 2, 1}, {10, 2, 2, 2, 1}, {10, 2, 2, 2, 1}, {10, 2, 2, 2, 1}, {10, 1, 2, 0, 2}, {10, 1, 2, 0, 2}, {10, 1, 2, 0, 2}, {10, 1, 2, 0, 2}, {10, 2, 0, 1, 2}, {10, 2, 0, 1, 2}, + {10, 2, 0, 1, 2}, {10, 2, 0, 1, 2}, {10, 2, 1, 0, 2}, {10, 2, 1, 0, 2}, {10, 2, 1, 0, 2}, {10, 2, 1, 0, 2}, {10, 1, 2, 2, 2}, {10, 1, 2, 2, 2}, {10, 1, 2, 2, 2}, {10, 1, 2, 2, 2}, + {11, 2, 1, 2, 2}, {11, 2, 1, 2, 2}, {11, 2, 2, 1, 2}, {11, 2, 2, 1, 2}, {11, 0, 2, 2, 0}, {11, 0, 2, 2, 0}, {11, 2, 2, 0, 0}, {11, 2, 2, 0, 0}, {11, 0, 0, 2, 2}, {11, 0, 0, 2, 2}, + {11, 2, 0, 2, 0}, {11, 2, 0, 2, 0}, {11, 0, 2, 0, 2}, {11, 0, 2, 0, 2}, {11, 2, 0, 0, 2}, {11, 2, 0, 0, 2}, {11, 2, 2, 2, 2}, {11, 2, 2, 2, 2}, {11, 0, 2, 2, 2}, {11, 0, 2, 2, 2}, + {11, 2, 2, 2, 0}, {11, 2, 2, 2, 0}, {12, 2, 2, 0, 2}, {12, 2, 0, 2, 2}, +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb_bin_pair hcb5[] = { + {/* 0 */ 0, {1, 2}}, {/* 1 */ 1, {0, 0}}, /* 0 */ + {/* 2 */ 0, {1, 2}}, {/* 3 */ 0, {2, 3}}, {/* 4 */ 0, {3, 4}}, {/* 5 */ 0, {4, 5}}, {/* 6 */ 0, {5, 6}}, {/* 7 */ 0, {6, 7}}, {/* 8 */ 0, {7, 8}}, + {/* 9 */ 1, {-1, 0}}, /* 1000 */ + {/* 10 */ 1, {1, 0}}, /* 1001 */ + {/* 11 */ 1, {0, 1}}, /* 1010 */ + {/* 12 */ 1, {0, -1}}, /* 1011 */ + {/* 13 */ 0, {4, 5}}, {/* 14 */ 0, {5, 6}}, {/* 15 */ 0, {6, 7}}, {/* 16 */ 0, {7, 8}}, {/* 17 */ 1, {1, -1}}, {/* 18 */ 1, {-1, 1}}, {/* 19 */ 1, {-1, -1}}, + {/* 20 */ 1, {1, 1}}, {/* 21 */ 0, {4, 5}}, {/* 22 */ 0, {5, 6}}, {/* 23 */ 0, {6, 7}}, {/* 24 */ 0, {7, 8}}, {/* 25 */ 0, {8, 9}}, {/* 26 */ 0, {9, 10}}, + {/* 27 */ 0, {10, 11}}, {/* 28 */ 0, {11, 12}}, {/* 29 */ 0, {12, 13}}, {/* 30 */ 0, {13, 14}}, {/* 31 */ 0, {14, 15}}, {/* 32 */ 0, {15, 16}}, {/* 33 */ 1, {-2, 0}}, + {/* 34 */ 1, {0, 2}}, {/* 35 */ 1, {2, 0}}, {/* 36 */ 1, {0, -2}}, {/* 37 */ 0, {12, 13}}, {/* 38 */ 0, {13, 14}}, {/* 39 */ 0, {14, 15}}, {/* 40 */ 0, {15, 16}}, + {/* 41 */ 0, {16, 17}}, {/* 42 */ 0, {17, 18}}, {/* 43 */ 0, {18, 19}}, {/* 44 */ 0, {19, 20}}, {/* 45 */ 0, {20, 21}}, {/* 46 */ 0, {21, 22}}, {/* 47 */ 0, {22, 23}}, + {/* 48 */ 0, {23, 24}}, {/* 49 */ 1, {-2, -1}}, {/* 50 */ 1, {2, 1}}, {/* 51 */ 1, {-1, -2}}, {/* 52 */ 1, {1, 2}}, {/* 53 */ 1, {-2, 1}}, {/* 54 */ 1, {2, -1}}, + {/* 55 */ 1, {-1, 2}}, {/* 56 */ 1, {1, -2}}, {/* 57 */ 1, {-3, 0}}, {/* 58 */ 1, {3, 0}}, {/* 59 */ 1, {0, -3}}, {/* 60 */ 1, {0, 3}}, {/* 61 */ 0, {12, 13}}, + {/* 62 */ 0, {13, 14}}, {/* 63 */ 0, {14, 15}}, {/* 64 */ 0, {15, 16}}, {/* 65 */ 0, {16, 17}}, {/* 66 */ 0, {17, 18}}, {/* 67 */ 0, {18, 19}}, {/* 68 */ 0, {19, 20}}, + {/* 69 */ 0, {20, 21}}, {/* 70 */ 0, {21, 22}}, {/* 71 */ 0, {22, 23}}, {/* 72 */ 0, {23, 24}}, {/* 73 */ 1, {-3, -1}}, {/* 74 */ 1, {1, 3}}, {/* 75 */ 1, {3, 1}}, + {/* 76 */ 1, {-1, -3}}, {/* 77 */ 1, {-3, 1}}, {/* 78 */ 1, {3, -1}}, {/* 79 */ 1, {1, -3}}, {/* 80 */ 1, {-1, 3}}, {/* 81 */ 1, {-2, 2}}, {/* 82 */ 1, {2, 2}}, + {/* 83 */ 1, {-2, -2}}, {/* 84 */ 1, {2, -2}}, {/* 85 */ 0, {12, 13}}, {/* 86 */ 0, {13, 14}}, {/* 87 */ 0, {14, 15}}, {/* 88 */ 0, {15, 16}}, {/* 89 */ 0, {16, 17}}, + {/* 90 */ 0, {17, 18}}, {/* 91 */ 0, {18, 19}}, {/* 92 */ 0, {19, 20}}, {/* 93 */ 0, {20, 21}}, {/* 94 */ 0, {21, 22}}, {/* 95 */ 0, {22, 23}}, {/* 96 */ 0, {23, 24}}, + {/* 97 */ 1, {-3, -2}}, {/* 98 */ 1, {3, -2}}, {/* 99 */ 1, {-2, 3}}, {/* 00 */ 1, {2, -3}}, {/* 01 */ 1, {3, 2}}, {/* 02 */ 1, {2, 3}}, {/* 03 */ 1, {-3, 2}}, + {/* 04 */ 1, {-2, -3}}, {/* 05 */ 1, {0, -4}}, {/* 06 */ 1, {-4, 0}}, {/* 07 */ 1, {4, 1}}, {/* 08 */ 1, {4, 0}}, {/* 09 */ 0, {12, 13}}, {/* 10 */ 0, {13, 14}}, + {/* 11 */ 0, {14, 15}}, {/* 12 */ 0, {15, 16}}, {/* 13 */ 0, {16, 17}}, {/* 14 */ 0, {17, 18}}, {/* 15 */ 0, {18, 19}}, {/* 16 */ 0, {19, 20}}, {/* 17 */ 0, {20, 21}}, + {/* 18 */ 0, {21, 22}}, {/* 19 */ 0, {22, 23}}, {/* 20 */ 0, {23, 24}}, {/* 21 */ 1, {-4, -1}}, {/* 22 */ 1, {0, 4}}, {/* 23 */ 1, {4, -1}}, {/* 24 */ 1, {-1, -4}}, + {/* 25 */ 1, {1, 4}}, {/* 26 */ 1, {-1, 4}}, {/* 27 */ 1, {-4, 1}}, {/* 28 */ 1, {1, -4}}, {/* 29 */ 1, {3, -3}}, {/* 30 */ 1, {-3, -3}}, {/* 31 */ 1, {-3, 3}}, + {/* 32 */ 1, {-2, 4}}, {/* 33 */ 1, {-4, -2}}, {/* 34 */ 1, {4, 2}}, {/* 35 */ 1, {2, -4}}, {/* 36 */ 1, {2, 4}}, {/* 37 */ 1, {3, 3}}, {/* 38 */ 1, {-4, 2}}, + {/* 39 */ 0, {6, 7}}, {/* 40 */ 0, {7, 8}}, {/* 41 */ 0, {8, 9}}, {/* 42 */ 0, {9, 10}}, {/* 43 */ 0, {10, 11}}, {/* 44 */ 0, {11, 12}}, {/* 45 */ 1, {-2, -4}}, + {/* 46 */ 1, {4, -2}}, {/* 47 */ 1, {3, -4}}, {/* 48 */ 1, {-4, -3}}, {/* 49 */ 1, {-4, 3}}, {/* 50 */ 1, {3, 4}}, {/* 51 */ 1, {-3, 4}}, {/* 52 */ 1, {4, 3}}, + {/* 53 */ 1, {4, -3}}, {/* 54 */ 1, {-3, -4}}, {/* 55 */ 0, {2, 3}}, {/* 56 */ 0, {3, 4}}, {/* 57 */ 1, {4, -4}}, {/* 58 */ 1, {-4, 4}}, {/* 59 */ 1, {4, 4}}, + {/* 60 */ 1, {-4, -4}}}; + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb6_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* 00010 */ 1, 0}, {/* */ 1, 0}, {/* 00100 */ 2, 0}, {/* */ 2, 0}, {/* 00110 */ 3, 0}, {/* */ 3, 0}, + {/* 01000 */ 4, 0}, {/* */ 4, 0}, {/* 01010 */ 5, 0}, {/* */ 5, 0}, {/* 01100 */ 6, 0}, {/* */ 6, 0}, {/* 01110 */ 7, 0}, {/* */ 7, 0}, + {/* 10000 */ 8, 0}, {/* */ 8, 0}, {/* 10010 */ 9, 1}, {/* 10011 */ 11, 1}, {/* 10100 */ 13, 1}, {/* 10101 */ 15, 1}, {/* 10110 */ 17, 1}, {/* 10111 */ 19, 1}, + {/* 11000 */ 21, 1}, {/* 11001 */ 23, 1}, {/* 11010 */ 25, 2}, {/* 11011 */ 29, 2}, {/* 11100 */ 33, 2}, {/* 11101 */ 37, 3}, {/* 11110 */ 45, 4}, {/* 11111 */ 61, 6}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_pair hcb6_2[] = { + {4, 0, 0}, {4, 1, 0}, {4, 0, -1}, {4, 0, 1}, {4, -1, 0}, {4, 1, 1}, {4, -1, 1}, {4, 1, -1}, {4, -1, -1}, {6, 2, -1}, {6, 2, 1}, {6, -2, 1}, {6, -2, -1}, {6, -2, 0}, + {6, -1, 2}, {6, 2, 0}, {6, 1, -2}, {6, 1, 2}, {6, 0, -2}, {6, -1, -2}, {6, 0, 2}, {6, 2, -2}, {6, -2, 2}, {6, -2, -2}, {6, 2, 2}, {7, -3, 1}, {7, 3, 1}, {7, 3, -1}, + {7, -1, 3}, {7, -3, -1}, {7, 1, 3}, {7, 1, -3}, {7, -1, -3}, {7, 3, 0}, {7, -3, 0}, {7, 0, -3}, {7, 0, 3}, {7, 3, 2}, {7, 3, 2}, {8, -3, -2}, {8, -2, 3}, {8, 2, 3}, + {8, 3, -2}, {8, 2, -3}, {8, -2, -3}, {8, -3, 2}, {8, -3, 2}, {8, 3, 3}, {8, 3, 3}, {9, 3, -3}, {9, -3, -3}, {9, -3, 3}, {9, 1, -4}, {9, -1, -4}, {9, 4, 1}, {9, -4, 1}, + {9, -4, -1}, {9, 1, 4}, {9, 4, -1}, {9, -1, 4}, {9, 0, -4}, {9, -4, 2}, {9, -4, 2}, {9, -4, 2}, {9, -4, 2}, {9, -4, -2}, {9, -4, -2}, {9, -4, -2}, {9, -4, -2}, {9, 2, 4}, + {9, 2, 4}, {9, 2, 4}, {9, 2, 4}, {9, -2, -4}, {9, -2, -4}, {9, -2, -4}, {9, -2, -4}, {9, -4, 0}, {9, -4, 0}, {9, -4, 0}, {9, -4, 0}, {9, 4, 2}, {9, 4, 2}, {9, 4, 2}, + {9, 4, 2}, {9, 4, -2}, {9, 4, -2}, {9, 4, -2}, {9, 4, -2}, {9, -2, 4}, {9, -2, 4}, {9, -2, 4}, {9, -2, 4}, {9, 4, 0}, {9, 4, 0}, {9, 4, 0}, {9, 4, 0}, {9, 2, -4}, + {9, 2, -4}, {9, 2, -4}, {9, 2, -4}, {9, 0, 4}, {9, 0, 4}, {9, 0, 4}, {9, 0, 4}, {10, -3, -4}, {10, -3, -4}, {10, -3, 4}, {10, -3, 4}, {10, 3, -4}, {10, 3, -4}, {10, 4, -3}, + {10, 4, -3}, {10, 3, 4}, {10, 3, 4}, {10, 4, 3}, {10, 4, 3}, {10, -4, 3}, {10, -4, 3}, {10, -4, -3}, {10, -4, -3}, {11, 4, 4}, {11, -4, 4}, {11, -4, -4}, {11, 4, -4}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb_bin_pair hcb7[] = { + {/* 0 */ 0, {1, 2}}, {/* 1 */ 1, {0, 0}}, {/* 2 */ 0, {1, 2}}, {/* 3 */ 0, {2, 3}}, {/* 4 */ 0, {3, 4}}, {/* 5 */ 1, {1, 0}}, {/* 6 */ 1, {0, 1}}, {/* 7 */ 0, {2, 3}}, + {/* 8 */ 0, {3, 4}}, {/* 9 */ 1, {1, 1}}, {/* 10 */ 0, {3, 4}}, {/* 11 */ 0, {4, 5}}, {/* 12 */ 0, {5, 6}}, {/* 13 */ 0, {6, 7}}, {/* 14 */ 0, {7, 8}}, {/* 15 */ 0, {8, 9}}, + {/* 16 */ 0, {9, 10}}, {/* 17 */ 0, {10, 11}}, {/* 18 */ 0, {11, 12}}, {/* 19 */ 1, {2, 1}}, {/* 20 */ 1, {1, 2}}, {/* 21 */ 1, {2, 0}}, {/* 22 */ 1, {0, 2}}, {/* 23 */ 0, {8, 9}}, + {/* 24 */ 0, {9, 10}}, {/* 25 */ 0, {10, 11}}, {/* 26 */ 0, {11, 12}}, {/* 27 */ 0, {12, 13}}, {/* 28 */ 0, {13, 14}}, {/* 29 */ 0, {14, 15}}, {/* 30 */ 0, {15, 16}}, {/* 31 */ 1, {3, 1}}, + {/* 32 */ 1, {1, 3}}, {/* 33 */ 1, {2, 2}}, {/* 34 */ 1, {3, 0}}, {/* 35 */ 1, {0, 3}}, {/* 36 */ 0, {11, 12}}, {/* 37 */ 0, {12, 13}}, {/* 38 */ 0, {13, 14}}, {/* 39 */ 0, {14, 15}}, + {/* 40 */ 0, {15, 16}}, {/* 41 */ 0, {16, 17}}, {/* 42 */ 0, {17, 18}}, {/* 43 */ 0, {18, 19}}, {/* 44 */ 0, {19, 20}}, {/* 45 */ 0, {20, 21}}, {/* 46 */ 0, {21, 22}}, {/* 47 */ 1, {2, 3}}, + {/* 48 */ 1, {3, 2}}, {/* 49 */ 1, {1, 4}}, {/* 50 */ 1, {4, 1}}, {/* 51 */ 1, {1, 5}}, {/* 52 */ 1, {5, 1}}, {/* 53 */ 1, {3, 3}}, {/* 54 */ 1, {2, 4}}, {/* 55 */ 1, {0, 4}}, + {/* 56 */ 1, {4, 0}}, {/* 57 */ 0, {12, 13}}, {/* 58 */ 0, {13, 14}}, {/* 59 */ 0, {14, 15}}, {/* 60 */ 0, {15, 16}}, {/* 61 */ 0, {16, 17}}, {/* 62 */ 0, {17, 18}}, {/* 63 */ 0, {18, 19}}, + {/* 64 */ 0, {19, 20}}, {/* 65 */ 0, {20, 21}}, {/* 66 */ 0, {21, 22}}, {/* 67 */ 0, {22, 23}}, {/* 68 */ 0, {23, 24}}, {/* 69 */ 1, {4, 2}}, {/* 70 */ 1, {2, 5}}, {/* 71 */ 1, {5, 2}}, + {/* 72 */ 1, {0, 5}}, {/* 73 */ 1, {6, 1}}, {/* 74 */ 1, {5, 0}}, {/* 75 */ 1, {1, 6}}, {/* 76 */ 1, {4, 3}}, {/* 77 */ 1, {3, 5}}, {/* 78 */ 1, {3, 4}}, {/* 79 */ 1, {5, 3}}, + {/* 80 */ 1, {2, 6}}, {/* 81 */ 1, {6, 2}}, {/* 82 */ 1, {1, 7}}, {/* 83 */ 0, {10, 11}}, {/* 84 */ 0, {11, 12}}, {/* 85 */ 0, {12, 13}}, {/* 86 */ 0, {13, 14}}, {/* 87 */ 0, {14, 15}}, + {/* 88 */ 0, {15, 16}}, {/* 89 */ 0, {16, 17}}, {/* 90 */ 0, {17, 18}}, {/* 91 */ 0, {18, 19}}, {/* 92 */ 0, {19, 20}}, {/* 93 */ 1, {3, 6}}, {/* 94 */ 1, {0, 6}}, {/* 95 */ 1, {6, 0}}, + {/* 96 */ 1, {4, 4}}, {/* 97 */ 1, {7, 1}}, {/* 98 */ 1, {4, 5}}, {/* 99 */ 1, {7, 2}}, {/* 00 */ 1, {5, 4}}, {/* 01 */ 1, {6, 3}}, {/* 02 */ 1, {2, 7}}, {/* 03 */ 1, {7, 3}}, + {/* 04 */ 1, {6, 4}}, {/* 05 */ 1, {5, 5}}, {/* 06 */ 1, {4, 6}}, {/* 07 */ 1, {3, 7}}, {/* 08 */ 0, {5, 6}}, {/* 09 */ 0, {6, 7}}, {/* 10 */ 0, {7, 8}}, {/* 11 */ 0, {8, 9}}, + {/* 12 */ 0, {9, 10}}, {/* 13 */ 1, {7, 0}}, {/* 14 */ 1, {0, 7}}, {/* 15 */ 1, {6, 5}}, {/* 16 */ 1, {5, 6}}, {/* 17 */ 1, {7, 4}}, {/* 18 */ 1, {4, 7}}, {/* 19 */ 1, {5, 7}}, + {/* 20 */ 1, {7, 5}}, {/* 21 */ 0, {2, 3}}, {/* 22 */ 0, {3, 4}}, {/* 23 */ 1, {7, 6}}, {/* 24 */ 1, {6, 6}}, {/* 25 */ 1, {6, 7}}, {/* 26 */ 1, {7, 7}}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb8_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* 00100 */ 1, 0}, {/* */ 1, 0}, {/* 00110 */ 2, 0}, {/* */ 2, 0}, + {/* 01000 */ 3, 0}, {/* */ 3, 0}, {/* 01010 */ 4, 0}, {/* */ 4, 0}, {/* 01100 */ 5, 0}, {/* */ 5, 0}, {/* 01110 */ 6, 0}, {/* 01111 */ 7, 0}, + {/* 10000 */ 8, 0}, {/* 10001 */ 9, 0}, {/* 10010 */ 10, 0}, {/* 10011 */ 11, 0}, {/* 10100 */ 12, 0}, {/* 10101 */ 13, 1}, {/* 10110 */ 15, 1}, {/* 10111 */ 17, 1}, + {/* 11000 */ 19, 1}, {/* 11001 */ 21, 1}, {/* 11010 */ 23, 2}, {/* 11011 */ 27, 2}, {/* 11100 */ 31, 2}, {/* 11101 */ 35, 3}, {/* 11110 */ 43, 3}, {/* 11111 */ 51, 5}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w)*/ +static const hcb_2_pair hcb8_2[] = {{3, 1, 1}, {4, 2, 1}, {4, 1, 0}, {4, 1, 2}, {4, 0, 1}, {4, 2, 2}, {5, 0, 0}, {5, 2, 0}, {5, 0, 2}, {5, 3, 1}, {5, 1, 3}, {5, 3, 2}, {5, 2, 3}, {6, 3, 3}, + {6, 4, 1}, {6, 1, 4}, {6, 4, 2}, {6, 2, 4}, {6, 3, 0}, {6, 0, 3}, {6, 4, 3}, {6, 3, 4}, {6, 5, 2}, {7, 5, 1}, {7, 2, 5}, {7, 1, 5}, {7, 5, 3}, {7, 3, 5}, + {7, 4, 4}, {7, 5, 4}, {7, 0, 4}, {7, 4, 5}, {7, 4, 0}, {7, 2, 6}, {7, 6, 2}, {7, 6, 1}, {7, 6, 1}, {7, 1, 6}, {7, 1, 6}, {8, 3, 6}, {8, 6, 3}, {8, 5, 5}, + {8, 5, 0}, {8, 6, 4}, {8, 0, 5}, {8, 4, 6}, {8, 7, 1}, {8, 7, 2}, {8, 2, 7}, {8, 6, 5}, {8, 7, 3}, {8, 1, 7}, {8, 1, 7}, {8, 1, 7}, {8, 1, 7}, {8, 5, 6}, + {8, 5, 6}, {8, 5, 6}, {8, 5, 6}, {8, 3, 7}, {8, 3, 7}, {8, 3, 7}, {8, 3, 7}, {9, 6, 6}, {9, 6, 6}, {9, 7, 4}, {9, 7, 4}, {9, 6, 0}, {9, 6, 0}, {9, 4, 7}, + {9, 4, 7}, {9, 0, 6}, {9, 0, 6}, {9, 7, 5}, {9, 7, 5}, {9, 7, 6}, {9, 7, 6}, {9, 6, 7}, {9, 6, 7}, {10, 5, 7}, {10, 7, 0}, {10, 0, 7}, {10, 7, 7}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Binary search huffman table HCB_9 */ +static const hcb_bin_pair hcb9[] = { + {/* 0 */ 0, {1, 2}}, {/* 1 */ 1, {0, 0}}, {/* 2 */ 0, {1, 2}}, {/* 3 */ 0, {2, 3}}, {/* 4 */ 0, {3, 4}}, {/* 5 */ 1, {1, 0}}, {/* 6 */ 1, {0, 1}}, {/* 7 */ 0, {2, 3}}, + {/* 8 */ 0, {3, 4}}, {/* 9 */ 1, {1, 1}}, {/* 10 */ 0, {3, 4}}, {/* 11 */ 0, {4, 5}}, {/* 12 */ 0, {5, 6}}, {/* 13 */ 0, {6, 7}}, {/* 14 */ 0, {7, 8}}, {/* 15 */ 0, {8, 9}}, + {/* 16 */ 0, {9, 10}}, {/* 17 */ 0, {10, 11}}, {/* 18 */ 0, {11, 12}}, {/* 19 */ 1, {2, 1}}, {/* 20 */ 1, {1, 2}}, {/* 21 */ 1, {2, 0}}, {/* 22 */ 1, {0, 2}}, {/* 23 */ 0, {8, 9}}, + {/* 24 */ 0, {9, 10}}, {/* 25 */ 0, {10, 11}}, {/* 26 */ 0, {11, 12}}, {/* 27 */ 0, {12, 13}}, {/* 28 */ 0, {13, 14}}, {/* 29 */ 0, {14, 15}}, {/* 30 */ 0, {15, 16}}, {/* 31 */ 1, {3, 1}}, + {/* 32 */ 1, {2, 2}}, {/* 33 */ 1, {1, 3}}, {/* 34 */ 0, {13, 14}}, {/* 35 */ 0, {14, 15}}, {/* 36 */ 0, {15, 16}}, {/* 37 */ 0, {16, 17}}, {/* 38 */ 0, {17, 18}}, {/* 39 */ 0, {18, 19}}, + {/* 40 */ 0, {19, 20}}, {/* 41 */ 0, {20, 21}}, {/* 42 */ 0, {21, 22}}, {/* 43 */ 0, {22, 23}}, {/* 44 */ 0, {23, 24}}, {/* 45 */ 0, {24, 25}}, {/* 46 */ 0, {25, 26}}, {/* 47 */ 1, {3, 0}}, + {/* 48 */ 1, {0, 3}}, {/* 49 */ 1, {2, 3}}, {/* 50 */ 1, {3, 2}}, {/* 51 */ 1, {1, 4}}, {/* 52 */ 1, {4, 1}}, {/* 53 */ 1, {2, 4}}, {/* 54 */ 1, {1, 5}}, {/* 55 */ 0, {18, 19}}, + {/* 56 */ 0, {19, 20}}, {/* 57 */ 0, {20, 21}}, {/* 58 */ 0, {21, 22}}, {/* 59 */ 0, {22, 23}}, {/* 60 */ 0, {23, 24}}, {/* 61 */ 0, {24, 25}}, {/* 62 */ 0, {25, 26}}, {/* 63 */ 0, {26, 27}}, + {/* 64 */ 0, {27, 28}}, {/* 65 */ 0, {28, 29}}, {/* 66 */ 0, {29, 30}}, {/* 67 */ 0, {30, 31}}, {/* 68 */ 0, {31, 32}}, {/* 69 */ 0, {32, 33}}, {/* 70 */ 0, {33, 34}}, {/* 71 */ 0, {34, 35}}, + {/* 72 */ 0, {35, 36}}, {/* 73 */ 1, {4, 2}}, {/* 74 */ 1, {3, 3}}, {/* 75 */ 1, {0, 4}}, {/* 76 */ 1, {4, 0}}, {/* 77 */ 1, {5, 1}}, {/* 78 */ 1, {2, 5}}, {/* 79 */ 1, {1, 6}}, + {/* 80 */ 1, {3, 4}}, {/* 81 */ 1, {5, 2}}, {/* 82 */ 1, {6, 1}}, {/* 83 */ 1, {4, 3}}, {/* 84 */ 0, {25, 26}}, {/* 85 */ 0, {26, 27}}, {/* 86 */ 0, {27, 28}}, {/* 87 */ 0, {28, 29}}, + {/* 88 */ 0, {29, 30}}, {/* 89 */ 0, {30, 31}}, {/* 90 */ 0, {31, 32}}, {/* 91 */ 0, {32, 33}}, {/* 92 */ 0, {33, 34}}, {/* 93 */ 0, {34, 35}}, {/* 94 */ 0, {35, 36}}, {/* 95 */ 0, {36, 37}}, + {/* 96 */ 0, {37, 38}}, {/* 97 */ 0, {38, 39}}, {/* 98 */ 0, {39, 40}}, {/* 99 */ 0, {40, 41}}, {/* 00 */ 0, {41, 42}}, {/* 01 */ 0, {42, 43}}, {/* 02 */ 0, {43, 44}}, {/* 03 */ 0, {44, 45}}, + {/* 04 */ 0, {45, 46}}, {/* 05 */ 0, {46, 47}}, {/* 06 */ 0, {47, 48}}, {/* 07 */ 0, {48, 49}}, {/* 08 */ 0, {49, 50}}, {/* 09 */ 1, {0, 5}}, {/* 10 */ 1, {2, 6}}, {/* 11 */ 1, {5, 0}}, + {/* 12 */ 1, {1, 7}}, {/* 13 */ 1, {3, 5}}, {/* 14 */ 1, {1, 8}}, {/* 15 */ 1, {8, 1}}, {/* 16 */ 1, {4, 4}}, {/* 17 */ 1, {5, 3}}, {/* 18 */ 1, {6, 2}}, {/* 19 */ 1, {7, 1}}, + {/* 20 */ 1, {0, 6}}, {/* 21 */ 1, {8, 2}}, {/* 22 */ 1, {2, 8}}, {/* 23 */ 1, {3, 6}}, {/* 24 */ 1, {2, 7}}, {/* 25 */ 1, {4, 5}}, {/* 26 */ 1, {9, 1}}, {/* 27 */ 1, {1, 9}}, + {/* 28 */ 1, {7, 2}}, {/* 29 */ 0, {30, 31}}, {/* 30 */ 0, {31, 32}}, {/* 31 */ 0, {32, 33}}, {/* 32 */ 0, {33, 34}}, {/* 33 */ 0, {34, 35}}, {/* 34 */ 0, {35, 36}}, {/* 35 */ 0, {36, 37}}, + {/* 36 */ 0, {37, 38}}, {/* 37 */ 0, {38, 39}}, {/* 38 */ 0, {39, 40}}, {/* 39 */ 0, {40, 41}}, {/* 40 */ 0, {41, 42}}, {/* 41 */ 0, {42, 43}}, {/* 42 */ 0, {43, 44}}, {/* 43 */ 0, {44, 45}}, + {/* 44 */ 0, {45, 46}}, {/* 45 */ 0, {46, 47}}, {/* 46 */ 0, {47, 48}}, {/* 47 */ 0, {48, 49}}, {/* 48 */ 0, {49, 50}}, {/* 49 */ 0, {50, 51}}, {/* 50 */ 0, {51, 52}}, {/* 51 */ 0, {52, 53}}, + {/* 52 */ 0, {53, 54}}, {/* 53 */ 0, {54, 55}}, {/* 54 */ 0, {55, 56}}, {/* 55 */ 0, {56, 57}}, {/* 56 */ 0, {57, 58}}, {/* 57 */ 0, {58, 59}}, {/* 58 */ 0, {59, 60}}, {/* 59 */ 1, {6, 0}}, + {/* 60 */ 1, {5, 4}}, {/* 61 */ 1, {6, 3}}, {/* 62 */ 1, {8, 3}}, {/* 63 */ 1, {0, 7}}, {/* 64 */ 1, {9, 2}}, {/* 65 */ 1, {3, 8}}, {/* 66 */ 1, {4, 6}}, {/* 67 */ 1, {3, 7}}, + {/* 68 */ 1, {0, 8}}, {/* 69 */ 1, {10, 1}}, {/* 70 */ 1, {6, 4}}, {/* 71 */ 1, {2, 9}}, {/* 72 */ 1, {5, 5}}, {/* 73 */ 1, {8, 0}}, {/* 74 */ 1, {7, 0}}, {/* 75 */ 1, {7, 3}}, + {/* 76 */ 1, {10, 2}}, {/* 77 */ 1, {9, 3}}, {/* 78 */ 1, {8, 4}}, {/* 79 */ 1, {1, 10}}, {/* 80 */ 1, {7, 4}}, {/* 81 */ 1, {6, 5}}, {/* 82 */ 1, {5, 6}}, {/* 83 */ 1, {4, 8}}, + {/* 84 */ 1, {4, 7}}, {/* 85 */ 1, {3, 9}}, {/* 86 */ 1, {11, 1}}, {/* 87 */ 1, {5, 8}}, {/* 88 */ 1, {9, 0}}, {/* 89 */ 1, {8, 5}}, {/* 90 */ 0, {29, 30}}, {/* 91 */ 0, {30, 31}}, + {/* 92 */ 0, {31, 32}}, {/* 93 */ 0, {32, 33}}, {/* 94 */ 0, {33, 34}}, {/* 95 */ 0, {34, 35}}, {/* 96 */ 0, {35, 36}}, {/* 97 */ 0, {36, 37}}, {/* 98 */ 0, {37, 38}}, {/* 99 */ 0, {38, 39}}, + {/* 00 */ 0, {39, 40}}, {/* 01 */ 0, {40, 41}}, {/* 02 */ 0, {41, 42}}, {/* 03 */ 0, {42, 43}}, {/* 04 */ 0, {43, 44}}, {/* 05 */ 0, {44, 45}}, {/* 06 */ 0, {45, 46}}, {/* 07 */ 0, {46, 47}}, + {/* 08 */ 0, {47, 48}}, {/* 09 */ 0, {48, 49}}, {/* 10 */ 0, {49, 50}}, {/* 11 */ 0, {50, 51}}, {/* 12 */ 0, {51, 52}}, {/* 13 */ 0, {52, 53}}, {/* 14 */ 0, {53, 54}}, {/* 15 */ 0, {54, 55}}, + {/* 16 */ 0, {55, 56}}, {/* 17 */ 0, {56, 57}}, {/* 18 */ 0, {57, 58}}, {/* 19 */ 1, {10, 3}}, {/* 20 */ 1, {2, 10}}, {/* 21 */ 1, {0, 9}}, {/* 22 */ 1, {11, 2}}, {/* 23 */ 1, {9, 4}}, + {/* 24 */ 1, {6, 6}}, {/* 25 */ 1, {12, 1}}, {/* 26 */ 1, {4, 9}}, {/* 27 */ 1, {8, 6}}, {/* 28 */ 1, {1, 11}}, {/* 29 */ 1, {9, 5}}, {/* 30 */ 1, {10, 4}}, {/* 31 */ 1, {5, 7}}, + {/* 32 */ 1, {7, 5}}, {/* 33 */ 1, {2, 11}}, {/* 34 */ 1, {1, 12}}, {/* 35 */ 1, {12, 2}}, {/* 36 */ 1, {11, 3}}, {/* 37 */ 1, {3, 10}}, {/* 38 */ 1, {5, 9}}, {/* 39 */ 1, {6, 7}}, + {/* 40 */ 1, {8, 7}}, {/* 41 */ 1, {11, 4}}, {/* 42 */ 1, {0, 10}}, {/* 43 */ 1, {7, 6}}, {/* 44 */ 1, {12, 3}}, {/* 45 */ 1, {10, 0}}, {/* 46 */ 1, {10, 5}}, {/* 47 */ 1, {4, 10}}, + {/* 48 */ 1, {6, 8}}, {/* 49 */ 1, {2, 12}}, {/* 50 */ 1, {9, 6}}, {/* 51 */ 1, {9, 7}}, {/* 52 */ 1, {4, 11}}, {/* 53 */ 1, {11, 0}}, {/* 54 */ 1, {6, 9}}, {/* 55 */ 1, {3, 11}}, + {/* 56 */ 1, {5, 10}}, {/* 57 */ 0, {20, 21}}, {/* 58 */ 0, {21, 22}}, {/* 59 */ 0, {22, 23}}, {/* 60 */ 0, {23, 24}}, {/* 61 */ 0, {24, 25}}, {/* 62 */ 0, {25, 26}}, {/* 63 */ 0, {26, 27}}, + {/* 64 */ 0, {27, 28}}, {/* 65 */ 0, {28, 29}}, {/* 66 */ 0, {29, 30}}, {/* 67 */ 0, {30, 31}}, {/* 68 */ 0, {31, 32}}, {/* 69 */ 0, {32, 33}}, {/* 70 */ 0, {33, 34}}, {/* 71 */ 0, {34, 35}}, + {/* 72 */ 0, {35, 36}}, {/* 73 */ 0, {36, 37}}, {/* 74 */ 0, {37, 38}}, {/* 75 */ 0, {38, 39}}, {/* 76 */ 0, {39, 40}}, {/* 77 */ 1, {8, 8}}, {/* 78 */ 1, {7, 8}}, {/* 79 */ 1, {12, 5}}, + {/* 80 */ 1, {3, 12}}, {/* 81 */ 1, {11, 5}}, {/* 82 */ 1, {7, 7}}, {/* 83 */ 1, {12, 4}}, {/* 84 */ 1, {11, 6}}, {/* 85 */ 1, {10, 6}}, {/* 86 */ 1, {4, 12}}, {/* 87 */ 1, {7, 9}}, + {/* 88 */ 1, {5, 11}}, {/* 89 */ 1, {0, 11}}, {/* 90 */ 1, {12, 6}}, {/* 91 */ 1, {6, 10}}, {/* 92 */ 1, {12, 0}}, {/* 93 */ 1, {10, 7}}, {/* 94 */ 1, {5, 12}}, {/* 95 */ 1, {7, 10}}, + {/* 96 */ 1, {9, 8}}, {/* 97 */ 1, {0, 12}}, {/* 98 */ 1, {11, 7}}, {/* 99 */ 1, {8, 9}}, {/* 00 */ 1, {9, 9}}, {/* 01 */ 1, {10, 8}}, {/* 02 */ 1, {7, 11}}, {/* 03 */ 1, {12, 7}}, + {/* 04 */ 1, {6, 11}}, {/* 05 */ 1, {8, 11}}, {/* 06 */ 1, {11, 8}}, {/* 07 */ 1, {7, 12}}, {/* 08 */ 1, {6, 12}}, {/* 09 */ 0, {8, 9}}, {/* 10 */ 0, {9, 10}}, {/* 11 */ 0, {10, 11}}, + {/* 12 */ 0, {11, 12}}, {/* 13 */ 0, {12, 13}}, {/* 14 */ 0, {13, 14}}, {/* 15 */ 0, {14, 15}}, {/* 16 */ 0, {15, 16}}, {/* 17 */ 1, {8, 10}}, {/* 18 */ 1, {10, 9}}, {/* 19 */ 1, {8, 12}}, + {/* 20 */ 1, {9, 10}}, {/* 21 */ 1, {9, 11}}, {/* 22 */ 1, {9, 12}}, {/* 23 */ 1, {10, 11}}, {/* 24 */ 1, {12, 9}}, {/* 25 */ 1, {10, 10}}, {/* 26 */ 1, {11, 9}}, {/* 27 */ 1, {12, 8}}, + {/* 28 */ 1, {11, 10}}, {/* 29 */ 1, {12, 10}}, {/* 30 */ 1, {12, 11}}, {/* 31 */ 0, {2, 3}}, {/* 32 */ 0, {3, 4}}, {/* 33 */ 1, {10, 12}}, {/* 34 */ 1, {11, 11}}, {/* 35 */ 1, {11, 12}}, + {/* 36 */ 1, {12, 12}}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb10_1[] = { + {/* 000000 */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* */ 0, 0}, {/* 000100 */ 1, 0}, {/* */ 1, 0}, {/* */ 1, 0}, {/* */ 1, 0}, + {/* 001000 */ 2, 0}, {/* */ 2, 0}, {/* */ 2, 0}, {/* */ 2, 0}, {/* 001100 */ 3, 0}, {/* */ 3, 0}, {/* 001110 */ 4, 0}, {/* */ 4, 0}, + {/* 010000 */ 5, 0}, {/* */ 5, 0}, {/* 010010 */ 6, 0}, {/* */ 6, 0}, {/* 010100 */ 7, 0}, {/* */ 7, 0}, {/* 010110 */ 8, 0}, {/* */ 8, 0}, + {/* 011000 */ 9, 0}, {/* */ 9, 0}, {/* 011010 */ 10, 0}, {/* */ 10, 0}, {/* 011100 */ 11, 0}, {/* 011101 */ 12, 0}, {/* 011110 */ 13, 0}, {/* 011111 */ 14, 0}, + {/* 100000 */ 15, 0}, {/* 100001 */ 16, 0}, {/* 100010 */ 17, 0}, {/* 100011 */ 18, 0}, {/* 100100 */ 19, 0}, {/* 100101 */ 20, 0}, {/* 100110 */ 21, 0}, {/* 100111 */ 22, 0}, + {/* 101000 */ 23, 0}, {/* 101001 */ 24, 0}, {/* 101010 */ 25, 1}, {/* 101011 */ 27, 1}, {/* 101100 */ 29, 1}, {/* 101101 */ 31, 1}, {/* 101110 */ 33, 1}, {/* 101111 */ 35, 1}, + {/* 110000 */ 37, 1}, {/* 110001 */ 39, 1}, {/* 110010 */ 41, 2}, {/* 110011 */ 45, 2}, {/* 110100 */ 49, 2}, {/* 110101 */ 53, 2}, {/* 110110 */ 57, 2}, {/* 110111 */ 61, 2}, + {/* 111000 */ 65, 3}, {/* 111001 */ 73, 3}, {/* 111010 */ 81, 3}, {/* 111011 */ 89, 3}, {/* 111100 */ 97, 4}, {/* 111101 */ 113, 4}, {/* 111110 */ 129, 4}, {/* 111111 */ 145, 6}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table + * Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_pair hcb10_2[] = { + {4, 1, 1}, {4, 1, 2}, {4, 2, 1}, {5, 2, 2}, {5, 1, 0}, {5, 0, 1}, {5, 1, 3}, {5, 3, 2}, {5, 3, 1}, {5, 2, 3}, {5, 3, 3}, {6, 2, 0}, {6, 0, 2}, {6, 2, 4}, + {6, 4, 2}, {6, 1, 4}, {6, 4, 1}, {6, 0, 0}, {6, 4, 3}, {6, 3, 4}, {6, 3, 0}, {6, 0, 3}, {6, 4, 4}, {6, 2, 5}, {6, 5, 2}, {7, 1, 5}, {7, 5, 1}, {7, 5, 3}, + {7, 3, 5}, {7, 5, 4}, {7, 4, 5}, {7, 6, 2}, {7, 2, 6}, {7, 6, 3}, {7, 4, 0}, {7, 6, 1}, {7, 0, 4}, {7, 1, 6}, {7, 3, 6}, {7, 5, 5}, {7, 6, 4}, {7, 4, 6}, + {7, 4, 6}, {8, 6, 5}, {8, 7, 2}, {8, 3, 7}, {8, 2, 7}, {8, 5, 6}, {8, 8, 2}, {8, 7, 3}, {8, 5, 0}, {8, 7, 1}, {8, 0, 5}, {8, 8, 1}, {8, 1, 7}, {8, 8, 3}, + {8, 7, 4}, {8, 4, 7}, {8, 2, 8}, {8, 6, 6}, {8, 7, 5}, {8, 1, 8}, {8, 3, 8}, {8, 8, 4}, {8, 4, 8}, {8, 5, 7}, {8, 5, 7}, {8, 8, 5}, {8, 8, 5}, {8, 5, 8}, + {8, 5, 8}, {9, 7, 6}, {9, 6, 7}, {9, 9, 2}, {9, 6, 0}, {9, 6, 8}, {9, 9, 3}, {9, 3, 9}, {9, 9, 1}, {9, 2, 9}, {9, 0, 6}, {9, 8, 6}, {9, 9, 4}, {9, 4, 9}, + {9, 10, 2}, {9, 1, 9}, {9, 7, 7}, {9, 8, 7}, {9, 9, 5}, {9, 7, 8}, {9, 10, 3}, {9, 5, 9}, {9, 10, 4}, {9, 2, 10}, {9, 10, 1}, {9, 3, 10}, {9, 9, 6}, {9, 6, 9}, + {9, 6, 9}, {9, 8, 0}, {9, 8, 0}, {9, 4, 10}, {9, 4, 10}, {9, 7, 0}, {9, 7, 0}, {9, 11, 2}, {9, 11, 2}, {10, 7, 9}, {10, 11, 3}, {10, 10, 6}, {10, 1, 10}, {10, 11, 1}, + {10, 9, 7}, {10, 0, 7}, {10, 8, 8}, {10, 10, 5}, {10, 3, 11}, {10, 5, 10}, {10, 8, 9}, {10, 11, 5}, {10, 0, 8}, {10, 11, 4}, {10, 2, 11}, {10, 7, 10}, {10, 6, 10}, {10, 10, 7}, + {10, 4, 11}, {10, 1, 11}, {10, 12, 2}, {10, 9, 8}, {10, 12, 3}, {10, 11, 6}, {10, 5, 11}, {10, 12, 4}, {10, 11, 7}, {10, 12, 5}, {10, 3, 12}, {10, 6, 11}, {10, 9, 0}, {10, 10, 8}, + {10, 10, 0}, {10, 12, 1}, {10, 0, 9}, {10, 4, 12}, {10, 9, 9}, {10, 12, 6}, {10, 12, 6}, {10, 12, 6}, {10, 12, 6}, {10, 2, 12}, {10, 2, 12}, {10, 2, 12}, {10, 2, 12}, {10, 8, 10}, + {10, 8, 10}, {10, 8, 10}, {10, 8, 10}, {11, 9, 10}, {11, 9, 10}, {11, 1, 12}, {11, 1, 12}, {11, 11, 8}, {11, 11, 8}, {11, 12, 7}, {11, 12, 7}, {11, 7, 11}, {11, 7, 11}, {11, 5, 12}, + {11, 5, 12}, {11, 6, 12}, {11, 6, 12}, {11, 10, 9}, {11, 10, 9}, {11, 8, 11}, {11, 8, 11}, {11, 12, 8}, {11, 12, 8}, {11, 0, 10}, {11, 0, 10}, {11, 7, 12}, {11, 7, 12}, {11, 11, 0}, + {11, 11, 0}, {11, 10, 10}, {11, 10, 10}, {11, 11, 9}, {11, 11, 9}, {11, 11, 10}, {11, 11, 10}, {11, 0, 11}, {11, 0, 11}, {11, 11, 11}, {11, 11, 11}, {11, 9, 11}, {11, 9, 11}, {11, 10, 11}, + {11, 10, 11}, {11, 12, 0}, {11, 12, 0}, {11, 8, 12}, {11, 8, 12}, {12, 12, 9}, {12, 10, 12}, {12, 9, 12}, {12, 11, 12}, {12, 12, 11}, {12, 0, 12}, {12, 12, 10}, {12, 12, 12}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb hcb11_1[] = {{/* 00000 */ 0, 0}, {/* */ 0, 0}, {/* 00010 */ 1, 0}, {/* */ 1, 0}, {/* 00100 */ 2, 0}, {/* 00101 */ 3, 0}, {/* 00110 */ 4, 0}, + {/* 00111 */ 5, 0}, {/* 01000 */ 6, 0}, {/* 01001 */ 7, 0}, {/* 01010 */ 8, 1}, {/* 01011 */ 10, 1}, {/* 01100 */ 12, 1}, {/* 01101 */ 14, 2}, + {/* 01110 */ 18, 2}, {/* 01111 */ 22, 2}, {/* 10000 */ 26, 2}, {/* 10001 */ 30, 3}, {/* 10010 */ 38, 3}, {/* 10011 */ 46, 3}, {/* 10100 */ 54, 3}, + {/* 10101 */ 62, 3}, {/* 10110 */ 70, 3}, {/* 10111 */ 78, 3}, {/* 11000 */ 86, 4}, {/* 11001 */ 102, 4}, {/* 11010 */ 118, 4}, {/* 11011 */ 134, 4}, + {/* 11100 */ 150, 5}, {/* 11101 */ 182, 5}, {/* 11110 */ 214, 5}, {/* 11111 */ 246, 7}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 2nd step table, Gives size of codeword and actual data (x,y,v,w) */ +static const hcb_2_pair hcb11_2[] = { + {4, 0, 0}, {4, 1, 1}, {5, 16, 16}, {5, 1, 0}, {5, 0, 1}, {5, 2, 1}, {5, 1, 2}, {5, 2, 2}, {6, 1, 3}, {6, 3, 1}, {6, 3, 2}, {6, 2, 0}, {6, 2, 3}, {6, 0, 2}, + {6, 3, 3}, {6, 3, 3}, {7, 4, 1}, {7, 1, 4}, {7, 4, 2}, {7, 2, 4}, {7, 4, 3}, {7, 3, 4}, {7, 3, 0}, {7, 0, 3}, {7, 5, 1}, {7, 5, 2}, {7, 2, 5}, {7, 4, 4}, + {7, 1, 5}, {7, 5, 3}, {7, 3, 5}, {7, 3, 5}, {7, 5, 4}, {7, 5, 4}, {8, 4, 5}, {8, 6, 2}, {8, 2, 6}, {8, 6, 1}, {8, 6, 3}, {8, 3, 6}, {8, 1, 6}, {8, 4, 16}, + {8, 3, 16}, {8, 16, 5}, {8, 16, 3}, {8, 16, 4}, {8, 6, 4}, {8, 16, 6}, {8, 4, 0}, {8, 4, 6}, {8, 0, 4}, {8, 2, 16}, {8, 5, 5}, {8, 5, 16}, {8, 16, 7}, {8, 16, 2}, + {8, 16, 8}, {8, 2, 7}, {8, 7, 2}, {8, 3, 7}, {8, 6, 5}, {8, 5, 6}, {8, 6, 16}, {8, 16, 10}, {8, 7, 3}, {8, 7, 1}, {8, 16, 9}, {8, 7, 16}, {8, 1, 16}, {8, 1, 7}, + {8, 4, 7}, {8, 16, 11}, {8, 7, 4}, {8, 16, 12}, {8, 8, 16}, {8, 16, 1}, {8, 6, 6}, {8, 9, 16}, {8, 2, 8}, {8, 5, 7}, {8, 10, 16}, {8, 16, 13}, {8, 8, 3}, {8, 8, 2}, + {8, 3, 8}, {8, 5, 0}, {8, 16, 14}, {8, 16, 14}, {8, 11, 16}, {8, 11, 16}, {8, 7, 5}, {8, 7, 5}, {8, 4, 8}, {8, 4, 8}, {8, 6, 7}, {8, 6, 7}, {8, 7, 6}, {8, 7, 6}, + {8, 0, 5}, {8, 0, 5}, {9, 8, 4}, {9, 16, 15}, {9, 12, 16}, {9, 1, 8}, {9, 8, 1}, {9, 14, 16}, {9, 5, 8}, {9, 13, 16}, {9, 3, 9}, {9, 8, 5}, {9, 7, 7}, {9, 2, 9}, + {9, 8, 6}, {9, 9, 2}, {9, 9, 3}, {9, 15, 16}, {9, 4, 9}, {9, 6, 8}, {9, 6, 0}, {9, 9, 4}, {9, 5, 9}, {9, 8, 7}, {9, 7, 8}, {9, 1, 9}, {9, 10, 3}, {9, 0, 6}, + {9, 10, 2}, {9, 9, 1}, {9, 9, 5}, {9, 4, 10}, {9, 2, 10}, {9, 9, 6}, {9, 3, 10}, {9, 6, 9}, {9, 10, 4}, {9, 8, 8}, {9, 10, 5}, {9, 9, 7}, {9, 11, 3}, {9, 1, 10}, + {9, 7, 0}, {9, 10, 6}, {9, 7, 9}, {9, 3, 11}, {9, 5, 10}, {9, 10, 1}, {9, 4, 11}, {9, 11, 2}, {9, 13, 2}, {9, 6, 10}, {9, 13, 3}, {9, 13, 3}, {9, 2, 11}, {9, 2, 11}, + {9, 16, 0}, {9, 16, 0}, {9, 5, 11}, {9, 5, 11}, {9, 11, 5}, {9, 11, 5}, {10, 11, 4}, {10, 9, 8}, {10, 7, 10}, {10, 8, 9}, {10, 0, 16}, {10, 4, 13}, {10, 0, 7}, {10, 3, 13}, + {10, 11, 6}, {10, 13, 1}, {10, 13, 4}, {10, 12, 3}, {10, 2, 13}, {10, 13, 5}, {10, 8, 10}, {10, 6, 11}, {10, 10, 8}, {10, 10, 7}, {10, 14, 2}, {10, 12, 4}, {10, 1, 11}, {10, 4, 12}, + {10, 11, 1}, {10, 3, 12}, {10, 1, 13}, {10, 12, 2}, {10, 7, 11}, {10, 3, 14}, {10, 5, 12}, {10, 5, 13}, {10, 14, 4}, {10, 4, 14}, {10, 11, 7}, {10, 14, 3}, {10, 12, 5}, {10, 13, 6}, + {10, 12, 6}, {10, 8, 0}, {10, 11, 8}, {10, 2, 12}, {10, 9, 9}, {10, 14, 5}, {10, 6, 13}, {10, 10, 10}, {10, 15, 2}, {10, 8, 11}, {10, 9, 10}, {10, 14, 6}, {10, 10, 9}, {10, 5, 14}, + {10, 11, 9}, {10, 14, 1}, {10, 2, 14}, {10, 6, 12}, {10, 1, 12}, {10, 13, 8}, {10, 0, 8}, {10, 13, 7}, {10, 7, 12}, {10, 12, 7}, {10, 7, 13}, {10, 15, 3}, {10, 12, 1}, {10, 6, 14}, + {10, 2, 15}, {10, 15, 5}, {10, 15, 4}, {10, 1, 14}, {10, 9, 11}, {10, 4, 15}, {10, 14, 7}, {10, 8, 13}, {10, 13, 9}, {10, 8, 12}, {10, 5, 15}, {10, 3, 15}, {10, 10, 11}, {10, 11, 10}, + {10, 12, 8}, {10, 15, 6}, {10, 15, 7}, {10, 8, 14}, {10, 15, 1}, {10, 7, 14}, {10, 9, 0}, {10, 0, 9}, {10, 9, 13}, {10, 9, 13}, {10, 9, 13}, {10, 9, 13}, {10, 9, 12}, {10, 9, 12}, + {10, 9, 12}, {10, 9, 12}, {10, 12, 9}, {10, 12, 9}, {10, 12, 9}, {10, 12, 9}, {10, 14, 8}, {10, 14, 8}, {10, 14, 8}, {10, 14, 8}, {10, 10, 13}, {10, 10, 13}, {10, 10, 13}, {10, 10, 13}, + {10, 14, 9}, {10, 14, 9}, {10, 14, 9}, {10, 14, 9}, {10, 12, 10}, {10, 12, 10}, {10, 12, 10}, {10, 12, 10}, {10, 6, 15}, {10, 6, 15}, {10, 6, 15}, {10, 6, 15}, {10, 7, 15}, {10, 7, 15}, + {10, 7, 15}, {10, 7, 15}, {11, 9, 14}, {11, 9, 14}, {11, 15, 8}, {11, 15, 8}, {11, 11, 11}, {11, 11, 11}, {11, 11, 14}, {11, 11, 14}, {11, 1, 15}, {11, 1, 15}, {11, 10, 12}, {11, 10, 12}, + {11, 10, 14}, {11, 10, 14}, {11, 13, 11}, {11, 13, 11}, {11, 13, 10}, {11, 13, 10}, {11, 11, 13}, {11, 11, 13}, {11, 11, 12}, {11, 11, 12}, {11, 8, 15}, {11, 8, 15}, {11, 14, 11}, {11, 14, 11}, + {11, 13, 12}, {11, 13, 12}, {11, 12, 13}, {11, 12, 13}, {11, 15, 9}, {11, 15, 9}, {11, 14, 10}, {11, 14, 10}, {11, 10, 0}, {11, 10, 0}, {11, 12, 11}, {11, 12, 11}, {11, 9, 15}, {11, 9, 15}, + {11, 0, 10}, {11, 0, 10}, {11, 12, 12}, {11, 12, 12}, {11, 11, 0}, {11, 11, 0}, {11, 12, 14}, {11, 12, 14}, {11, 10, 15}, {11, 10, 15}, {11, 13, 13}, {11, 13, 13}, {11, 0, 13}, {11, 0, 13}, + {11, 14, 12}, {11, 14, 12}, {11, 15, 10}, {11, 15, 10}, {11, 15, 11}, {11, 15, 11}, {11, 11, 15}, {11, 11, 15}, {11, 14, 13}, {11, 14, 13}, {11, 13, 0}, {11, 13, 0}, {11, 0, 11}, {11, 0, 11}, + {11, 13, 14}, {11, 13, 14}, {11, 15, 12}, {11, 15, 12}, {11, 15, 13}, {11, 15, 13}, {11, 12, 15}, {11, 12, 15}, {11, 14, 0}, {11, 14, 0}, {11, 14, 14}, {11, 14, 14}, {11, 13, 15}, {11, 13, 15}, + {11, 12, 0}, {11, 12, 0}, {11, 14, 15}, {11, 14, 15}, {12, 0, 14}, {12, 0, 12}, {12, 15, 14}, {12, 15, 0}, {12, 0, 15}, {12, 15, 15}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Binary search huffman table HCB_SF */ +static const uint8_t hcb_sf[][2] = { + {/* 0 */ 1, 2}, {/* 1 */ 60, 0}, {/* 2 */ 1, 2}, {/* 3 */ 2, 3}, {/* 4 */ 3, 4}, {/* 5 */ 59, 0}, {/* 6 */ 3, 4}, {/* 7 */ 4, 5}, {/* 8 */ 5, 6}, {/* 9 */ 61, 0}, + {/* 10 */ 58, 0}, {/* 11 */ 62, 0}, {/* 12 */ 3, 4}, {/* 13 */ 4, 5}, {/* 14 */ 5, 6}, {/* 15 */ 57, 0}, {/* 16 */ 63, 0}, {/* 17 */ 4, 5}, {/* 18 */ 5, 6}, {/* 19 */ 6, 7}, + {/* 20 */ 7, 8}, {/* 21 */ 56, 0}, {/* 22 */ 64, 0}, {/* 23 */ 55, 0}, {/* 24 */ 65, 0}, {/* 25 */ 4, 5}, {/* 26 */ 5, 6}, {/* 27 */ 6, 7}, {/* 28 */ 7, 8}, {/* 29 */ 66, 0}, + {/* 30 */ 54, 0}, {/* 31 */ 67, 0}, {/* 32 */ 5, 6}, {/* 33 */ 6, 7}, {/* 34 */ 7, 8}, {/* 35 */ 8, 9}, {/* 36 */ 9, 10}, {/* 37 */ 53, 0}, {/* 38 */ 68, 0}, {/* 39 */ 52, 0}, + {/* 40 */ 69, 0}, {/* 41 */ 51, 0}, {/* 42 */ 5, 6}, {/* 43 */ 6, 7}, {/* 44 */ 7, 8}, {/* 45 */ 8, 9}, {/* 46 */ 9, 10}, {/* 47 */ 70, 0}, {/* 48 */ 50, 0}, {/* 49 */ 49, 0}, + {/* 50 */ 71, 0}, {/* 51 */ 6, 7}, {/* 52 */ 7, 8}, {/* 53 */ 8, 9}, {/* 54 */ 9, 10}, {/* 55 */ 10, 11}, {/* 56 */ 11, 12}, {/* 57 */ 72, 0}, {/* 58 */ 48, 0}, {/* 59 */ 73, 0}, + {/* 60 */ 47, 0}, {/* 61 */ 74, 0}, {/* 62 */ 46, 0}, {/* 63 */ 6, 7}, {/* 64 */ 7, 8}, {/* 65 */ 8, 9}, {/* 66 */ 9, 10}, {/* 67 */ 10, 11}, {/* 68 */ 11, 12}, {/* 69 */ 76, 0}, + {/* 70 */ 75, 0}, {/* 71 */ 77, 0}, {/* 72 */ 78, 0}, {/* 73 */ 45, 0}, {/* 74 */ 43, 0}, {/* 75 */ 6, 7}, {/* 76 */ 7, 8}, {/* 77 */ 8, 9}, {/* 78 */ 9, 10}, {/* 79 */ 10, 11}, + {/* 80 */ 11, 12}, {/* 81 */ 44, 0}, {/* 82 */ 79, 0}, {/* 83 */ 42, 0}, {/* 84 */ 41, 0}, {/* 85 */ 80, 0}, {/* 86 */ 40, 0}, {/* 87 */ 6, 7}, {/* 88 */ 7, 8}, {/* 89 */ 8, 9}, + {/* 90 */ 9, 10}, {/* 91 */ 10, 11}, {/* 92 */ 11, 12}, {/* 93 */ 81, 0}, {/* 94 */ 39, 0}, {/* 95 */ 82, 0}, {/* 96 */ 38, 0}, {/* 97 */ 83, 0}, {/* 98 */ 7, 8}, {/* 99 */ 8, 9}, + {/* 00 */ 9, 10}, {/* 01 */ 10, 11}, {/* 02 */ 11, 12}, {/* 03 */ 12, 13}, {/* 04 */ 13, 14}, {/* 05 */ 37, 0}, {/* 06 */ 35, 0}, {/* 07 */ 85, 0}, {/* 08 */ 33, 0}, {/* 09 */ 36, 0}, + {/* 10 */ 34, 0}, {/* 11 */ 84, 0}, {/* 12 */ 32, 0}, {/* 13 */ 6, 7}, {/* 14 */ 7, 8}, {/* 15 */ 8, 9}, {/* 16 */ 9, 10}, {/* 17 */ 10, 11}, {/* 18 */ 11, 12}, {/* 19 */ 87, 0}, + {/* 20 */ 89, 0}, {/* 21 */ 30, 0}, {/* 22 */ 31, 0}, {/* 23 */ 8, 9}, {/* 24 */ 9, 10}, {/* 25 */ 10, 11}, {/* 26 */ 11, 12}, {/* 27 */ 12, 13}, {/* 28 */ 13, 14}, {/* 29 */ 14, 15}, + {/* 30 */ 15, 16}, {/* 31 */ 86, 0}, {/* 32 */ 29, 0}, {/* 33 */ 26, 0}, {/* 34 */ 27, 0}, {/* 35 */ 28, 0}, {/* 36 */ 24, 0}, {/* 37 */ 88, 0}, {/* 38 */ 9, 10}, {/* 39 */ 10, 11}, + {/* 40 */ 11, 12}, {/* 41 */ 12, 13}, {/* 42 */ 13, 14}, {/* 43 */ 14, 15}, {/* 44 */ 15, 16}, {/* 45 */ 16, 17}, {/* 46 */ 17, 18}, {/* 47 */ 25, 0}, {/* 48 */ 22, 0}, {/* 49 */ 23, 0}, + {/* 50 */ 15, 16}, {/* 51 */ 16, 17}, {/* 52 */ 17, 18}, {/* 53 */ 18, 19}, {/* 54 */ 19, 20}, {/* 55 */ 20, 21}, {/* 56 */ 21, 22}, {/* 57 */ 22, 23}, {/* 58 */ 23, 24}, {/* 59 */ 24, 25}, + {/* 60 */ 25, 26}, {/* 61 */ 26, 27}, {/* 62 */ 27, 28}, {/* 63 */ 28, 29}, {/* 64 */ 29, 30}, {/* 65 */ 90, 0}, {/* 66 */ 21, 0}, {/* 67 */ 19, 0}, {/* 68 */ 3, 0}, {/* 69 */ 1, 0}, + {/* 70 */ 2, 0}, {/* 71 */ 0, 0}, {/* 72 */ 23, 24}, {/* 73 */ 24, 25}, {/* 74 */ 25, 26}, {/* 75 */ 26, 27}, {/* 76 */ 27, 28}, {/* 77 */ 28, 29}, {/* 78 */ 29, 30}, {/* 79 */ 30, 31}, + {/* 80 */ 31, 32}, {/* 81 */ 32, 33}, {/* 82 */ 33, 34}, {/* 83 */ 34, 35}, {/* 84 */ 35, 36}, {/* 85 */ 36, 37}, {/* 86 */ 37, 38}, {/* 87 */ 38, 39}, {/* 88 */ 39, 40}, {/* 89 */ 40, 41}, + {/* 90 */ 41, 42}, {/* 91 */ 42, 43}, {/* 92 */ 43, 44}, {/* 93 */ 44, 45}, {/* 94 */ 45, 46}, {/* 95 */ 98, 0}, {/* 96 */ 99, 0}, {/* 97 */ 100, 0}, {/* 98 */ 101, 0}, {/* 99 */ 102, 0}, + {/* 00 */ 117, 0}, {/* 01 */ 97, 0}, {/* 02 */ 91, 0}, {/* 03 */ 92, 0}, {/* 04 */ 93, 0}, {/* 05 */ 94, 0}, {/* 06 */ 95, 0}, {/* 07 */ 96, 0}, {/* 08 */ 104, 0}, {/* 09 */ 111, 0}, + {/* 10 */ 112, 0}, {/* 11 */ 113, 0}, {/* 12 */ 114, 0}, {/* 13 */ 115, 0}, {/* 14 */ 116, 0}, {/* 15 */ 110, 0}, {/* 16 */ 105, 0}, {/* 17 */ 106, 0}, {/* 18 */ 107, 0}, {/* 19 */ 108, 0}, + {/* 20 */ 109, 0}, {/* 21 */ 118, 0}, {/* 22 */ 6, 0}, {/* 23 */ 8, 0}, {/* 24 */ 9, 0}, {/* 25 */ 10, 0}, {/* 26 */ 5, 0}, {/* 27 */ 103, 0}, {/* 28 */ 120, 0}, {/* 29 */ 119, 0}, + {/* 30 */ 4, 0}, {/* 31 */ 7, 0}, {/* 32 */ 15, 0}, {/* 33 */ 16, 0}, {/* 34 */ 18, 0}, {/* 35 */ 20, 0}, {/* 36 */ 17, 0}, {/* 37 */ 11, 0}, {/* 38 */ 12, 0}, {/* 39 */ 14, 0}, + {/* 40 */ 13, 0}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const hcb* hcb_table[] = {0, hcb1_1, hcb2_1, 0, hcb4_1, 0, hcb6_1, 0, hcb8_1, 0, hcb10_1, hcb11_1}; +static const hcb_2_quad* hcb_2_quad_table[] = {0, hcb1_2, hcb2_2, 0, hcb4_2, 0, 0, 0, 0, 0, 0, 0}; +static const hcb_2_pair* hcb_2_pair_table[] = {0, 0, 0, 0, 0, 0, hcb6_2, 0, hcb8_2, 0, hcb10_2, hcb11_2}; +static const hcb_bin_pair* hcb_bin_table[] = {0, 0, 0, 0, 0, hcb5, 0, hcb7, 0, hcb9, 0, 0}; +static const uint8_t hcbN[] = {0, 5, 5, 0, 5, 0, 5, 0, 5, 0, 6, 5}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const uint8_t PreSortCB_STD[NUM_CB] = {11, 9, 7, 5, 3, 1}; +const uint8_t PreSortCB_ER[NUM_CB_ER] = {11, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 9, 7, 5, 3, 1}; +/* 8.5.3.3.2 Derivation of segment width */ +const uint8_t maxCwLen[MAX_CB] = {0, 11, 9, 20, 16, 13, 11, 14, 12, 17, 14, 49, 0, 0, 0, 0, 14, 17, 21, 21, 25, 25, 29, 29, 29, 29, 33, 33, 33, 37, 37, 41}; + +/* bit-twiddling helpers */ +const uint8_t S[] = {1, 2, 4, 8, 16}; +const uint32_t B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +// w_array_real[i] = cos(2*M_PI*i/32) +static const real_t w_array_real[] = {FRAC_CONST(1.000000000000000), FRAC_CONST(0.980785279337272), FRAC_CONST(0.923879528329380), FRAC_CONST(0.831469603195765), + FRAC_CONST(0.707106765732237), FRAC_CONST(0.555570210304169), FRAC_CONST(0.382683402077046), FRAC_CONST(0.195090284503576), + FRAC_CONST(0.000000000000000), FRAC_CONST(-0.195090370246552), FRAC_CONST(-0.382683482845162), FRAC_CONST(-0.555570282993553), + FRAC_CONST(-0.707106827549476), FRAC_CONST(-0.831469651765257), FRAC_CONST(-0.923879561784627), FRAC_CONST(-0.980785296392607)}; +// w_array_imag[i] = sin(-2*M_PI*i/32) +static const real_t w_array_imag[] = {FRAC_CONST(0.000000000000000), FRAC_CONST(-0.195090327375064), FRAC_CONST(-0.382683442461104), FRAC_CONST(-0.555570246648862), + FRAC_CONST(-0.707106796640858), FRAC_CONST(-0.831469627480512), FRAC_CONST(-0.923879545057005), FRAC_CONST(-0.980785287864940), + FRAC_CONST(-1.000000000000000), FRAC_CONST(-0.980785270809601), FRAC_CONST(-0.923879511601754), FRAC_CONST(-0.831469578911016), + FRAC_CONST(-0.707106734823616), FRAC_CONST(-0.555570173959476), FRAC_CONST(-0.382683361692986), FRAC_CONST(-0.195090241632088)}; + // FFT decimation in frequency + // 4*16*2+16=128+16=144 multiplications + // 6*16*2+10*8+4*16*2=192+80+128=400 additions + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +/* 256 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_2048[] = { + {FRAC_CONST(0.999999926465718), FRAC_CONST(0.000383495187571)}, {FRAC_CONST(0.999994043728986), FRAC_CONST(0.003451449920136)}, {FRAC_CONST(0.999978748667469), FRAC_CONST(0.006519372166339)}, + {FRAC_CONST(0.999954041425130), FRAC_CONST(0.009587233049729)}, {FRAC_CONST(0.999919922234523), FRAC_CONST(0.012655003694430)}, {FRAC_CONST(0.999876391416790), FRAC_CONST(0.015722655225417)}, + {FRAC_CONST(0.999823449381662), FRAC_CONST(0.018790158768785)}, {FRAC_CONST(0.999761096627447), FRAC_CONST(0.021857485452022)}, {FRAC_CONST(0.999689333741034), FRAC_CONST(0.024924606404281)}, + {FRAC_CONST(0.999608161397882), FRAC_CONST(0.027991492756653)}, {FRAC_CONST(0.999517580362017), FRAC_CONST(0.031058115642435)}, {FRAC_CONST(0.999417591486022), FRAC_CONST(0.034124446197403)}, + {FRAC_CONST(0.999308195711029), FRAC_CONST(0.037190455560088)}, {FRAC_CONST(0.999189394066715), FRAC_CONST(0.040256114872041)}, {FRAC_CONST(0.999061187671285), FRAC_CONST(0.043321395278110)}, + {FRAC_CONST(0.998923577731466), FRAC_CONST(0.046386267926707)}, {FRAC_CONST(0.998776565542496), FRAC_CONST(0.049450703970085)}, {FRAC_CONST(0.998620152488109), FRAC_CONST(0.052514674564603)}, + {FRAC_CONST(0.998454340040525), FRAC_CONST(0.055578150871005)}, {FRAC_CONST(0.998279129760433), FRAC_CONST(0.058641104054683)}, {FRAC_CONST(0.998094523296980), FRAC_CONST(0.061703505285957)}, + {FRAC_CONST(0.997900522387752), FRAC_CONST(0.064765325740340)}, {FRAC_CONST(0.997697128858759), FRAC_CONST(0.067826536598811)}, {FRAC_CONST(0.997484344624418), FRAC_CONST(0.070887109048088)}, + {FRAC_CONST(0.997262171687536), FRAC_CONST(0.073947014280897)}, {FRAC_CONST(0.997030612139289), FRAC_CONST(0.077006223496246)}, {FRAC_CONST(0.996789668159205), FRAC_CONST(0.080064707899691)}, + {FRAC_CONST(0.996539342015138), FRAC_CONST(0.083122438703613)}, {FRAC_CONST(0.996279636063255), FRAC_CONST(0.086179387127485)}, {FRAC_CONST(0.996010552748006), FRAC_CONST(0.089235524398144)}, + {FRAC_CONST(0.995732094602106), FRAC_CONST(0.092290821750062)}, {FRAC_CONST(0.995444264246510), FRAC_CONST(0.095345250425618)}, {FRAC_CONST(0.995147064390386), FRAC_CONST(0.098398781675364)}, + {FRAC_CONST(0.994840497831093), FRAC_CONST(0.101451386758302)}, {FRAC_CONST(0.994524567454152), FRAC_CONST(0.104503036942151)}, {FRAC_CONST(0.994199276233219), FRAC_CONST(0.107553703503616)}, + {FRAC_CONST(0.993864627230060), FRAC_CONST(0.110603357728662)}, {FRAC_CONST(0.993520623594518), FRAC_CONST(0.113651970912782)}, {FRAC_CONST(0.993167268564487), FRAC_CONST(0.116699514361268)}, + {FRAC_CONST(0.992804565465879), FRAC_CONST(0.119745959389480)}, {FRAC_CONST(0.992432517712594), FRAC_CONST(0.122791277323117)}, {FRAC_CONST(0.992051128806486), FRAC_CONST(0.125835439498487)}, + {FRAC_CONST(0.991660402337333), FRAC_CONST(0.128878417262777)}, {FRAC_CONST(0.991260341982802), FRAC_CONST(0.131920181974320)}, {FRAC_CONST(0.990850951508414), FRAC_CONST(0.134960705002869)}, + {FRAC_CONST(0.990432234767506), FRAC_CONST(0.137999957729863)}, {FRAC_CONST(0.990004195701201), FRAC_CONST(0.141037911548698)}, {FRAC_CONST(0.989566838338365), FRAC_CONST(0.144074537864995)}, + {FRAC_CONST(0.989120166795573), FRAC_CONST(0.147109808096872)}, {FRAC_CONST(0.988664185277066), FRAC_CONST(0.150143693675208)}, {FRAC_CONST(0.988198898074718), FRAC_CONST(0.153176166043918)}, + {FRAC_CONST(0.987724309567987), FRAC_CONST(0.156207196660216)}, {FRAC_CONST(0.987240424223882), FRAC_CONST(0.159236756994888)}, {FRAC_CONST(0.986747246596917), FRAC_CONST(0.162264818532558)}, + {FRAC_CONST(0.986244781329065), FRAC_CONST(0.165291352771958)}, {FRAC_CONST(0.985733033149723), FRAC_CONST(0.168316331226195)}, {FRAC_CONST(0.985212006875659), FRAC_CONST(0.171339725423019)}, + {FRAC_CONST(0.984681707410971), FRAC_CONST(0.174361506905094)}, {FRAC_CONST(0.984142139747039), FRAC_CONST(0.177381647230260)}, {FRAC_CONST(0.983593308962479), FRAC_CONST(0.180400117971807)}, + {FRAC_CONST(0.983035220223096), FRAC_CONST(0.183416890718739)}, {FRAC_CONST(0.982467878781833), FRAC_CONST(0.186431937076042)}, {FRAC_CONST(0.981891289978725), FRAC_CONST(0.189445228664950)}, + {FRAC_CONST(0.981305459240845), FRAC_CONST(0.192456737123217)}, {FRAC_CONST(0.980710392082254), FRAC_CONST(0.195466434105377)}, {FRAC_CONST(0.980106094103952), FRAC_CONST(0.198474291283016)}, + {FRAC_CONST(0.979492570993821), FRAC_CONST(0.201480280345038)}, {FRAC_CONST(0.978869828526574), FRAC_CONST(0.204484372997927)}, {FRAC_CONST(0.978237872563701), FRAC_CONST(0.207486540966021)}, + {FRAC_CONST(0.977596709053412), FRAC_CONST(0.210486755991770)}, {FRAC_CONST(0.976946344030582), FRAC_CONST(0.213484989836008)}, {FRAC_CONST(0.976286783616694), FRAC_CONST(0.216481214278217)}, + {FRAC_CONST(0.975618034019782), FRAC_CONST(0.219475401116790)}, {FRAC_CONST(0.974940101534372), FRAC_CONST(0.222467522169302)}, {FRAC_CONST(0.974252992541423), FRAC_CONST(0.225457549272769)}, + {FRAC_CONST(0.973556713508266), FRAC_CONST(0.228445454283916)}, {FRAC_CONST(0.972851270988544), FRAC_CONST(0.231431209079446)}, {FRAC_CONST(0.972136671622152), FRAC_CONST(0.234414785556295)}, + {FRAC_CONST(0.971412922135171), FRAC_CONST(0.237396155631907)}, {FRAC_CONST(0.970680029339806), FRAC_CONST(0.240375291244489)}, {FRAC_CONST(0.969938000134324), FRAC_CONST(0.243352164353285)}, + {FRAC_CONST(0.969186841502986), FRAC_CONST(0.246326746938829)}, {FRAC_CONST(0.968426560515983), FRAC_CONST(0.249299011003218)}, {FRAC_CONST(0.967657164329370), FRAC_CONST(0.252268928570371)}, + {FRAC_CONST(0.966878660184996), FRAC_CONST(0.255236471686292)}, {FRAC_CONST(0.966091055410439), FRAC_CONST(0.258201612419335)}, {FRAC_CONST(0.965294357418935), FRAC_CONST(0.261164322860466)}, + {FRAC_CONST(0.964488573709308), FRAC_CONST(0.264124575123528)}, {FRAC_CONST(0.963673711865903), FRAC_CONST(0.267082341345496)}, {FRAC_CONST(0.962849779558509), FRAC_CONST(0.270037593686751)}, + {FRAC_CONST(0.962016784542291), FRAC_CONST(0.272990304331330)}, {FRAC_CONST(0.961174734657714), FRAC_CONST(0.275940445487197)}, {FRAC_CONST(0.960323637830474), FRAC_CONST(0.278887989386500)}, + {FRAC_CONST(0.959463502071418), FRAC_CONST(0.281832908285833)}, {FRAC_CONST(0.958594335476470), FRAC_CONST(0.284775174466498)}, {FRAC_CONST(0.957716146226559), FRAC_CONST(0.287714760234765)}, + {FRAC_CONST(0.956828942587535), FRAC_CONST(0.290651637922133)}, {FRAC_CONST(0.955932732910098), FRAC_CONST(0.293585779885591)}, {FRAC_CONST(0.955027525629714), FRAC_CONST(0.296517158507877)}, + {FRAC_CONST(0.954113329266539), FRAC_CONST(0.299445746197740)}, {FRAC_CONST(0.953190152425337), FRAC_CONST(0.302371515390196)}, {FRAC_CONST(0.952258003795400), FRAC_CONST(0.305294438546792)}, + {FRAC_CONST(0.951316892150466), FRAC_CONST(0.308214488155861)}, {FRAC_CONST(0.950366826348636), FRAC_CONST(0.311131636732785)}, {FRAC_CONST(0.949407815332292), FRAC_CONST(0.314045856820251)}, + {FRAC_CONST(0.948439868128010), FRAC_CONST(0.316957120988508)}, {FRAC_CONST(0.947462993846478), FRAC_CONST(0.319865401835631)}, {FRAC_CONST(0.946477201682409), FRAC_CONST(0.322770671987771)}, + {FRAC_CONST(0.945482500914454), FRAC_CONST(0.325672904099420)}, {FRAC_CONST(0.944478900905116), FRAC_CONST(0.328572070853664)}, {FRAC_CONST(0.943466411100659), FRAC_CONST(0.331468144962441)}, + {FRAC_CONST(0.942445041031025), FRAC_CONST(0.334361099166799)}, {FRAC_CONST(0.941414800309736), FRAC_CONST(0.337250906237151)}, {FRAC_CONST(0.940375698633812), FRAC_CONST(0.340137538973532)}, + {FRAC_CONST(0.939327745783671), FRAC_CONST(0.343020970205856)}, {FRAC_CONST(0.938270951623047), FRAC_CONST(0.345901172794169)}, {FRAC_CONST(0.937205326098888), FRAC_CONST(0.348778119628908)}, + {FRAC_CONST(0.936130879241267), FRAC_CONST(0.351651783631155)}, {FRAC_CONST(0.935047621163287), FRAC_CONST(0.354522137752887)}, {FRAC_CONST(0.933955562060987), FRAC_CONST(0.357389154977241)}, + {FRAC_CONST(0.932854712213241), FRAC_CONST(0.360252808318757)}, {FRAC_CONST(0.931745081981669), FRAC_CONST(0.363113070823639)}, {FRAC_CONST(0.930626681810532), FRAC_CONST(0.365969915570009)}, + {FRAC_CONST(0.929499522226639), FRAC_CONST(0.368823315668154)}, {FRAC_CONST(0.928363613839244), FRAC_CONST(0.371673244260787)}, {FRAC_CONST(0.927218967339952), FRAC_CONST(0.374519674523293)}, + {FRAC_CONST(0.926065593502609), FRAC_CONST(0.377362579663988)}, {FRAC_CONST(0.924903503183211), FRAC_CONST(0.380201932924366)}, {FRAC_CONST(0.923732707319793), FRAC_CONST(0.383037707579352)}, + {FRAC_CONST(0.922553216932333), FRAC_CONST(0.385869876937555)}, {FRAC_CONST(0.921365043122642), FRAC_CONST(0.388698414341519)}, {FRAC_CONST(0.920168197074266), FRAC_CONST(0.391523293167972)}, + {FRAC_CONST(0.918962690052376), FRAC_CONST(0.394344486828080)}, {FRAC_CONST(0.917748533403661), FRAC_CONST(0.397161968767692)}, {FRAC_CONST(0.916525738556228), FRAC_CONST(0.399975712467595)}, + {FRAC_CONST(0.915294317019487), FRAC_CONST(0.402785691443764)}, {FRAC_CONST(0.914054280384047), FRAC_CONST(0.405591879247604)}, {FRAC_CONST(0.912805640321604), FRAC_CONST(0.408394249466208)}, + {FRAC_CONST(0.911548408584834), FRAC_CONST(0.411192775722600)}, {FRAC_CONST(0.910282597007282), FRAC_CONST(0.413987431675985)}, {FRAC_CONST(0.909008217503247), FRAC_CONST(0.416778191021998)}, + {FRAC_CONST(0.907725282067676), FRAC_CONST(0.419565027492947)}, {FRAC_CONST(0.906433802776045), FRAC_CONST(0.422347914858067)}, {FRAC_CONST(0.905133791784250), FRAC_CONST(0.425126826923762)}, + {FRAC_CONST(0.903825261328488), FRAC_CONST(0.427901737533854)}, {FRAC_CONST(0.902508223725146), FRAC_CONST(0.430672620569827)}, {FRAC_CONST(0.901182691370685), FRAC_CONST(0.433439449951074)}, + {FRAC_CONST(0.899848676741519), FRAC_CONST(0.436202199635144)}, {FRAC_CONST(0.898506192393902), FRAC_CONST(0.438960843617984)}, {FRAC_CONST(0.897155250963809), FRAC_CONST(0.441715355934187)}, + {FRAC_CONST(0.895795865166814), FRAC_CONST(0.444465710657234)}, {FRAC_CONST(0.894428047797974), FRAC_CONST(0.447211881899738)}, {FRAC_CONST(0.893051811731707), FRAC_CONST(0.449953843813691)}, + {FRAC_CONST(0.891667169921672), FRAC_CONST(0.452691570590701)}, {FRAC_CONST(0.890274135400645), FRAC_CONST(0.455425036462242)}, {FRAC_CONST(0.888872721280396), FRAC_CONST(0.458154215699893)}, + {FRAC_CONST(0.887462940751569), FRAC_CONST(0.460879082615579)}, {FRAC_CONST(0.886044807083556), FRAC_CONST(0.463599611561814)}, {FRAC_CONST(0.884618333624370), FRAC_CONST(0.466315776931944)}, + {FRAC_CONST(0.883183533800523), FRAC_CONST(0.469027553160387)}, {FRAC_CONST(0.881740421116898), FRAC_CONST(0.471734914722871)}, {FRAC_CONST(0.880289009156621), FRAC_CONST(0.474437836136679)}, + {FRAC_CONST(0.878829311580933), FRAC_CONST(0.477136291960885)}, {FRAC_CONST(0.877361342129065), FRAC_CONST(0.479830256796594)}, {FRAC_CONST(0.875885114618104), FRAC_CONST(0.482519705287184)}, + {FRAC_CONST(0.874400642942865), FRAC_CONST(0.485204612118542)}, {FRAC_CONST(0.872907941075761), FRAC_CONST(0.487884952019301)}, {FRAC_CONST(0.871407023066671), FRAC_CONST(0.490560699761082)}, + {FRAC_CONST(0.869897903042806), FRAC_CONST(0.493231830158728)}, {FRAC_CONST(0.868380595208580), FRAC_CONST(0.495898318070542)}, {FRAC_CONST(0.866855113845470), FRAC_CONST(0.498560138398525)}, + {FRAC_CONST(0.865321473311890), FRAC_CONST(0.501217266088610)}, {FRAC_CONST(0.863779688043047), FRAC_CONST(0.503869676130899)}, {FRAC_CONST(0.862229772550811), FRAC_CONST(0.506517343559899)}, + {FRAC_CONST(0.860671741423578), FRAC_CONST(0.509160243454755)}, {FRAC_CONST(0.859105609326130), FRAC_CONST(0.511798350939487)}, {FRAC_CONST(0.857531390999499), FRAC_CONST(0.514431641183223)}, + {FRAC_CONST(0.855949101260827), FRAC_CONST(0.517060089400432)}, {FRAC_CONST(0.854358755003227), FRAC_CONST(0.519683670851158)}, {FRAC_CONST(0.852760367195645), FRAC_CONST(0.522302360841255)}, + {FRAC_CONST(0.851153952882715), FRAC_CONST(0.524916134722613)}, {FRAC_CONST(0.849539527184621), FRAC_CONST(0.527524967893398)}, {FRAC_CONST(0.847917105296951), FRAC_CONST(0.530128835798279)}, + {FRAC_CONST(0.846286702490560), FRAC_CONST(0.532727713928659)}, {FRAC_CONST(0.844648334111418), FRAC_CONST(0.535321577822907)}, {FRAC_CONST(0.843002015580473), FRAC_CONST(0.537910403066589)}, + {FRAC_CONST(0.841347762393502), FRAC_CONST(0.540494165292695)}, {FRAC_CONST(0.839685590120966), FRAC_CONST(0.543072840181872)}, {FRAC_CONST(0.838015514407864), FRAC_CONST(0.545646403462649)}, + {FRAC_CONST(0.836337550973584), FRAC_CONST(0.548214830911668)}, {FRAC_CONST(0.834651715611756), FRAC_CONST(0.550778098353912)}, {FRAC_CONST(0.832958024190107), FRAC_CONST(0.553336181662932)}, + {FRAC_CONST(0.831256492650303), FRAC_CONST(0.555889056761074)}, {FRAC_CONST(0.829547137007809), FRAC_CONST(0.558436699619704)}, {FRAC_CONST(0.827829973351730), FRAC_CONST(0.560979086259438)}, + {FRAC_CONST(0.826105017844665), FRAC_CONST(0.563516192750365)}, {FRAC_CONST(0.824372286722551), FRAC_CONST(0.566047995212271)}, {FRAC_CONST(0.822631796294515), FRAC_CONST(0.568574469814869)}, + {FRAC_CONST(0.820883562942715), FRAC_CONST(0.571095592778017)}, {FRAC_CONST(0.819127603122188), FRAC_CONST(0.573611340371945)}, {FRAC_CONST(0.817363933360698), FRAC_CONST(0.576121688917478)}, + {FRAC_CONST(0.815592570258577), FRAC_CONST(0.578626614786261)}, {FRAC_CONST(0.813813530488567), FRAC_CONST(0.581126094400978)}, {FRAC_CONST(0.812026830795670), FRAC_CONST(0.583620104235573)}, + {FRAC_CONST(0.810232487996982), FRAC_CONST(0.586108620815476)}, {FRAC_CONST(0.808430518981543), FRAC_CONST(0.588591620717823)}, {FRAC_CONST(0.806620940710170), FRAC_CONST(0.591069080571671)}, + {FRAC_CONST(0.804803770215303), FRAC_CONST(0.593540977058226)}, {FRAC_CONST(0.802979024600843), FRAC_CONST(0.596007286911057)}, {FRAC_CONST(0.801146721041991), FRAC_CONST(0.598467986916314)}, + {FRAC_CONST(0.799306876785086), FRAC_CONST(0.600923053912954)}, {FRAC_CONST(0.797459509147442), FRAC_CONST(0.603372464792950)}, {FRAC_CONST(0.795604635517188), FRAC_CONST(0.605816196501515)}, + {FRAC_CONST(0.793742273353100), FRAC_CONST(0.608254226037314)}, {FRAC_CONST(0.791872440184440), FRAC_CONST(0.610686530452686)}, {FRAC_CONST(0.789995153610791), FRAC_CONST(0.613113086853855)}, + {FRAC_CONST(0.788110431301888), FRAC_CONST(0.615533872401147)}, {FRAC_CONST(0.786218290997456), FRAC_CONST(0.617948864309208)}, {FRAC_CONST(0.784318750507039), FRAC_CONST(0.620358039847214)}, + {FRAC_CONST(0.782411827709837), FRAC_CONST(0.622761376339086)}, {FRAC_CONST(0.780497540554532), FRAC_CONST(0.625158851163708)}, {FRAC_CONST(0.778575907059125), FRAC_CONST(0.627550441755132)}, + {FRAC_CONST(0.776646945310762), FRAC_CONST(0.629936125602796)}, {FRAC_CONST(0.774710673465566), FRAC_CONST(0.632315880251738)}, {FRAC_CONST(0.772767109748464), FRAC_CONST(0.634689683302798)}, + {FRAC_CONST(0.770816272453019), FRAC_CONST(0.637057512412839)}, {FRAC_CONST(0.768858179941253), FRAC_CONST(0.639419345294951)}, {FRAC_CONST(0.766892850643481), FRAC_CONST(0.641775159718664)}, + {FRAC_CONST(0.764920303058128), FRAC_CONST(0.644124933510155)}, {FRAC_CONST(0.762940555751566), FRAC_CONST(0.646468644552458)}, {FRAC_CONST(0.760953627357928), FRAC_CONST(0.648806270785673)}, + {FRAC_CONST(0.758959536578942), FRAC_CONST(0.651137790207170)}, {FRAC_CONST(0.756958302183750), FRAC_CONST(0.653463180871802)}, {FRAC_CONST(0.754949943008733), FRAC_CONST(0.655782420892106)}, + {FRAC_CONST(0.752934477957330), FRAC_CONST(0.658095488438511)}, {FRAC_CONST(0.750911925999868), FRAC_CONST(0.660402361739545)}, {FRAC_CONST(0.748882306173375), FRAC_CONST(0.662703019082037)}, + {FRAC_CONST(0.746845637581407), FRAC_CONST(0.664997438811325)}, {FRAC_CONST(0.744801939393863), FRAC_CONST(0.667285599331456)}, {FRAC_CONST(0.742751230846809), FRAC_CONST(0.669567479105392)}, + {FRAC_CONST(0.740693531242296), FRAC_CONST(0.671843056655212)}, {FRAC_CONST(0.738628859948175), FRAC_CONST(0.674112310562312)}, {FRAC_CONST(0.736557236397919), FRAC_CONST(0.676375219467612)}, + {FRAC_CONST(0.734478680090438), FRAC_CONST(0.678631762071749)}, {FRAC_CONST(0.732393210589896), FRAC_CONST(0.680881917135287)}, {FRAC_CONST(0.730300847525525), FRAC_CONST(0.683125663478909)}, + {FRAC_CONST(0.728201610591445), FRAC_CONST(0.685362979983619)}, {FRAC_CONST(0.726095519546471), FRAC_CONST(0.687593845590942)}, {FRAC_CONST(0.723982594213936), FRAC_CONST(0.689818239303122)}, + {FRAC_CONST(0.721862854481496), FRAC_CONST(0.692036140183319)}, {FRAC_CONST(0.719736320300951), FRAC_CONST(0.694247527355803)}, {FRAC_CONST(0.717603011688049), FRAC_CONST(0.696452380006158)}, + {FRAC_CONST(0.715462948722304), FRAC_CONST(0.698650677381469)}, {FRAC_CONST(0.713316151546803), FRAC_CONST(0.700842398790526)}, {FRAC_CONST(0.711162640368018), FRAC_CONST(0.703027523604011)}, + {FRAC_CONST(0.709002435455618), FRAC_CONST(0.705206031254698)}, {FRAC_CONST(0.706835557142274), FRAC_CONST(0.707377901237642)}, {FRAC_CONST(0.704662025823469), FRAC_CONST(0.709543113110377)}, + {FRAC_CONST(0.702481861957308), FRAC_CONST(0.711701646493103)}, {FRAC_CONST(0.700295086064324), FRAC_CONST(0.713853481068882)}, {FRAC_CONST(0.698101718727284), FRAC_CONST(0.715998596583829)}, + {FRAC_CONST(0.695901780590997), FRAC_CONST(0.718136972847297)}, {FRAC_CONST(0.693695292362118), FRAC_CONST(0.720268589732077)}, {FRAC_CONST(0.691482274808956), FRAC_CONST(0.722393427174578)}, + {FRAC_CONST(0.689262748761273), FRAC_CONST(0.724511465175020)}, {FRAC_CONST(0.687036735110096), FRAC_CONST(0.726622683797623)}, {FRAC_CONST(0.684804254807511), FRAC_CONST(0.728727063170794)}, + {FRAC_CONST(0.682565328866473), FRAC_CONST(0.730824583487312)}, {FRAC_CONST(0.680319978360607), FRAC_CONST(0.732915225004518)}, {FRAC_CONST(0.678068224424007), FRAC_CONST(0.734998968044497)}, + {FRAC_CONST(0.675810088251037), FRAC_CONST(0.737075792994266)}, {FRAC_CONST(0.673545591096136), FRAC_CONST(0.739145680305957)}, {FRAC_CONST(0.671274754273613), FRAC_CONST(0.741208610497004)}, + {FRAC_CONST(0.668997599157450), FRAC_CONST(0.743264564150321)}, {FRAC_CONST(0.666714147181098), FRAC_CONST(0.745313521914490)}, {FRAC_CONST(0.664424419837275), FRAC_CONST(0.747355464503940)}, + {FRAC_CONST(0.662128438677769), FRAC_CONST(0.749390372699130)}, {FRAC_CONST(0.659826225313227), FRAC_CONST(0.751418227346727)}, {FRAC_CONST(0.657517801412960), FRAC_CONST(0.753439009359794)}, + {FRAC_CONST(0.655203188704732), FRAC_CONST(0.755452699717958)}, {FRAC_CONST(0.652882408974559), FRAC_CONST(0.757459279467601)}, {FRAC_CONST(0.650555484066504), FRAC_CONST(0.759458729722028)}, + {FRAC_CONST(0.648222435882470), FRAC_CONST(0.761451031661654)}, {FRAC_CONST(0.645883286381996), FRAC_CONST(0.763436166534172)}, {FRAC_CONST(0.643538057582048), FRAC_CONST(0.765414115654738)}, + {FRAC_CONST(0.641186771556811), FRAC_CONST(0.767384860406142)}, {FRAC_CONST(0.638829450437486), FRAC_CONST(0.769348382238982)}, {FRAC_CONST(0.636466116412077), FRAC_CONST(0.771304662671845)}, + {FRAC_CONST(0.634096791725184), FRAC_CONST(0.773253683291473)}, {FRAC_CONST(0.631721498677792), FRAC_CONST(0.775195425752941)}, {FRAC_CONST(0.629340259627066), FRAC_CONST(0.777129871779832)}, + {FRAC_CONST(0.626953096986133), FRAC_CONST(0.779057003164401)}, {FRAC_CONST(0.624560033223877), FRAC_CONST(0.780976801767754)}, {FRAC_CONST(0.622161090864727), FRAC_CONST(0.782889249520015)}, + {FRAC_CONST(0.619756292488441), FRAC_CONST(0.784794328420499)}, {FRAC_CONST(0.617345660729897), FRAC_CONST(0.786692020537877)}, {FRAC_CONST(0.614929218278880), FRAC_CONST(0.788582308010347)}, + {FRAC_CONST(0.612506987879866), FRAC_CONST(0.790465173045805)}, {FRAC_CONST(0.610078992331810), FRAC_CONST(0.792340597922007)}, {FRAC_CONST(0.607645254487931), FRAC_CONST(0.794208564986741)}, + {FRAC_CONST(0.605205797255497), FRAC_CONST(0.796069056657988)}, {FRAC_CONST(0.602760643595607), FRAC_CONST(0.797922055424093)}, {FRAC_CONST(0.600309816522980), FRAC_CONST(0.799767543843926)}, + {FRAC_CONST(0.597853339105734), FRAC_CONST(0.801605504547046)}, {FRAC_CONST(0.595391234465169), FRAC_CONST(0.803435920233868)}, {FRAC_CONST(0.592923525775551), FRAC_CONST(0.805258773675822)}, + {FRAC_CONST(0.590450236263896), FRAC_CONST(0.807074047715518)}, {FRAC_CONST(0.587971389209745), FRAC_CONST(0.808881725266904)}, {FRAC_CONST(0.585487007944951), FRAC_CONST(0.810681789315431)}, + {FRAC_CONST(0.582997115853458), FRAC_CONST(0.812474222918210)}, {FRAC_CONST(0.580501736371077), FRAC_CONST(0.814259009204175)}, {FRAC_CONST(0.578000892985270), FRAC_CONST(0.816036131374237)}, + {FRAC_CONST(0.575494609234928), FRAC_CONST(0.817805572701444)}, {FRAC_CONST(0.572982908710149), FRAC_CONST(0.819567316531142)}, {FRAC_CONST(0.570465815052013), FRAC_CONST(0.821321346281127)}, + {FRAC_CONST(0.567943351952366), FRAC_CONST(0.823067645441802)}, {FRAC_CONST(0.565415543153590), FRAC_CONST(0.824806197576334)}, {FRAC_CONST(0.562882412448385), FRAC_CONST(0.826536986320810)}, + {FRAC_CONST(0.560343983679541), FRAC_CONST(0.828259995384386)}, {FRAC_CONST(0.557800280739717), FRAC_CONST(0.829975208549444)}, {FRAC_CONST(0.555251327571214), FRAC_CONST(0.831682609671745)}, + {FRAC_CONST(0.552697148165750), FRAC_CONST(0.833382182680580)}, {FRAC_CONST(0.550137766564234), FRAC_CONST(0.835073911578919)}, {FRAC_CONST(0.547573206856540), FRAC_CONST(0.836757780443567)}, + {FRAC_CONST(0.545003493181281), FRAC_CONST(0.838433773425308)}, {FRAC_CONST(0.542428649725581), FRAC_CONST(0.840101874749058)}, {FRAC_CONST(0.539848700724848), FRAC_CONST(0.841762068714012)}, + {FRAC_CONST(0.537263670462543), FRAC_CONST(0.843414339693793)}, {FRAC_CONST(0.534673583269956), FRAC_CONST(0.845058672136595)}, {FRAC_CONST(0.532078463525974), FRAC_CONST(0.846695050565337)}, + {FRAC_CONST(0.529478335656852), FRAC_CONST(0.848323459577802)}, {FRAC_CONST(0.526873224135985), FRAC_CONST(0.849943883846782)}, {FRAC_CONST(0.524263153483673), FRAC_CONST(0.851556308120229)}, + {FRAC_CONST(0.521648148266897), FRAC_CONST(0.853160717221390)}, {FRAC_CONST(0.519028233099081), FRAC_CONST(0.854757096048957)}, {FRAC_CONST(0.516403432639864), FRAC_CONST(0.856345429577204)}, + {FRAC_CONST(0.513773771594868), FRAC_CONST(0.857925702856130)}, {FRAC_CONST(0.511139274715464), FRAC_CONST(0.859497901011602)}, {FRAC_CONST(0.508499966798541), FRAC_CONST(0.861062009245491)}, + {FRAC_CONST(0.505855872686269), FRAC_CONST(0.862618012835817)}, {FRAC_CONST(0.503207017265869), FRAC_CONST(0.864165897136879)}, {FRAC_CONST(0.500553425469378), FRAC_CONST(0.865705647579402)}, + {FRAC_CONST(0.497895122273411), FRAC_CONST(0.867237249670668)}, {FRAC_CONST(0.495232132698931), FRAC_CONST(0.868760688994655)}, {FRAC_CONST(0.492564481811011), FRAC_CONST(0.870275951212172)}, + {FRAC_CONST(0.489892194718595), FRAC_CONST(0.871783022060993)}, {FRAC_CONST(0.487215296574269), FRAC_CONST(0.873281887355994)}, {FRAC_CONST(0.484533812574016), FRAC_CONST(0.874772532989284)}, + {FRAC_CONST(0.481847767956986), FRAC_CONST(0.876254944930338)}, {FRAC_CONST(0.479157188005253), FRAC_CONST(0.877729109226132)}, {FRAC_CONST(0.476462098043581), FRAC_CONST(0.879195012001267)}, + {FRAC_CONST(0.473762523439183), FRAC_CONST(0.880652639458111)}, {FRAC_CONST(0.471058489601483), FRAC_CONST(0.882101977876918)}, {FRAC_CONST(0.468350021981877), FRAC_CONST(0.883543013615962)}, + {FRAC_CONST(0.465637146073494), FRAC_CONST(0.884975733111667)}, {FRAC_CONST(0.462919887410955), FRAC_CONST(0.886400122878730)}, {FRAC_CONST(0.460198271570134), FRAC_CONST(0.887816169510255)}, + {FRAC_CONST(0.457472324167916), FRAC_CONST(0.889223859677868)}, {FRAC_CONST(0.454742070861955), FRAC_CONST(0.890623180131856)}, {FRAC_CONST(0.452007537350437), FRAC_CONST(0.892014117701280)}, + {FRAC_CONST(0.449268749371830), FRAC_CONST(0.893396659294108)}, {FRAC_CONST(0.446525732704651), FRAC_CONST(0.894770791897330)}, {FRAC_CONST(0.443778513167218), FRAC_CONST(0.896136502577087)}, + {FRAC_CONST(0.441027116617407), FRAC_CONST(0.897493778478790)}, {FRAC_CONST(0.438271568952410), FRAC_CONST(0.898842606827242)}, {FRAC_CONST(0.435511896108492), FRAC_CONST(0.900182974926757)}, + {FRAC_CONST(0.432748124060744), FRAC_CONST(0.901514870161279)}, {FRAC_CONST(0.429980278822841), FRAC_CONST(0.902838279994503)}, {FRAC_CONST(0.427208386446796), FRAC_CONST(0.904153191969992)}, + {FRAC_CONST(0.424432473022717), FRAC_CONST(0.905459593711293)}, {FRAC_CONST(0.421652564678558), FRAC_CONST(0.906757472922057)}, {FRAC_CONST(0.418868687579875), FRAC_CONST(0.908046817386148)}, + {FRAC_CONST(0.416080867929579), FRAC_CONST(0.909327614967767)}, {FRAC_CONST(0.413289131967691), FRAC_CONST(0.910599853611559)}, {FRAC_CONST(0.410493505971093), FRAC_CONST(0.911863521342729)}, + {FRAC_CONST(0.407694016253280), FRAC_CONST(0.913118606267154)}, {FRAC_CONST(0.404890689164118), FRAC_CONST(0.914365096571498)}, {FRAC_CONST(0.402083551089587), FRAC_CONST(0.915602980523320)}, + {FRAC_CONST(0.399272628451541), FRAC_CONST(0.916832246471184)}, {FRAC_CONST(0.396457947707454), FRAC_CONST(0.918052882844770)}, {FRAC_CONST(0.393639535350173), FRAC_CONST(0.919264878154985)}, + {FRAC_CONST(0.390817417907669), FRAC_CONST(0.920468220994067)}, {FRAC_CONST(0.387991621942785), FRAC_CONST(0.921662900035695)}, {FRAC_CONST(0.385162174052990), FRAC_CONST(0.922848904035094)}, + {FRAC_CONST(0.382329100870125), FRAC_CONST(0.924026221829144)}, {FRAC_CONST(0.379492429060153), FRAC_CONST(0.925194842336480)}, {FRAC_CONST(0.376652185322910), FRAC_CONST(0.926354754557603)}, + {FRAC_CONST(0.373808396391851), FRAC_CONST(0.927505947574975)}, {FRAC_CONST(0.370961089033802), FRAC_CONST(0.928648410553131)}, {FRAC_CONST(0.368110290048703), FRAC_CONST(0.929782132738772)}, + {FRAC_CONST(0.365256026269360), FRAC_CONST(0.930907103460875)}, {FRAC_CONST(0.362398324561191), FRAC_CONST(0.932023312130786)}, {FRAC_CONST(0.359537211821973), FRAC_CONST(0.933130748242325)}, + {FRAC_CONST(0.356672714981588), FRAC_CONST(0.934229401371881)}, {FRAC_CONST(0.353804861001772), FRAC_CONST(0.935319261178512)}, {FRAC_CONST(0.350933676875858), FRAC_CONST(0.936400317404042)}, + {FRAC_CONST(0.348059189628526), FRAC_CONST(0.937472559873159)}, {FRAC_CONST(0.345181426315543), FRAC_CONST(0.938535978493509)}, {FRAC_CONST(0.342300414023514), FRAC_CONST(0.939590563255789)}, + {FRAC_CONST(0.339416179869623), FRAC_CONST(0.940636304233848)}, {FRAC_CONST(0.336528751001382), FRAC_CONST(0.941673191584771)}, {FRAC_CONST(0.333638154596371), FRAC_CONST(0.942701215548982)}, + {FRAC_CONST(0.330744417861983), FRAC_CONST(0.943720366450326)}, {FRAC_CONST(0.327847568035171), FRAC_CONST(0.944730634696168)}, {FRAC_CONST(0.324947632382188), FRAC_CONST(0.945732010777477)}, + {FRAC_CONST(0.322044638198335), FRAC_CONST(0.946724485268921)}, {FRAC_CONST(0.319138612807696), FRAC_CONST(0.947708048828952)}, {FRAC_CONST(0.316229583562890), FRAC_CONST(0.948682692199895)}, + {FRAC_CONST(0.313317577844809), FRAC_CONST(0.949648406208035)}, {FRAC_CONST(0.310402623062359), FRAC_CONST(0.950605181763705)}, {FRAC_CONST(0.307484746652204), FRAC_CONST(0.951553009861369)}, + {FRAC_CONST(0.304563976078509), FRAC_CONST(0.952491881579706)}, {FRAC_CONST(0.301640338832679), FRAC_CONST(0.953421788081700)}, {FRAC_CONST(0.298713862433100), FRAC_CONST(0.954342720614716)}, + {FRAC_CONST(0.295784574424884), FRAC_CONST(0.955254670510587)}, {FRAC_CONST(0.292852502379605), FRAC_CONST(0.956157629185692)}, {FRAC_CONST(0.289917673895041), FRAC_CONST(0.957051588141041)}, + {FRAC_CONST(0.286980116594916), FRAC_CONST(0.957936538962351)}, {FRAC_CONST(0.284039858128637), FRAC_CONST(0.958812473320129)}, {FRAC_CONST(0.281096926171038), FRAC_CONST(0.959679382969747)}, + {FRAC_CONST(0.278151348422115), FRAC_CONST(0.960537259751520)}, {FRAC_CONST(0.275203152606767), FRAC_CONST(0.961386095590786)}, {FRAC_CONST(0.272252366474537), FRAC_CONST(0.962225882497979)}, + {FRAC_CONST(0.269299017799346), FRAC_CONST(0.963056612568704)}, {FRAC_CONST(0.266343134379238), FRAC_CONST(0.963878277983814)}, {FRAC_CONST(0.263384744036113), FRAC_CONST(0.964690871009481)}, + {FRAC_CONST(0.260423874615468), FRAC_CONST(0.965494383997270)}, {FRAC_CONST(0.257460553986133), FRAC_CONST(0.966288809384210)}, {FRAC_CONST(0.254494810040011), FRAC_CONST(0.967074139692867)}, + {FRAC_CONST(0.251526670691813), FRAC_CONST(0.967850367531414)}, {FRAC_CONST(0.248556163878797), FRAC_CONST(0.968617485593698)}, {FRAC_CONST(0.245583317560504), FRAC_CONST(0.969375486659311)}, + {FRAC_CONST(0.242608159718497), FRAC_CONST(0.970124363593660)}, {FRAC_CONST(0.239630718356094), FRAC_CONST(0.970864109348029)}, {FRAC_CONST(0.236651021498106), FRAC_CONST(0.971594716959650)}, + {FRAC_CONST(0.233669097190577), FRAC_CONST(0.972316179551765)}, {FRAC_CONST(0.230684973500512), FRAC_CONST(0.973028490333694)}, {FRAC_CONST(0.227698678515621), FRAC_CONST(0.973731642600896)}, + {FRAC_CONST(0.224710240344050), FRAC_CONST(0.974425629735035)}, {FRAC_CONST(0.221719687114115), FRAC_CONST(0.975110445204039)}, {FRAC_CONST(0.218727046974045), FRAC_CONST(0.975786082562164)}, + {FRAC_CONST(0.215732348091706), FRAC_CONST(0.976452535450054)}, {FRAC_CONST(0.212735618654346), FRAC_CONST(0.977109797594801)}, {FRAC_CONST(0.209736886868323), FRAC_CONST(0.977757862810003)}, + {FRAC_CONST(0.206736180958844), FRAC_CONST(0.978396724995823)}, {FRAC_CONST(0.203733529169694), FRAC_CONST(0.979026378139048)}, {FRAC_CONST(0.200728959762976), FRAC_CONST(0.979646816313141)}, + {FRAC_CONST(0.197722501018842), FRAC_CONST(0.980258033678304)}, {FRAC_CONST(0.194714181235226), FRAC_CONST(0.980860024481524)}, {FRAC_CONST(0.191704028727580), FRAC_CONST(0.981452783056636)}, + {FRAC_CONST(0.188692071828605), FRAC_CONST(0.982036303824369)}, {FRAC_CONST(0.185678338887988), FRAC_CONST(0.982610581292405)}, {FRAC_CONST(0.182662858272129), FRAC_CONST(0.983175610055424)}, + {FRAC_CONST(0.179645658363882), FRAC_CONST(0.983731384795162)}, {FRAC_CONST(0.176626767562281), FRAC_CONST(0.984277900280454)}, {FRAC_CONST(0.173606214282275), FRAC_CONST(0.984815151367289)}, + {FRAC_CONST(0.170584026954464), FRAC_CONST(0.985343132998855)}, {FRAC_CONST(0.167560234024824), FRAC_CONST(0.985861840205587)}, {FRAC_CONST(0.164534863954446), FRAC_CONST(0.986371268105216)}, + {FRAC_CONST(0.161507945219266), FRAC_CONST(0.986871411902812)}, {FRAC_CONST(0.158479506309796), FRAC_CONST(0.987362266890832)}, {FRAC_CONST(0.155449575730856), FRAC_CONST(0.987843828449162)}, + {FRAC_CONST(0.152418182001307), FRAC_CONST(0.988316092045160)}, {FRAC_CONST(0.149385353653780), FRAC_CONST(0.988779053233702)}, {FRAC_CONST(0.146351119234411), FRAC_CONST(0.989232707657220)}, + {FRAC_CONST(0.143315507302572), FRAC_CONST(0.989677051045747)}, {FRAC_CONST(0.140278546430595), FRAC_CONST(0.990112079216954)}, {FRAC_CONST(0.137240265203516), FRAC_CONST(0.990537788076189)}, + {FRAC_CONST(0.134200692218792), FRAC_CONST(0.990954173616519)}, {FRAC_CONST(0.131159856086043), FRAC_CONST(0.991361231918763)}, {FRAC_CONST(0.128117785426777), FRAC_CONST(0.991758959151536)}, + {FRAC_CONST(0.125074508874121), FRAC_CONST(0.992147351571276)}, {FRAC_CONST(0.122030055072553), FRAC_CONST(0.992526405522286)}, {FRAC_CONST(0.118984452677633), FRAC_CONST(0.992896117436766)}, + {FRAC_CONST(0.115937730355728), FRAC_CONST(0.993256483834846)}, {FRAC_CONST(0.112889916783750), FRAC_CONST(0.993607501324622)}, {FRAC_CONST(0.109841040648883), FRAC_CONST(0.993949166602181)}, + {FRAC_CONST(0.106791130648307), FRAC_CONST(0.994281476451642)}, {FRAC_CONST(0.103740215488939), FRAC_CONST(0.994604427745176)}, {FRAC_CONST(0.100688323887154), FRAC_CONST(0.994918017443043)}, + {FRAC_CONST(0.097635484568517), FRAC_CONST(0.995222242593618)}, {FRAC_CONST(0.094581726267515), FRAC_CONST(0.995517100333418)}, {FRAC_CONST(0.091527077727285), FRAC_CONST(0.995802587887129)}, + {FRAC_CONST(0.088471567699341), FRAC_CONST(0.996078702567634)}, {FRAC_CONST(0.085415224943307), FRAC_CONST(0.996345441776036)}, {FRAC_CONST(0.082358078226647), FRAC_CONST(0.996602803001684)}, + {FRAC_CONST(0.079300156324388), FRAC_CONST(0.996850783822197)}, {FRAC_CONST(0.076241488018856), FRAC_CONST(0.997089381903483)}, {FRAC_CONST(0.073182102099403), FRAC_CONST(0.997318594999769)}, + {FRAC_CONST(0.070122027362134), FRAC_CONST(0.997538420953611)}, {FRAC_CONST(0.067061292609637), FRAC_CONST(0.997748857695926)}, {FRAC_CONST(0.063999926650714), FRAC_CONST(0.997949903246001)}, + {FRAC_CONST(0.060937958300107), FRAC_CONST(0.998141555711521)}, {FRAC_CONST(0.057875416378229), FRAC_CONST(0.998323813288578)}, {FRAC_CONST(0.054812329710890), FRAC_CONST(0.998496674261695)}, + {FRAC_CONST(0.051748727129028), FRAC_CONST(0.998660137003838)}, {FRAC_CONST(0.048684637468439), FRAC_CONST(0.998814199976435)}, {FRAC_CONST(0.045620089569500), FRAC_CONST(0.998958861729386)}, + {FRAC_CONST(0.042555112276904), FRAC_CONST(0.999094120901079)}, {FRAC_CONST(0.039489734439384), FRAC_CONST(0.999219976218404)}, {FRAC_CONST(0.036423984909444), FRAC_CONST(0.999336426496761)}, + {FRAC_CONST(0.033357892543086), FRAC_CONST(0.999443470640078)}, {FRAC_CONST(0.030291486199539), FRAC_CONST(0.999541107640813)}, {FRAC_CONST(0.027224794740988), FRAC_CONST(0.999629336579970)}, + {FRAC_CONST(0.024157847032300), FRAC_CONST(0.999708156627105)}, {FRAC_CONST(0.021090671940755), FRAC_CONST(0.999777567040333)}, {FRAC_CONST(0.018023298335774), FRAC_CONST(0.999837567166337)}, + {FRAC_CONST(0.014955755088644), FRAC_CONST(0.999888156440373)}, {FRAC_CONST(0.011888071072252), FRAC_CONST(0.999929334386276)}, {FRAC_CONST(0.008820275160808), FRAC_CONST(0.999961100616463)}, + {FRAC_CONST(0.005752396229574), FRAC_CONST(0.999983454831938)}, {FRAC_CONST(0.002684463154596), FRAC_CONST(0.999996396822294)}}; +/* 64 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_256[] = { + {FRAC_CONST(0.999995293809576), FRAC_CONST(0.003067956762966)}, {FRAC_CONST(0.999618822495179), FRAC_CONST(0.027608145778966)}, {FRAC_CONST(0.998640218180265), FRAC_CONST(0.052131704680283)}, + {FRAC_CONST(0.997060070339483), FRAC_CONST(0.076623861392031)}, {FRAC_CONST(0.994879330794806), FRAC_CONST(0.101069862754828)}, {FRAC_CONST(0.992099313142192), FRAC_CONST(0.125454983411546)}, + {FRAC_CONST(0.988721691960324), FRAC_CONST(0.149764534677322)}, {FRAC_CONST(0.984748501801904), FRAC_CONST(0.173983873387464)}, {FRAC_CONST(0.980182135968117), FRAC_CONST(0.198098410717954)}, + {FRAC_CONST(0.975025345066994), FRAC_CONST(0.222093620973204)}, {FRAC_CONST(0.969281235356549), FRAC_CONST(0.245955050335795)}, {FRAC_CONST(0.962953266873684), FRAC_CONST(0.269668325572915)}, + {FRAC_CONST(0.956045251349996), FRAC_CONST(0.293219162694259)}, {FRAC_CONST(0.948561349915730), FRAC_CONST(0.316593375556166)}, {FRAC_CONST(0.940506070593268), FRAC_CONST(0.339776884406827)}, + {FRAC_CONST(0.931884265581668), FRAC_CONST(0.362755724367397)}, {FRAC_CONST(0.922701128333879), FRAC_CONST(0.385516053843919)}, {FRAC_CONST(0.912962190428398), FRAC_CONST(0.408044162864979)}, + {FRAC_CONST(0.902673318237259), FRAC_CONST(0.430326481340083)}, {FRAC_CONST(0.891840709392343), FRAC_CONST(0.452349587233771)}, {FRAC_CONST(0.880470889052161), FRAC_CONST(0.474100214650550)}, + {FRAC_CONST(0.868570705971341), FRAC_CONST(0.495565261825773)}, {FRAC_CONST(0.856147328375194), FRAC_CONST(0.516731799017650)}, {FRAC_CONST(0.843208239641845), FRAC_CONST(0.537587076295645)}, + {FRAC_CONST(0.829761233794523), FRAC_CONST(0.558118531220556)}, {FRAC_CONST(0.815814410806734), FRAC_CONST(0.578313796411656)}, {FRAC_CONST(0.801376171723140), FRAC_CONST(0.598160706996342)}, + {FRAC_CONST(0.786455213599086), FRAC_CONST(0.617647307937804)}, {FRAC_CONST(0.771060524261814), FRAC_CONST(0.636761861236284)}, {FRAC_CONST(0.755201376896537), FRAC_CONST(0.655492852999615)}, + {FRAC_CONST(0.738887324460615), FRAC_CONST(0.673829000378756)}, {FRAC_CONST(0.722128193929215), FRAC_CONST(0.691759258364158)}, {FRAC_CONST(0.704934080375905), FRAC_CONST(0.709272826438866)}, + {FRAC_CONST(0.687315340891759), FRAC_CONST(0.726359155084346)}, {FRAC_CONST(0.669282588346636), FRAC_CONST(0.743007952135122)}, {FRAC_CONST(0.650846684996381), FRAC_CONST(0.759209188978388)}, + {FRAC_CONST(0.632018735939809), FRAC_CONST(0.774953106594874)}, {FRAC_CONST(0.612810082429410), FRAC_CONST(0.790230221437310)}, {FRAC_CONST(0.593232295039800), FRAC_CONST(0.805031331142964)}, + {FRAC_CONST(0.573297166698042), FRAC_CONST(0.819347520076797)}, {FRAC_CONST(0.553016705580028), FRAC_CONST(0.833170164701913)}, {FRAC_CONST(0.532403127877198), FRAC_CONST(0.846490938774052)}, + {FRAC_CONST(0.511468850437971), FRAC_CONST(0.859301818357008)}, {FRAC_CONST(0.490226483288291), FRAC_CONST(0.871595086655951)}, {FRAC_CONST(0.468688822035828), FRAC_CONST(0.883363338665732)}, + {FRAC_CONST(0.446868840162374), FRAC_CONST(0.894599485631383)}, {FRAC_CONST(0.424779681209109), FRAC_CONST(0.905296759318119)}, {FRAC_CONST(0.402434650859419), FRAC_CONST(0.915448716088268)}, + {FRAC_CONST(0.379847208924051), FRAC_CONST(0.925049240782678)}, {FRAC_CONST(0.357030961233430), FRAC_CONST(0.934092550404259)}, {FRAC_CONST(0.333999651442009), FRAC_CONST(0.942573197601447)}, + {FRAC_CONST(0.310767152749611), FRAC_CONST(0.950486073949482)}, {FRAC_CONST(0.287347459544730), FRAC_CONST(0.957826413027533)}, {FRAC_CONST(0.263754678974832), FRAC_CONST(0.964589793289813)}, + {FRAC_CONST(0.240003022448742), FRAC_CONST(0.970772140728950)}, {FRAC_CONST(0.216106797076220), FRAC_CONST(0.976369731330021)}, {FRAC_CONST(0.192080397049892), FRAC_CONST(0.981379193313755)}, + {FRAC_CONST(0.167938294974731), FRAC_CONST(0.985797509167567)}, {FRAC_CONST(0.143695033150295), FRAC_CONST(0.989622017463201)}, {FRAC_CONST(0.119365214810991), FRAC_CONST(0.992850414459865)}, + {FRAC_CONST(0.094963495329639), FRAC_CONST(0.995480755491927)}, {FRAC_CONST(0.070504573389614), FRAC_CONST(0.997511456140303)}, {FRAC_CONST(0.046003182130915), FRAC_CONST(0.998941293186857)}, + {FRAC_CONST(0.021474080275470), FRAC_CONST(0.999769405351215)}}; + #ifdef LD_DEC +/* 256 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_1024[] = { + {FRAC_CONST(0.999999705862882), FRAC_CONST(0.000766990318743)}, {FRAC_CONST(0.999976174986898), FRAC_CONST(0.006902858724730)}, {FRAC_CONST(0.999914995573113), FRAC_CONST(0.013038467241987)}, + {FRAC_CONST(0.999816169924900), FRAC_CONST(0.019173584868323)}, {FRAC_CONST(0.999679701762988), FRAC_CONST(0.025307980620025)}, {FRAC_CONST(0.999505596225325), FRAC_CONST(0.031441423540560)}, + {FRAC_CONST(0.999293859866888), FRAC_CONST(0.037573682709270)}, {FRAC_CONST(0.999044500659429), FRAC_CONST(0.043704527250063)}, {FRAC_CONST(0.998757527991183), FRAC_CONST(0.049833726340107)}, + {FRAC_CONST(0.998432952666508), FRAC_CONST(0.055961049218521)}, {FRAC_CONST(0.998070786905482), FRAC_CONST(0.062086265195060)}, {FRAC_CONST(0.997671044343441), FRAC_CONST(0.068209143658806)}, + {FRAC_CONST(0.997233740030466), FRAC_CONST(0.074329454086846)}, {FRAC_CONST(0.996758890430818), FRAC_CONST(0.080446966052950)}, {FRAC_CONST(0.996246513422316), FRAC_CONST(0.086561449236251)}, + {FRAC_CONST(0.995696628295664), FRAC_CONST(0.092672673429913)}, {FRAC_CONST(0.995109255753726), FRAC_CONST(0.098780408549800)}, {FRAC_CONST(0.994484417910748), FRAC_CONST(0.104884424643135)}, + {FRAC_CONST(0.993822138291520), FRAC_CONST(0.110984491897163)}, {FRAC_CONST(0.993122441830496), FRAC_CONST(0.117080380647801)}, {FRAC_CONST(0.992385354870852), FRAC_CONST(0.123171861388280)}, + {FRAC_CONST(0.991610905163495), FRAC_CONST(0.129258704777796)}, {FRAC_CONST(0.990799121866020), FRAC_CONST(0.135340681650134)}, {FRAC_CONST(0.989950035541609), FRAC_CONST(0.141417563022303)}, + {FRAC_CONST(0.989063678157882), FRAC_CONST(0.147489120103154)}, {FRAC_CONST(0.988140083085693), FRAC_CONST(0.153555124301993)}, {FRAC_CONST(0.987179285097874), FRAC_CONST(0.159615347237193)}, + {FRAC_CONST(0.986181320367928), FRAC_CONST(0.165669560744784)}, {FRAC_CONST(0.985146226468662), FRAC_CONST(0.171717536887050)}, {FRAC_CONST(0.984074042370776), FRAC_CONST(0.177759047961107)}, + {FRAC_CONST(0.982964808441396), FRAC_CONST(0.183793866507478)}, {FRAC_CONST(0.981818566442553), FRAC_CONST(0.189821765318656)}, {FRAC_CONST(0.980635359529608), FRAC_CONST(0.195842517447658)}, + {FRAC_CONST(0.979415232249635), FRAC_CONST(0.201855896216568)}, {FRAC_CONST(0.978158230539735), FRAC_CONST(0.207861675225075)}, {FRAC_CONST(0.976864401725313), FRAC_CONST(0.213859628358994)}, + {FRAC_CONST(0.975533794518291), FRAC_CONST(0.219849529798779)}, {FRAC_CONST(0.974166459015280), FRAC_CONST(0.225831154028026)}, {FRAC_CONST(0.972762446695689), FRAC_CONST(0.231804275841965)}, + {FRAC_CONST(0.971321810419786), FRAC_CONST(0.237768670355934)}, {FRAC_CONST(0.969844604426715), FRAC_CONST(0.243724113013852)}, {FRAC_CONST(0.968330884332445), FRAC_CONST(0.249670379596669)}, + {FRAC_CONST(0.966780707127683), FRAC_CONST(0.255607246230807)}, {FRAC_CONST(0.965194131175725), FRAC_CONST(0.261534489396596)}, {FRAC_CONST(0.963571216210257), FRAC_CONST(0.267451885936678)}, + {FRAC_CONST(0.961912023333112), FRAC_CONST(0.273359213064419)}, {FRAC_CONST(0.960216615011963), FRAC_CONST(0.279256248372291)}, {FRAC_CONST(0.958485055077976), FRAC_CONST(0.285142769840249)}, + {FRAC_CONST(0.956717408723403), FRAC_CONST(0.291018555844085)}, {FRAC_CONST(0.954913742499131), FRAC_CONST(0.296883385163778)}, {FRAC_CONST(0.953074124312172), FRAC_CONST(0.302737036991819)}, + {FRAC_CONST(0.951198623423113), FRAC_CONST(0.308579290941525)}, {FRAC_CONST(0.949287310443502), FRAC_CONST(0.314409927055337)}, {FRAC_CONST(0.947340257333192), FRAC_CONST(0.320228725813100)}, + {FRAC_CONST(0.945357537397632), FRAC_CONST(0.326035468140330)}, {FRAC_CONST(0.943339225285108), FRAC_CONST(0.331829935416461)}, {FRAC_CONST(0.941285396983929), FRAC_CONST(0.337611909483075)}, + {FRAC_CONST(0.939196129819570), FRAC_CONST(0.343381172652115)}, {FRAC_CONST(0.937071502451759), FRAC_CONST(0.349137507714085)}, {FRAC_CONST(0.934911594871516), FRAC_CONST(0.354880697946223)}, + {FRAC_CONST(0.932716488398140), FRAC_CONST(0.360610527120662)}, {FRAC_CONST(0.930486265676150), FRAC_CONST(0.366326779512574)}, {FRAC_CONST(0.928221010672169), FRAC_CONST(0.372029239908285)}, + {FRAC_CONST(0.925920808671770), FRAC_CONST(0.377717693613386)}, {FRAC_CONST(0.923585746276257), FRAC_CONST(0.383391926460809)}, {FRAC_CONST(0.921215911399409), FRAC_CONST(0.389051724818894)}, + {FRAC_CONST(0.918811393264170), FRAC_CONST(0.394696875599434)}, {FRAC_CONST(0.916372282399289), FRAC_CONST(0.400327166265690)}, {FRAC_CONST(0.913898670635912), FRAC_CONST(0.405942384840403)}, + {FRAC_CONST(0.911390651104122), FRAC_CONST(0.411542319913765)}, {FRAC_CONST(0.908848318229439), FRAC_CONST(0.417126760651388)}, {FRAC_CONST(0.906271767729258), FRAC_CONST(0.422695496802233)}, + {FRAC_CONST(0.903661096609248), FRAC_CONST(0.428248318706532)}, {FRAC_CONST(0.901016403159702), FRAC_CONST(0.433785017303679)}, {FRAC_CONST(0.898337786951834), FRAC_CONST(0.439305384140100)}, + {FRAC_CONST(0.895625348834030), FRAC_CONST(0.444809211377105)}, {FRAC_CONST(0.892879190928052), FRAC_CONST(0.450296291798709)}, {FRAC_CONST(0.890099416625192), FRAC_CONST(0.455766418819435)}, + {FRAC_CONST(0.887286130582383), FRAC_CONST(0.461219386492092)}, {FRAC_CONST(0.884439438718254), FRAC_CONST(0.466654989515531)}, {FRAC_CONST(0.881559448209144), FRAC_CONST(0.472073023242369)}, + {FRAC_CONST(0.878646267485068), FRAC_CONST(0.477473283686698)}, {FRAC_CONST(0.875700006225635), FRAC_CONST(0.482855567531766)}, {FRAC_CONST(0.872720775355914), FRAC_CONST(0.488219672137627)}, + {FRAC_CONST(0.869708687042266), FRAC_CONST(0.493565395548775)}, {FRAC_CONST(0.866663854688111), FRAC_CONST(0.498892536501745)}, {FRAC_CONST(0.863586392929668), FRAC_CONST(0.504200894432690)}, + {FRAC_CONST(0.860476417631632), FRAC_CONST(0.509490269484936)}, {FRAC_CONST(0.857334045882816), FRAC_CONST(0.514760462516501)}, {FRAC_CONST(0.854159395991739), FRAC_CONST(0.520011275107596)}, + {FRAC_CONST(0.850952587482176), FRAC_CONST(0.525242509568095)}, {FRAC_CONST(0.847713741088654), FRAC_CONST(0.530453968944976)}, {FRAC_CONST(0.844442978751911), FRAC_CONST(0.535645457029741)}, + {FRAC_CONST(0.841140423614298), FRAC_CONST(0.540816778365797)}, {FRAC_CONST(0.837806200015151), FRAC_CONST(0.545967738255818)}, {FRAC_CONST(0.834440433486103), FRAC_CONST(0.551098142769075)}, + {FRAC_CONST(0.831043250746362), FRAC_CONST(0.556207798748740)}, {FRAC_CONST(0.827614779697938), FRAC_CONST(0.561296513819151)}, {FRAC_CONST(0.824155149420829), FRAC_CONST(0.566364096393064)}, + {FRAC_CONST(0.820664490168157), FRAC_CONST(0.571410355678857)}, {FRAC_CONST(0.817142933361273), FRAC_CONST(0.576435101687722)}, {FRAC_CONST(0.813590611584799), FRAC_CONST(0.581438145240810)}, + {FRAC_CONST(0.810007658581641), FRAC_CONST(0.586419297976361)}, {FRAC_CONST(0.806394209247956), FRAC_CONST(0.591378372356788)}, {FRAC_CONST(0.802750399628069), FRAC_CONST(0.596315181675744)}, + {FRAC_CONST(0.799076366909352), FRAC_CONST(0.601229540065149)}, {FRAC_CONST(0.795372249417061), FRAC_CONST(0.606121262502186)}, {FRAC_CONST(0.791638186609126), FRAC_CONST(0.610990164816272)}, + {FRAC_CONST(0.787874319070900), FRAC_CONST(0.615836063695985)}, {FRAC_CONST(0.784080788509870), FRAC_CONST(0.620658776695972)}, {FRAC_CONST(0.780257737750317), FRAC_CONST(0.625458122243814)}, + {FRAC_CONST(0.776405310727940), FRAC_CONST(0.630233919646864)}, {FRAC_CONST(0.772523652484441), FRAC_CONST(0.634985989099049)}, {FRAC_CONST(0.768612909162058), FRAC_CONST(0.639714151687640)}, + {FRAC_CONST(0.764673227998067), FRAC_CONST(0.644418229399988)}, {FRAC_CONST(0.760704757319237), FRAC_CONST(0.649098045130226)}, {FRAC_CONST(0.756707646536246), FRAC_CONST(0.653753422685936)}, + {FRAC_CONST(0.752682046138055), FRAC_CONST(0.658384186794785)}, {FRAC_CONST(0.748628107686245), FRAC_CONST(0.662990163111121)}, {FRAC_CONST(0.744545983809307), FRAC_CONST(0.667571178222540)}, + {FRAC_CONST(0.740435828196898), FRAC_CONST(0.672127059656412)}, {FRAC_CONST(0.736297795594053), FRAC_CONST(0.676657635886375)}, {FRAC_CONST(0.732132041795361), FRAC_CONST(0.681162736338795)}, + {FRAC_CONST(0.727938723639099), FRAC_CONST(0.685642191399187)}, {FRAC_CONST(0.723717999001324), FRAC_CONST(0.690095832418600)}, {FRAC_CONST(0.719470026789933), FRAC_CONST(0.694523491719966)}, + {FRAC_CONST(0.715194966938680), FRAC_CONST(0.698925002604414)}, {FRAC_CONST(0.710892980401152), FRAC_CONST(0.703300199357549)}, {FRAC_CONST(0.706564229144710), FRAC_CONST(0.707648917255684)}, + {FRAC_CONST(0.702208876144392), FRAC_CONST(0.711970992572050)}, {FRAC_CONST(0.697827085376777), FRAC_CONST(0.716266262582953)}, {FRAC_CONST(0.693419021813812), FRAC_CONST(0.720534565573905)}, + {FRAC_CONST(0.688984851416597), FRAC_CONST(0.724775740845711)}, {FRAC_CONST(0.684524741129142), FRAC_CONST(0.728989628720519)}, {FRAC_CONST(0.680038858872079), FRAC_CONST(0.733176070547833)}, + {FRAC_CONST(0.675527373536339), FRAC_CONST(0.737334908710483)}, {FRAC_CONST(0.670990454976794), FRAC_CONST(0.741465986630563)}, {FRAC_CONST(0.666428274005865), FRAC_CONST(0.745569148775325)}, + {FRAC_CONST(0.661841002387087), FRAC_CONST(0.749644240663033)}, {FRAC_CONST(0.657228812828643), FRAC_CONST(0.753691108868781)}, {FRAC_CONST(0.652591878976863), FRAC_CONST(0.757709601030268)}, + {FRAC_CONST(0.647930375409685), FRAC_CONST(0.761699565853535)}, {FRAC_CONST(0.643244477630086), FRAC_CONST(0.765660853118662)}, {FRAC_CONST(0.638534362059467), FRAC_CONST(0.769593313685423)}, + {FRAC_CONST(0.633800206031017), FRAC_CONST(0.773496799498899)}, {FRAC_CONST(0.629042187783036), FRAC_CONST(0.777371163595056)}, {FRAC_CONST(0.624260486452221), FRAC_CONST(0.781216260106276)}, + {FRAC_CONST(0.619455282066924), FRAC_CONST(0.785031944266848)}, {FRAC_CONST(0.614626755540375), FRAC_CONST(0.788818072418420)}, {FRAC_CONST(0.609775088663868), FRAC_CONST(0.792574502015408)}, + {FRAC_CONST(0.604900464099920), FRAC_CONST(0.796301091630359)}, {FRAC_CONST(0.600003065375389), FRAC_CONST(0.799997700959282)}, {FRAC_CONST(0.595083076874570), FRAC_CONST(0.803664190826924)}, + {FRAC_CONST(0.590140683832249), FRAC_CONST(0.807300423192014)}, {FRAC_CONST(0.585176072326730), FRAC_CONST(0.810906261152460)}, {FRAC_CONST(0.580189429272832), FRAC_CONST(0.814481568950499)}, + {FRAC_CONST(0.575180942414845), FRAC_CONST(0.818026211977813)}, {FRAC_CONST(0.570150800319470), FRAC_CONST(0.821540056780598)}, {FRAC_CONST(0.565099192368714), FRAC_CONST(0.825022971064580)}, + {FRAC_CONST(0.560026308752760), FRAC_CONST(0.828474823700007)}, {FRAC_CONST(0.554932340462810), FRAC_CONST(0.831895484726578)}, {FRAC_CONST(0.549817479283891), FRAC_CONST(0.835284825358337)}, + {FRAC_CONST(0.544681917787635), FRAC_CONST(0.838642717988527)}, {FRAC_CONST(0.539525849325029), FRAC_CONST(0.841969036194388)}, {FRAC_CONST(0.534349468019138), FRAC_CONST(0.845263654741918)}, + {FRAC_CONST(0.529152968757791), FRAC_CONST(0.848526449590593)}, {FRAC_CONST(0.523936547186249), FRAC_CONST(0.851757297898029)}, {FRAC_CONST(0.518700399699835), FRAC_CONST(0.854956078024615)}, + {FRAC_CONST(0.513444723436544), FRAC_CONST(0.858122669538086)}, {FRAC_CONST(0.508169716269615), FRAC_CONST(0.861256953218062)}, {FRAC_CONST(0.502875576800087), FRAC_CONST(0.864358811060534)}, + {FRAC_CONST(0.497562504349319), FRAC_CONST(0.867428126282307)}, {FRAC_CONST(0.492230698951486), FRAC_CONST(0.870464783325398)}, {FRAC_CONST(0.486880361346047), FRAC_CONST(0.873468667861385)}, + {FRAC_CONST(0.481511692970190), FRAC_CONST(0.876439666795714)}, {FRAC_CONST(0.476124895951244), FRAC_CONST(0.879377668271953)}, {FRAC_CONST(0.470720173099072), FRAC_CONST(0.882282561676009)}, + {FRAC_CONST(0.465297727898435), FRAC_CONST(0.885154237640285)}, {FRAC_CONST(0.459857764501330), FRAC_CONST(0.887992588047806)}, {FRAC_CONST(0.454400487719304), FRAC_CONST(0.890797506036281)}, + {FRAC_CONST(0.448926103015743), FRAC_CONST(0.893568886002136)}, {FRAC_CONST(0.443434816498138), FRAC_CONST(0.896306623604480)}, {FRAC_CONST(0.437926834910323), FRAC_CONST(0.899010615769039)}, + {FRAC_CONST(0.432402365624690), FRAC_CONST(0.901680760692038)}, {FRAC_CONST(0.426861616634386), FRAC_CONST(0.904316957844028)}, {FRAC_CONST(0.421304796545480), FRAC_CONST(0.906919107973678)}, + {FRAC_CONST(0.415732114569105), FRAC_CONST(0.909487113111505)}, {FRAC_CONST(0.410143780513590), FRAC_CONST(0.912020876573568)}, {FRAC_CONST(0.404540004776553), FRAC_CONST(0.914520302965104)}, + {FRAC_CONST(0.398920998336983), FRAC_CONST(0.916985298184123)}, {FRAC_CONST(0.393286972747297), FRAC_CONST(0.919415769424947)}, {FRAC_CONST(0.387638140125373), FRAC_CONST(0.921811625181708)}, + {FRAC_CONST(0.381974713146567), FRAC_CONST(0.924172775251791)}, {FRAC_CONST(0.376296905035705), FRAC_CONST(0.926499130739231)}, {FRAC_CONST(0.370604929559052), FRAC_CONST(0.928790604058057)}, + {FRAC_CONST(0.364899001016267), FRAC_CONST(0.931047108935595)}, {FRAC_CONST(0.359179334232337), FRAC_CONST(0.933268560415712)}, {FRAC_CONST(0.353446144549481), FRAC_CONST(0.935454874862015)}, + {FRAC_CONST(0.347699647819051), FRAC_CONST(0.937605969961000)}, {FRAC_CONST(0.341940060393402), FRAC_CONST(0.939721764725153)}, {FRAC_CONST(0.336167599117745), FRAC_CONST(0.941802179495998)}, + {FRAC_CONST(0.330382481321983), FRAC_CONST(0.943847135947093)}, {FRAC_CONST(0.324584924812532), FRAC_CONST(0.945856557086984)}, {FRAC_CONST(0.318775147864118), FRAC_CONST(0.947830367262101)}, + {FRAC_CONST(0.312953369211560), FRAC_CONST(0.949768492159607)}, {FRAC_CONST(0.307119808041533), FRAC_CONST(0.951670858810194)}, {FRAC_CONST(0.301274683984318), FRAC_CONST(0.953537395590833)}, + {FRAC_CONST(0.295418217105532), FRAC_CONST(0.955368032227470)}, {FRAC_CONST(0.289550627897843), FRAC_CONST(0.957162699797670)}, {FRAC_CONST(0.283672137272669), FRAC_CONST(0.958921330733213)}, + {FRAC_CONST(0.277782966551858), FRAC_CONST(0.960643858822638)}, {FRAC_CONST(0.271883337459360), FRAC_CONST(0.962330219213737)}, {FRAC_CONST(0.265973472112876), FRAC_CONST(0.963980348415994)}, + {FRAC_CONST(0.260053593015495), FRAC_CONST(0.965594184302977)}, {FRAC_CONST(0.254123923047321), FRAC_CONST(0.967171666114677)}, {FRAC_CONST(0.248184685457075), FRAC_CONST(0.968712734459795)}, + {FRAC_CONST(0.242236103853696), FRAC_CONST(0.970217331317979)}, {FRAC_CONST(0.236278402197920), FRAC_CONST(0.971685400042009)}, {FRAC_CONST(0.230311804793846), FRAC_CONST(0.973116885359925)}, + {FRAC_CONST(0.224336536280494), FRAC_CONST(0.974511733377116)}, {FRAC_CONST(0.218352821623346), FRAC_CONST(0.975869891578341)}, {FRAC_CONST(0.212360886105879), FRAC_CONST(0.977191308829712)}, + {FRAC_CONST(0.206360955321076), FRAC_CONST(0.978475935380617)}, {FRAC_CONST(0.200353255162940), FRAC_CONST(0.979723722865591)}, {FRAC_CONST(0.194338011817989), FRAC_CONST(0.980934624306142)}, + {FRAC_CONST(0.188315451756732), FRAC_CONST(0.982108594112514)}, {FRAC_CONST(0.182285801725153), FRAC_CONST(0.983245588085407)}, {FRAC_CONST(0.176249288736168), FRAC_CONST(0.984345563417642)}, + {FRAC_CONST(0.170206140061078), FRAC_CONST(0.985408478695768)}, {FRAC_CONST(0.164156583221016), FRAC_CONST(0.986434293901627)}, {FRAC_CONST(0.158100845978377), FRAC_CONST(0.987422970413855)}, + {FRAC_CONST(0.152039156328246), FRAC_CONST(0.988374471009341)}, {FRAC_CONST(0.145971742489812), FRAC_CONST(0.989288759864625)}, {FRAC_CONST(0.139898832897777), FRAC_CONST(0.990165802557248)}, + {FRAC_CONST(0.133820656193755), FRAC_CONST(0.991005566067049)}, {FRAC_CONST(0.127737441217662), FRAC_CONST(0.991808018777406)}, {FRAC_CONST(0.121649416999106), FRAC_CONST(0.992573130476429)}, + {FRAC_CONST(0.115556812748755), FRAC_CONST(0.993300872358093)}, {FRAC_CONST(0.109459857849718), FRAC_CONST(0.993991217023329)}, {FRAC_CONST(0.103358781848900), FRAC_CONST(0.994644138481051)}, + {FRAC_CONST(0.097253814448363), FRAC_CONST(0.995259612149133)}, {FRAC_CONST(0.091145185496681), FRAC_CONST(0.995837614855342)}, {FRAC_CONST(0.085033124980280), FRAC_CONST(0.996378124838200)}, + {FRAC_CONST(0.078917863014785), FRAC_CONST(0.996881121747814)}, {FRAC_CONST(0.072799629836352), FRAC_CONST(0.997346586646633)}, {FRAC_CONST(0.066678655793002), FRAC_CONST(0.997774502010168)}, + {FRAC_CONST(0.060555171335948), FRAC_CONST(0.998164851727646)}, {FRAC_CONST(0.054429407010919), FRAC_CONST(0.998517621102622)}, {FRAC_CONST(0.048301593449480), FRAC_CONST(0.998832796853528)}, + {FRAC_CONST(0.042171961360348), FRAC_CONST(0.999110367114175)}, {FRAC_CONST(0.036040741520706), FRAC_CONST(0.999350321434199)}, {FRAC_CONST(0.029908164767517), FRAC_CONST(0.999552650779457)}, + {FRAC_CONST(0.023774461988828), FRAC_CONST(0.999717347532362)}, {FRAC_CONST(0.017639864115082), FRAC_CONST(0.999844405492175)}, {FRAC_CONST(0.011504602110423), FRAC_CONST(0.999933819875236)}, + {FRAC_CONST(0.005368906963996), FRAC_CONST(0.999985587315143)}}; + #endif // LD_DEC + #ifdef ALLOW_SMALL_FRAMELENGTH +/* 480 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_1920[] = { + {FRAC_CONST(0.999999916334328), FRAC_CONST(0.000409061532028)}, {FRAC_CONST(0.999993223088129), FRAC_CONST(0.003681545574400)}, {FRAC_CONST(0.999975820717897), FRAC_CONST(0.006953990190376)}, + {FRAC_CONST(0.999947709409999), FRAC_CONST(0.010226360334704)}, {FRAC_CONST(0.999908889465485), FRAC_CONST(0.013498620962929)}, {FRAC_CONST(0.999859361300084), FRAC_CONST(0.016770737031768)}, + {FRAC_CONST(0.999799125444203), FRAC_CONST(0.020042673499487)}, {FRAC_CONST(0.999728182542920), FRAC_CONST(0.023314395326274)}, {FRAC_CONST(0.999646533355977), FRAC_CONST(0.026585867474619)}, + {FRAC_CONST(0.999554178757770), FRAC_CONST(0.029857054909681)}, {FRAC_CONST(0.999451119737344), FRAC_CONST(0.033127922599673)}, {FRAC_CONST(0.999337357398377), FRAC_CONST(0.036398435516228)}, + {FRAC_CONST(0.999212892959173), FRAC_CONST(0.039668558634781)}, {FRAC_CONST(0.999077727752645), FRAC_CONST(0.042938256934941)}, {FRAC_CONST(0.998931863226306), FRAC_CONST(0.046207495400865)}, + {FRAC_CONST(0.998775300942246), FRAC_CONST(0.049476239021636)}, {FRAC_CONST(0.998608042577122), FRAC_CONST(0.052744452791636)}, {FRAC_CONST(0.998430089922136), FRAC_CONST(0.056012101710921)}, + {FRAC_CONST(0.998241444883019), FRAC_CONST(0.059279150785597)}, {FRAC_CONST(0.998042109480008), FRAC_CONST(0.062545565028192)}, {FRAC_CONST(0.997832085847824), FRAC_CONST(0.065811309458034)}, + {FRAC_CONST(0.997611376235651), FRAC_CONST(0.069076349101624)}, {FRAC_CONST(0.997379983007114), FRAC_CONST(0.072340648993011)}, {FRAC_CONST(0.997137908640245), FRAC_CONST(0.075604174174166)}, + {FRAC_CONST(0.996885155727469), FRAC_CONST(0.078866889695354)}, {FRAC_CONST(0.996621726975566), FRAC_CONST(0.082128760615515)}, {FRAC_CONST(0.996347625205645), FRAC_CONST(0.085389752002632)}, + {FRAC_CONST(0.996062853353117), FRAC_CONST(0.088649828934106)}, {FRAC_CONST(0.995767414467660), FRAC_CONST(0.091908956497133)}, {FRAC_CONST(0.995461311713186), FRAC_CONST(0.095167099789075)}, + {FRAC_CONST(0.995144548367810), FRAC_CONST(0.098424223917834)}, {FRAC_CONST(0.994817127823813), FRAC_CONST(0.101680294002229)}, {FRAC_CONST(0.994479053587606), FRAC_CONST(0.104935275172364)}, + {FRAC_CONST(0.994130329279692), FRAC_CONST(0.108189132570007)}, {FRAC_CONST(0.993770958634630), FRAC_CONST(0.111441831348957)}, {FRAC_CONST(0.993400945500988), FRAC_CONST(0.114693336675426)}, + {FRAC_CONST(0.993020293841312), FRAC_CONST(0.117943613728403)}, {FRAC_CONST(0.992629007732074), FRAC_CONST(0.121192627700032)}, {FRAC_CONST(0.992227091363634), FRAC_CONST(0.124440343795983)}, + {FRAC_CONST(0.991814549040194), FRAC_CONST(0.127686727235827)}, {FRAC_CONST(0.991391385179751), FRAC_CONST(0.130931743253405)}, {FRAC_CONST(0.990957604314048), FRAC_CONST(0.134175357097202)}, + {FRAC_CONST(0.990513211088533), FRAC_CONST(0.137417534030720)}, {FRAC_CONST(0.990058210262297), FRAC_CONST(0.140658239332849)}, {FRAC_CONST(0.989592606708036), FRAC_CONST(0.143897438298239)}, + {FRAC_CONST(0.989116405411988), FRAC_CONST(0.147135096237670)}, {FRAC_CONST(0.988629611473887), FRAC_CONST(0.150371178478428)}, {FRAC_CONST(0.988132230106905), FRAC_CONST(0.153605650364672)}, + {FRAC_CONST(0.987624266637598), FRAC_CONST(0.156838477257806)}, {FRAC_CONST(0.987105726505845), FRAC_CONST(0.160069624536852)}, {FRAC_CONST(0.986576615264794), FRAC_CONST(0.163299057598817)}, + {FRAC_CONST(0.986036938580803), FRAC_CONST(0.166526741859069)}, {FRAC_CONST(0.985486702233375), FRAC_CONST(0.169752642751702)}, {FRAC_CONST(0.984925912115099), FRAC_CONST(0.172976725729910)}, + {FRAC_CONST(0.984354574231587), FRAC_CONST(0.176198956266353)}, {FRAC_CONST(0.983772694701407), FRAC_CONST(0.179419299853531)}, {FRAC_CONST(0.983180279756024), FRAC_CONST(0.182637722004152)}, + {FRAC_CONST(0.982577335739725), FRAC_CONST(0.185854188251500)}, {FRAC_CONST(0.981963869109555), FRAC_CONST(0.189068664149806)}, {FRAC_CONST(0.981339886435250), FRAC_CONST(0.192281115274616)}, + {FRAC_CONST(0.980705394399163), FRAC_CONST(0.195491507223158)}, {FRAC_CONST(0.980060399796194), FRAC_CONST(0.198699805614714)}, {FRAC_CONST(0.979404909533716), FRAC_CONST(0.201905976090986)}, + {FRAC_CONST(0.978738930631504), FRAC_CONST(0.205109984316464)}, {FRAC_CONST(0.978062470221657), FRAC_CONST(0.208311795978794)}, {FRAC_CONST(0.977375535548522), FRAC_CONST(0.211511376789145)}, + {FRAC_CONST(0.976678133968618), FRAC_CONST(0.214708692482577)}, {FRAC_CONST(0.975970272950556), FRAC_CONST(0.217903708818409)}, {FRAC_CONST(0.975251960074958), FRAC_CONST(0.221096391580581)}, + {FRAC_CONST(0.974523203034377), FRAC_CONST(0.224286706578026)}, {FRAC_CONST(0.973784009633218), FRAC_CONST(0.227474619645035)}, {FRAC_CONST(0.973034387787646), FRAC_CONST(0.230660096641619)}, + {FRAC_CONST(0.972274345525510), FRAC_CONST(0.233843103453878)}, {FRAC_CONST(0.971503890986252), FRAC_CONST(0.237023605994367)}, {FRAC_CONST(0.970723032420820), FRAC_CONST(0.240201570202459)}, + {FRAC_CONST(0.969931778191584), FRAC_CONST(0.243376962044711)}, {FRAC_CONST(0.969130136772239), FRAC_CONST(0.246549747515226)}, {FRAC_CONST(0.968318116747721), FRAC_CONST(0.249719892636022)}, + {FRAC_CONST(0.967495726814114), FRAC_CONST(0.252887363457390)}, {FRAC_CONST(0.966662975778551), FRAC_CONST(0.256052126058264)}, {FRAC_CONST(0.965819872559127), FRAC_CONST(0.259214146546579)}, + {FRAC_CONST(0.964966426184802), FRAC_CONST(0.262373391059634)}, {FRAC_CONST(0.964102645795299), FRAC_CONST(0.265529825764461)}, {FRAC_CONST(0.963228540641012), FRAC_CONST(0.268683416858178)}, + {FRAC_CONST(0.962344120082907), FRAC_CONST(0.271834130568359)}, {FRAC_CONST(0.961449393592416), FRAC_CONST(0.274981933153391)}, {FRAC_CONST(0.960544370751341), FRAC_CONST(0.278126790902837)}, + {FRAC_CONST(0.959629061251750), FRAC_CONST(0.281268670137799)}, {FRAC_CONST(0.958703474895872), FRAC_CONST(0.284407537211272)}, {FRAC_CONST(0.957767621595993), FRAC_CONST(0.287543358508512)}, + {FRAC_CONST(0.956821511374351), FRAC_CONST(0.290676100447394)}, {FRAC_CONST(0.955865154363025), FRAC_CONST(0.293805729478766)}, {FRAC_CONST(0.954898560803832), FRAC_CONST(0.296932212086818)}, + {FRAC_CONST(0.953921741048211), FRAC_CONST(0.300055514789431)}, {FRAC_CONST(0.952934705557117), FRAC_CONST(0.303175604138543)}, {FRAC_CONST(0.951937464900908), FRAC_CONST(0.306292446720504)}, + {FRAC_CONST(0.950930029759229), FRAC_CONST(0.309406009156434)}, {FRAC_CONST(0.949912410920903), FRAC_CONST(0.312516258102580)}, {FRAC_CONST(0.948884619283808), FRAC_CONST(0.315623160250676)}, + {FRAC_CONST(0.947846665854767), FRAC_CONST(0.318726682328294)}, {FRAC_CONST(0.946798561749429), FRAC_CONST(0.321826791099207)}, {FRAC_CONST(0.945740318192145), FRAC_CONST(0.324923453363742)}, + {FRAC_CONST(0.944671946515855), FRAC_CONST(0.328016635959131)}, {FRAC_CONST(0.943593458161960), FRAC_CONST(0.331106305759876)}, {FRAC_CONST(0.942504864680205), FRAC_CONST(0.334192429678095)}, + {FRAC_CONST(0.941406177728551), FRAC_CONST(0.337274974663880)}, {FRAC_CONST(0.940297409073052), FRAC_CONST(0.340353907705650)}, {FRAC_CONST(0.939178570587730), FRAC_CONST(0.343429195830507)}, + {FRAC_CONST(0.938049674254446), FRAC_CONST(0.346500806104585)}, {FRAC_CONST(0.936910732162774), FRAC_CONST(0.349568705633406)}, {FRAC_CONST(0.935761756509868), FRAC_CONST(0.352632861562230)}, + {FRAC_CONST(0.934602759600334), FRAC_CONST(0.355693241076410)}, {FRAC_CONST(0.933433753846097), FRAC_CONST(0.358749811401739)}, {FRAC_CONST(0.932254751766271), FRAC_CONST(0.361802539804806)}, + {FRAC_CONST(0.931065765987021), FRAC_CONST(0.364851393593340)}, {FRAC_CONST(0.929866809241428), FRAC_CONST(0.367896340116568)}, {FRAC_CONST(0.928657894369357), FRAC_CONST(0.370937346765559)}, + {FRAC_CONST(0.927439034317314), FRAC_CONST(0.373974380973575)}, {FRAC_CONST(0.926210242138311), FRAC_CONST(0.377007410216418)}, {FRAC_CONST(0.924971530991726), FRAC_CONST(0.380036402012783)}, + {FRAC_CONST(0.923722914143160), FRAC_CONST(0.383061323924602)}, {FRAC_CONST(0.922464404964295), FRAC_CONST(0.386082143557389)}, {FRAC_CONST(0.921196016932755), FRAC_CONST(0.389098828560595)}, + {FRAC_CONST(0.919917763631956), FRAC_CONST(0.392111346627946)}, {FRAC_CONST(0.918629658750963), FRAC_CONST(0.395119665497795)}, {FRAC_CONST(0.917331716084346), FRAC_CONST(0.398123752953462)}, + {FRAC_CONST(0.916023949532027), FRAC_CONST(0.401123576823585)}, {FRAC_CONST(0.914706373099136), FRAC_CONST(0.404119104982459)}, {FRAC_CONST(0.913379000895858), FRAC_CONST(0.407110305350386)}, + {FRAC_CONST(0.912041847137282), FRAC_CONST(0.410097145894012)}, {FRAC_CONST(0.910694926143251), FRAC_CONST(0.413079594626675)}, {FRAC_CONST(0.909338252338207), FRAC_CONST(0.416057619608744)}, + {FRAC_CONST(0.907971840251037), FRAC_CONST(0.419031188947965)}, {FRAC_CONST(0.906595704514915), FRAC_CONST(0.422000270799800)}, {FRAC_CONST(0.905209859867151), FRAC_CONST(0.424964833367766)}, + {FRAC_CONST(0.903814321149027), FRAC_CONST(0.427924844903780)}, {FRAC_CONST(0.902409103305641), FRAC_CONST(0.430880273708497)}, {FRAC_CONST(0.900994221385748), FRAC_CONST(0.433831088131649)}, + {FRAC_CONST(0.899569690541596), FRAC_CONST(0.436777256572384)}, {FRAC_CONST(0.898135526028766), FRAC_CONST(0.439718747479604)}, {FRAC_CONST(0.896691743206008), FRAC_CONST(0.442655529352306)}, + {FRAC_CONST(0.895238357535076), FRAC_CONST(0.445587570739915)}, {FRAC_CONST(0.893775384580563), FRAC_CONST(0.448514840242624)}, {FRAC_CONST(0.892302840009734), FRAC_CONST(0.451437306511726)}, + {FRAC_CONST(0.890820739592359), FRAC_CONST(0.454354938249958)}, {FRAC_CONST(0.889329099200541), FRAC_CONST(0.457267704211826)}, {FRAC_CONST(0.887827934808551), FRAC_CONST(0.460175573203949)}, + {FRAC_CONST(0.886317262492655), FRAC_CONST(0.463078514085383)}, {FRAC_CONST(0.884797098430938), FRAC_CONST(0.465976495767966)}, {FRAC_CONST(0.883267458903136), FRAC_CONST(0.468869487216642)}, + {FRAC_CONST(0.881728360290461), FRAC_CONST(0.471757457449795)}, {FRAC_CONST(0.880179819075421), FRAC_CONST(0.474640375539586)}, {FRAC_CONST(0.878621851841649), FRAC_CONST(0.477518210612278)}, + {FRAC_CONST(0.877054475273722), FRAC_CONST(0.480390931848569)}, {FRAC_CONST(0.875477706156984), FRAC_CONST(0.483258508483922)}, {FRAC_CONST(0.873891561377366), FRAC_CONST(0.486120909808896)}, + {FRAC_CONST(0.872296057921204), FRAC_CONST(0.488978105169472)}, {FRAC_CONST(0.870691212875058), FRAC_CONST(0.491830063967383)}, {FRAC_CONST(0.869077043425529), FRAC_CONST(0.494676755660442)}, + {FRAC_CONST(0.867453566859076), FRAC_CONST(0.497518149762867)}, {FRAC_CONST(0.865820800561827), FRAC_CONST(0.500354215845611)}, {FRAC_CONST(0.864178762019399), FRAC_CONST(0.503184923536685)}, + {FRAC_CONST(0.862527468816704), FRAC_CONST(0.506010242521482)}, {FRAC_CONST(0.860866938637767), FRAC_CONST(0.508830142543107)}, {FRAC_CONST(0.859197189265532), FRAC_CONST(0.511644593402696)}, + {FRAC_CONST(0.857518238581672), FRAC_CONST(0.514453564959741)}, {FRAC_CONST(0.855830104566401), FRAC_CONST(0.517257027132414)}, {FRAC_CONST(0.854132805298278), FRAC_CONST(0.520054949897887)}, + {FRAC_CONST(0.852426358954015), FRAC_CONST(0.522847303292655)}, {FRAC_CONST(0.850710783808280), FRAC_CONST(0.525634057412856)}, {FRAC_CONST(0.848986098233506), FRAC_CONST(0.528415182414593)}, + {FRAC_CONST(0.847252320699689), FRAC_CONST(0.531190648514252)}, {FRAC_CONST(0.845509469774194), FRAC_CONST(0.533960425988819)}, {FRAC_CONST(0.843757564121554), FRAC_CONST(0.536724485176205)}, + {FRAC_CONST(0.841996622503271), FRAC_CONST(0.539482796475555)}, {FRAC_CONST(0.840226663777615), FRAC_CONST(0.542235330347571)}, {FRAC_CONST(0.838447706899422), FRAC_CONST(0.544982057314827)}, + {FRAC_CONST(0.836659770919891), FRAC_CONST(0.547722947962084)}, {FRAC_CONST(0.834862874986380), FRAC_CONST(0.550457972936605)}, {FRAC_CONST(0.833057038342201), FRAC_CONST(0.553187102948470)}, + {FRAC_CONST(0.831242280326413), FRAC_CONST(0.555910308770889)}, {FRAC_CONST(0.829418620373617), FRAC_CONST(0.558627561240515)}, {FRAC_CONST(0.827586078013746), FRAC_CONST(0.561338831257758)}, + {FRAC_CONST(0.825744672871856), FRAC_CONST(0.564044089787093)}, {FRAC_CONST(0.823894424667918), FRAC_CONST(0.566743307857377)}, {FRAC_CONST(0.822035353216601), FRAC_CONST(0.569436456562150)}, + {FRAC_CONST(0.820167478427070), FRAC_CONST(0.572123507059955)}, {FRAC_CONST(0.818290820302761), FRAC_CONST(0.574804430574639)}, {FRAC_CONST(0.816405398941175), FRAC_CONST(0.577479198395666)}, + {FRAC_CONST(0.814511234533661), FRAC_CONST(0.580147781878420)}, {FRAC_CONST(0.812608347365198), FRAC_CONST(0.582810152444517)}, {FRAC_CONST(0.810696757814178), FRAC_CONST(0.585466281582107)}, + {FRAC_CONST(0.808776486352191), FRAC_CONST(0.588116140846181)}, {FRAC_CONST(0.806847553543799), FRAC_CONST(0.590759701858874)}, {FRAC_CONST(0.804909980046325), FRAC_CONST(0.593396936309773)}, + {FRAC_CONST(0.802963786609623), FRAC_CONST(0.596027815956215)}, {FRAC_CONST(0.801008994075862), FRAC_CONST(0.598652312623592)}, {FRAC_CONST(0.799045623379300), FRAC_CONST(0.601270398205654)}, + {FRAC_CONST(0.797073695546059), FRAC_CONST(0.603882044664808)}, {FRAC_CONST(0.795093231693901), FRAC_CONST(0.606487224032418)}, {FRAC_CONST(0.793104253032005), FRAC_CONST(0.609085908409106)}, + {FRAC_CONST(0.791106780860733), FRAC_CONST(0.611678069965050)}, {FRAC_CONST(0.789100836571407), FRAC_CONST(0.614263680940283)}, {FRAC_CONST(0.787086441646080), FRAC_CONST(0.616842713644988)}, + {FRAC_CONST(0.785063617657302), FRAC_CONST(0.619415140459796)}, {FRAC_CONST(0.783032386267894), FRAC_CONST(0.621980933836084)}, {FRAC_CONST(0.780992769230711), FRAC_CONST(0.624540066296266)}, + {FRAC_CONST(0.778944788388414), FRAC_CONST(0.627092510434089)}, {FRAC_CONST(0.776888465673232), FRAC_CONST(0.629638238914927)}, {FRAC_CONST(0.774823823106730), FRAC_CONST(0.632177224476073)}, + {FRAC_CONST(0.772750882799570), FRAC_CONST(0.634709439927031)}, {FRAC_CONST(0.770669666951277), FRAC_CONST(0.637234858149809)}, {FRAC_CONST(0.768580197850002), FRAC_CONST(0.639753452099206)}, + {FRAC_CONST(0.766482497872280), FRAC_CONST(0.642265194803105)}, {FRAC_CONST(0.764376589482793), FRAC_CONST(0.644770059362758)}, {FRAC_CONST(0.762262495234126), FRAC_CONST(0.647268018953079)}, + {FRAC_CONST(0.760140237766532), FRAC_CONST(0.649759046822928)}, {FRAC_CONST(0.758009839807683), FRAC_CONST(0.652243116295397)}, {FRAC_CONST(0.755871324172429), FRAC_CONST(0.654720200768098)}, + {FRAC_CONST(0.753724713762555), FRAC_CONST(0.657190273713446)}, {FRAC_CONST(0.751570031566534), FRAC_CONST(0.659653308678945)}, {FRAC_CONST(0.749407300659280), FRAC_CONST(0.662109279287469)}, + {FRAC_CONST(0.747236544201905), FRAC_CONST(0.664558159237545)}, {FRAC_CONST(0.745057785441466), FRAC_CONST(0.666999922303638)}, {FRAC_CONST(0.742871047710719), FRAC_CONST(0.669434542336425)}, + {FRAC_CONST(0.740676354427868), FRAC_CONST(0.671861993263083)}, {FRAC_CONST(0.738473729096316), FRAC_CONST(0.674282249087562)}, {FRAC_CONST(0.736263195304409), FRAC_CONST(0.676695283890867)}, + {FRAC_CONST(0.734044776725190), FRAC_CONST(0.679101071831334)}, {FRAC_CONST(0.731818497116138), FRAC_CONST(0.681499587144906)}, {FRAC_CONST(0.729584380318920), FRAC_CONST(0.683890804145412)}, + {FRAC_CONST(0.727342450259131), FRAC_CONST(0.686274697224838)}, {FRAC_CONST(0.725092730946042), FRAC_CONST(0.688651240853606)}, {FRAC_CONST(0.722835246472338), FRAC_CONST(0.691020409580841)}, + {FRAC_CONST(0.720570021013866), FRAC_CONST(0.693382178034651)}, {FRAC_CONST(0.718297078829369), FRAC_CONST(0.695736520922392)}, {FRAC_CONST(0.716016444260233), FRAC_CONST(0.698083413030944)}, + {FRAC_CONST(0.713728141730222), FRAC_CONST(0.700422829226978)}, {FRAC_CONST(0.711432195745216), FRAC_CONST(0.702754744457225)}, {FRAC_CONST(0.709128630892954), FRAC_CONST(0.705079133748748)}, + {FRAC_CONST(0.706817471842764), FRAC_CONST(0.707395972209203)}, {FRAC_CONST(0.704498743345302), FRAC_CONST(0.709705235027113)}, {FRAC_CONST(0.702172470232289), FRAC_CONST(0.712006897472128)}, + {FRAC_CONST(0.699838677416240), FRAC_CONST(0.714300934895292)}, {FRAC_CONST(0.697497389890200), FRAC_CONST(0.716587322729308)}, {FRAC_CONST(0.695148632727480), FRAC_CONST(0.718866036488799)}, + {FRAC_CONST(0.692792431081381), FRAC_CONST(0.721137051770570)}, {FRAC_CONST(0.690428810184929), FRAC_CONST(0.723400344253874)}, {FRAC_CONST(0.688057795350606), FRAC_CONST(0.725655889700665)}, + {FRAC_CONST(0.685679411970075), FRAC_CONST(0.727903663955865)}, {FRAC_CONST(0.683293685513912), FRAC_CONST(0.730143642947616)}, {FRAC_CONST(0.680900641531330), FRAC_CONST(0.732375802687543)}, + {FRAC_CONST(0.678500305649909), FRAC_CONST(0.734600119271009)}, {FRAC_CONST(0.676092703575316), FRAC_CONST(0.736816568877370)}, {FRAC_CONST(0.673677861091036), FRAC_CONST(0.739025127770231)}, + {FRAC_CONST(0.671255804058092), FRAC_CONST(0.741225772297702)}, {FRAC_CONST(0.668826558414768), FRAC_CONST(0.743418478892647)}, {FRAC_CONST(0.666390150176334), FRAC_CONST(0.745603224072940)}, + {FRAC_CONST(0.663946605434765), FRAC_CONST(0.747779984441716)}, {FRAC_CONST(0.661495950358462), FRAC_CONST(0.749948736687619)}, {FRAC_CONST(0.659038211191971), FRAC_CONST(0.752109457585056)}, + {FRAC_CONST(0.656573414255705), FRAC_CONST(0.754262123994441)}, {FRAC_CONST(0.654101585945659), FRAC_CONST(0.756406712862448)}, {FRAC_CONST(0.651622752733128), FRAC_CONST(0.758543201222251)}, + {FRAC_CONST(0.649136941164425), FRAC_CONST(0.760671566193777)}, {FRAC_CONST(0.646644177860593), FRAC_CONST(0.762791784983948)}, {FRAC_CONST(0.644144489517126), FRAC_CONST(0.764903834886923)}, + {FRAC_CONST(0.641637902903677), FRAC_CONST(0.767007693284345)}, {FRAC_CONST(0.639124444863776), FRAC_CONST(0.769103337645580)}, {FRAC_CONST(0.636604142314538), FRAC_CONST(0.771190745527961)}, + {FRAC_CONST(0.634077022246379), FRAC_CONST(0.773269894577026)}, {FRAC_CONST(0.631543111722725), FRAC_CONST(0.775340762526760)}, {FRAC_CONST(0.629002437879721), FRAC_CONST(0.777403327199831)}, + {FRAC_CONST(0.626455027925944), FRAC_CONST(0.779457566507828)}, {FRAC_CONST(0.623900909142107), FRAC_CONST(0.781503458451498)}, {FRAC_CONST(0.621340108880771), FRAC_CONST(0.783540981120982)}, + {FRAC_CONST(0.618772654566049), FRAC_CONST(0.785570112696050)}, {FRAC_CONST(0.616198573693314), FRAC_CONST(0.787590831446332)}, {FRAC_CONST(0.613617893828905), FRAC_CONST(0.789603115731555)}, + {FRAC_CONST(0.611030642609828), FRAC_CONST(0.791606944001769)}, {FRAC_CONST(0.608436847743468), FRAC_CONST(0.793602294797585)}, {FRAC_CONST(0.605836537007281), FRAC_CONST(0.795589146750397)}, + {FRAC_CONST(0.603229738248508), FRAC_CONST(0.797567478582619)}, {FRAC_CONST(0.600616479383869), FRAC_CONST(0.799537269107905)}, {FRAC_CONST(0.597996788399267), FRAC_CONST(0.801498497231381)}, + {FRAC_CONST(0.595370693349487), FRAC_CONST(0.803451141949871)}, {FRAC_CONST(0.592738222357898), FRAC_CONST(0.805395182352117)}, {FRAC_CONST(0.590099403616149), FRAC_CONST(0.807330597619008)}, + {FRAC_CONST(0.587454265383869), FRAC_CONST(0.809257367023803)}, {FRAC_CONST(0.584802835988364), FRAC_CONST(0.811175469932349)}, {FRAC_CONST(0.582145143824311), FRAC_CONST(0.813084885803304)}, + {FRAC_CONST(0.579481217353460), FRAC_CONST(0.814985594188359)}, {FRAC_CONST(0.576811085104321), FRAC_CONST(0.816877574732454)}, {FRAC_CONST(0.574134775671867), FRAC_CONST(0.818760807173997)}, + {FRAC_CONST(0.571452317717222), FRAC_CONST(0.820635271345081)}, {FRAC_CONST(0.568763739967354), FRAC_CONST(0.822500947171703)}, {FRAC_CONST(0.566069071214772), FRAC_CONST(0.824357814673971)}, + {FRAC_CONST(0.563368340317214), FRAC_CONST(0.826205853966327)}, {FRAC_CONST(0.560661576197336), FRAC_CONST(0.828045045257756)}, {FRAC_CONST(0.557948807842409), FRAC_CONST(0.829875368851995)}, + {FRAC_CONST(0.555230064304002), FRAC_CONST(0.831696805147750)}, {FRAC_CONST(0.552505374697674), FRAC_CONST(0.833509334638900)}, {FRAC_CONST(0.549774768202663), FRAC_CONST(0.835312937914713)}, + {FRAC_CONST(0.547038274061568), FRAC_CONST(0.837107595660044)}, {FRAC_CONST(0.544295921580046), FRAC_CONST(0.838893288655553)}, {FRAC_CONST(0.541547740126486), FRAC_CONST(0.840669997777901)}, + {FRAC_CONST(0.538793759131706), FRAC_CONST(0.842437703999961)}, {FRAC_CONST(0.536034008088628), FRAC_CONST(0.844196388391019)}, {FRAC_CONST(0.533268516551970), FRAC_CONST(0.845946032116980)}, + {FRAC_CONST(0.530497314137923), FRAC_CONST(0.847686616440563)}, {FRAC_CONST(0.527720430523840), FRAC_CONST(0.849418122721510)}, {FRAC_CONST(0.524937895447912), FRAC_CONST(0.851140532416778)}, + {FRAC_CONST(0.522149738708856), FRAC_CONST(0.852853827080745)}, {FRAC_CONST(0.519355990165590), FRAC_CONST(0.854557988365401)}, {FRAC_CONST(0.516556679736915), FRAC_CONST(0.856252998020546)}, + {FRAC_CONST(0.513751837401199), FRAC_CONST(0.857938837893991)}, {FRAC_CONST(0.510941493196049), FRAC_CONST(0.859615489931744)}, {FRAC_CONST(0.508125677217994), FRAC_CONST(0.861282936178208)}, + {FRAC_CONST(0.505304419622159), FRAC_CONST(0.862941158776375)}, {FRAC_CONST(0.502477750621949), FRAC_CONST(0.864590139968012)}, {FRAC_CONST(0.499645700488717), FRAC_CONST(0.866229862093855)}, + {FRAC_CONST(0.496808299551444), FRAC_CONST(0.867860307593799)}, {FRAC_CONST(0.493965578196415), FRAC_CONST(0.869481459007080)}, {FRAC_CONST(0.491117566866892), FRAC_CONST(0.871093298972471)}, + {FRAC_CONST(0.488264296062789), FRAC_CONST(0.872695810228461)}, {FRAC_CONST(0.485405796340343), FRAC_CONST(0.874288975613440)}, {FRAC_CONST(0.482542098311789), FRAC_CONST(0.875872778065888)}, + {FRAC_CONST(0.479673232645033), FRAC_CONST(0.877447200624553)}, {FRAC_CONST(0.476799230063322), FRAC_CONST(0.879012226428633)}, {FRAC_CONST(0.473920121344914), FRAC_CONST(0.880567838717962)}, + {FRAC_CONST(0.471035937322751), FRAC_CONST(0.882114020833179)}, {FRAC_CONST(0.468146708884125), FRAC_CONST(0.883650756215917)}, {FRAC_CONST(0.465252466970353), FRAC_CONST(0.885178028408975)}, + {FRAC_CONST(0.462353242576441), FRAC_CONST(0.886695821056495)}, {FRAC_CONST(0.459449066750752), FRAC_CONST(0.888204117904136)}, {FRAC_CONST(0.456539970594675), FRAC_CONST(0.889702902799251)}, + {FRAC_CONST(0.453625985262295), FRAC_CONST(0.891192159691058)}, {FRAC_CONST(0.450707141960053), FRAC_CONST(0.892671872630812)}, {FRAC_CONST(0.447783471946415), FRAC_CONST(0.894142025771977)}, + {FRAC_CONST(0.444855006531538), FRAC_CONST(0.895602603370393)}, {FRAC_CONST(0.441921777076935), FRAC_CONST(0.897053589784447)}, {FRAC_CONST(0.438983814995137), FRAC_CONST(0.898494969475242)}, + {FRAC_CONST(0.436041151749356), FRAC_CONST(0.899926727006758)}, {FRAC_CONST(0.433093818853152), FRAC_CONST(0.901348847046022)}, {FRAC_CONST(0.430141847870093), FRAC_CONST(0.902761314363272)}, + {FRAC_CONST(0.427185270413416), FRAC_CONST(0.904164113832116)}, {FRAC_CONST(0.424224118145690), FRAC_CONST(0.905557230429701)}, {FRAC_CONST(0.421258422778478), FRAC_CONST(0.906940649236866)}, + {FRAC_CONST(0.418288216071994), FRAC_CONST(0.908314355438308)}, {FRAC_CONST(0.415313529834766), FRAC_CONST(0.909678334322736)}, {FRAC_CONST(0.412334395923293), FRAC_CONST(0.911032571283032)}, + {FRAC_CONST(0.409350846241706), FRAC_CONST(0.912377051816407)}, {FRAC_CONST(0.406362912741425), FRAC_CONST(0.913711761524555)}, {FRAC_CONST(0.403370627420818), FRAC_CONST(0.915036686113806)}, + {FRAC_CONST(0.400374022324857), FRAC_CONST(0.916351811395282)}, {FRAC_CONST(0.397373129544774), FRAC_CONST(0.917657123285050)}, {FRAC_CONST(0.394367981217720), FRAC_CONST(0.918952607804266)}, + {FRAC_CONST(0.391358609526420), FRAC_CONST(0.920238251079332)}, {FRAC_CONST(0.388345046698826), FRAC_CONST(0.921514039342042)}, {FRAC_CONST(0.385327325007776), FRAC_CONST(0.922779958929729)}, + {FRAC_CONST(0.382305476770645), FRAC_CONST(0.924035996285410)}, {FRAC_CONST(0.379279534348999), FRAC_CONST(0.925282137957935)}, {FRAC_CONST(0.376249530148250), FRAC_CONST(0.926518370602127)}, + {FRAC_CONST(0.373215496617310), FRAC_CONST(0.927744680978929)}, {FRAC_CONST(0.370177466248239), FRAC_CONST(0.928961055955541)}, {FRAC_CONST(0.367135471575903), FRAC_CONST(0.930167482505564)}, + {FRAC_CONST(0.364089545177621), FRAC_CONST(0.931363947709140)}, {FRAC_CONST(0.361039719672816), FRAC_CONST(0.932550438753087)}, {FRAC_CONST(0.357986027722671), FRAC_CONST(0.933726942931039)}, + {FRAC_CONST(0.354928502029772), FRAC_CONST(0.934893447643582)}, {FRAC_CONST(0.351867175337763), FRAC_CONST(0.936049940398387)}, {FRAC_CONST(0.348802080430994), FRAC_CONST(0.937196408810347)}, + {FRAC_CONST(0.345733250134169), FRAC_CONST(0.938332840601705)}, {FRAC_CONST(0.342660717311994), FRAC_CONST(0.939459223602190)}, {FRAC_CONST(0.339584514868829), FRAC_CONST(0.940575545749145)}, + {FRAC_CONST(0.336504675748328), FRAC_CONST(0.941681795087657)}, {FRAC_CONST(0.333421232933097), FRAC_CONST(0.942777959770684)}, {FRAC_CONST(0.330334219444328), FRAC_CONST(0.943864028059183)}, + {FRAC_CONST(0.327243668341457), FRAC_CONST(0.944939988322235)}, {FRAC_CONST(0.324149612721804), FRAC_CONST(0.946005829037171)}, {FRAC_CONST(0.321052085720218), FRAC_CONST(0.947061538789691)}, + {FRAC_CONST(0.317951120508725), FRAC_CONST(0.948107106273994)}, {FRAC_CONST(0.314846750296171), FRAC_CONST(0.949142520292891)}, {FRAC_CONST(0.311739008327867), FRAC_CONST(0.950167769757930)}, + {FRAC_CONST(0.308627927885232), FRAC_CONST(0.951182843689513)}, {FRAC_CONST(0.305513542285440), FRAC_CONST(0.952187731217013)}, {FRAC_CONST(0.302395884881056), FRAC_CONST(0.953182421578893)}, + {FRAC_CONST(0.299274989059689), FRAC_CONST(0.954166904122818)}, {FRAC_CONST(0.296150888243624), FRAC_CONST(0.955141168305771)}, {FRAC_CONST(0.293023615889471), FRAC_CONST(0.956105203694164)}, + {FRAC_CONST(0.289893205487806), FRAC_CONST(0.957058999963955)}, {FRAC_CONST(0.286759690562807), FRAC_CONST(0.958002546900750)}, {FRAC_CONST(0.283623104671904), FRAC_CONST(0.958935834399920)}, + {FRAC_CONST(0.280483481405410), FRAC_CONST(0.959858852466706)}, {FRAC_CONST(0.277340854386169), FRAC_CONST(0.960771591216325)}, {FRAC_CONST(0.274195257269191), FRAC_CONST(0.961674040874080)}, + {FRAC_CONST(0.271046723741295), FRAC_CONST(0.962566191775459)}, {FRAC_CONST(0.267895287520743), FRAC_CONST(0.963448034366243)}, {FRAC_CONST(0.264740982356888), FRAC_CONST(0.964319559202607)}, + {FRAC_CONST(0.261583842029803), FRAC_CONST(0.965180756951218)}, {FRAC_CONST(0.258423900349924), FRAC_CONST(0.966031618389343)}, {FRAC_CONST(0.255261191157689), FRAC_CONST(0.966872134404937)}, + {FRAC_CONST(0.252095748323171), FRAC_CONST(0.967702295996750)}, {FRAC_CONST(0.248927605745720), FRAC_CONST(0.968522094274417)}, {FRAC_CONST(0.245756797353599), FRAC_CONST(0.969331520458559)}, + {FRAC_CONST(0.242583357103617), FRAC_CONST(0.970130565880871)}, {FRAC_CONST(0.239407318980770), FRAC_CONST(0.970919221984218)}, {FRAC_CONST(0.236228716997876), FRAC_CONST(0.971697480322728)}, + {FRAC_CONST(0.233047585195206), FRAC_CONST(0.972465332561878)}, {FRAC_CONST(0.229863957640129), FRAC_CONST(0.973222770478587)}, {FRAC_CONST(0.226677868426735), FRAC_CONST(0.973969785961306)}, + {FRAC_CONST(0.223489351675482), FRAC_CONST(0.974706371010097)}, {FRAC_CONST(0.220298441532823), FRAC_CONST(0.975432517736727)}, {FRAC_CONST(0.217105172170841), FRAC_CONST(0.976148218364747)}, + {FRAC_CONST(0.213909577786886), FRAC_CONST(0.976853465229579)}, {FRAC_CONST(0.210711692603206), FRAC_CONST(0.977548250778596)}, {FRAC_CONST(0.207511550866582), FRAC_CONST(0.978232567571202)}, + {FRAC_CONST(0.204309186847962), FRAC_CONST(0.978906408278914)}, {FRAC_CONST(0.201104634842092), FRAC_CONST(0.979569765685441)}, {FRAC_CONST(0.197897929167148), FRAC_CONST(0.980222632686756)}, + {FRAC_CONST(0.194689104164373), FRAC_CONST(0.980865002291179)}, {FRAC_CONST(0.191478194197704), FRAC_CONST(0.981496867619447)}, {FRAC_CONST(0.188265233653407), FRAC_CONST(0.982118221904791)}, + {FRAC_CONST(0.185050256939710), FRAC_CONST(0.982729058493005)}, {FRAC_CONST(0.181833298486427), FRAC_CONST(0.983329370842520)}, {FRAC_CONST(0.178614392744603), FRAC_CONST(0.983919152524473)}, + {FRAC_CONST(0.175393574186129), FRAC_CONST(0.984498397222776)}, {FRAC_CONST(0.172170877303385), FRAC_CONST(0.985067098734184)}, {FRAC_CONST(0.168946336608867), FRAC_CONST(0.985625250968360)}, + {FRAC_CONST(0.165719986634814), FRAC_CONST(0.986172847947943)}, {FRAC_CONST(0.162491861932842), FRAC_CONST(0.986709883808609)}, {FRAC_CONST(0.159261997073573), FRAC_CONST(0.987236352799134)}, + {FRAC_CONST(0.156030426646266), FRAC_CONST(0.987752249281460)}, {FRAC_CONST(0.152797185258443), FRAC_CONST(0.988257567730749)}, {FRAC_CONST(0.149562307535523), FRAC_CONST(0.988752302735447)}, + {FRAC_CONST(0.146325828120446), FRAC_CONST(0.989236448997339)}, {FRAC_CONST(0.143087781673307), FRAC_CONST(0.989710001331608)}, {FRAC_CONST(0.139848202870981), FRAC_CONST(0.990172954666889)}, + {FRAC_CONST(0.136607126406757), FRAC_CONST(0.990625304045323)}, {FRAC_CONST(0.133364586989957), FRAC_CONST(0.991067044622612)}, {FRAC_CONST(0.130120619345575), FRAC_CONST(0.991498171668069)}, + {FRAC_CONST(0.126875258213898), FRAC_CONST(0.991918680564670)}, {FRAC_CONST(0.123628538350136), FRAC_CONST(0.992328566809103)}, {FRAC_CONST(0.120380494524051), FRAC_CONST(0.992727826011815)}, + {FRAC_CONST(0.117131161519582), FRAC_CONST(0.993116453897061)}, {FRAC_CONST(0.113880574134475), FRAC_CONST(0.993494446302948)}, {FRAC_CONST(0.110628767179910), FRAC_CONST(0.993861799181482)}, + {FRAC_CONST(0.107375775480128), FRAC_CONST(0.994218508598608)}, {FRAC_CONST(0.104121633872055), FRAC_CONST(0.994564570734255)}, {FRAC_CONST(0.100866377204933), FRAC_CONST(0.994899981882376)}, + {FRAC_CONST(0.097610040339947), FRAC_CONST(0.995224738450986)}, {FRAC_CONST(0.094352658149849), FRAC_CONST(0.995538836962204)}, {FRAC_CONST(0.091094265518583), FRAC_CONST(0.995842274052287)}, + {FRAC_CONST(0.087834897340919), FRAC_CONST(0.996135046471667)}, {FRAC_CONST(0.084574588522070), FRAC_CONST(0.996417151084987)}, {FRAC_CONST(0.081313373977324), FRAC_CONST(0.996688584871134)}, + {FRAC_CONST(0.078051288631670), FRAC_CONST(0.996949344923269)}, {FRAC_CONST(0.074788367419420), FRAC_CONST(0.997199428448862)}, {FRAC_CONST(0.071524645283840), FRAC_CONST(0.997438832769720)}, + {FRAC_CONST(0.068260157176771), FRAC_CONST(0.997667555322013)}, {FRAC_CONST(0.064994938058259), FRAC_CONST(0.997885593656308)}, {FRAC_CONST(0.061729022896176), FRAC_CONST(0.998092945437590)}, + {FRAC_CONST(0.058462446665851), FRAC_CONST(0.998289608445286)}, {FRAC_CONST(0.055195244349690), FRAC_CONST(0.998475580573295)}, {FRAC_CONST(0.051927450936806), FRAC_CONST(0.998650859830004)}, + {FRAC_CONST(0.048659101422640), FRAC_CONST(0.998815444338313)}, {FRAC_CONST(0.045390230808591), FRAC_CONST(0.998969332335654)}, {FRAC_CONST(0.042120874101635), FRAC_CONST(0.999112522174011)}, + {FRAC_CONST(0.038851066313958), FRAC_CONST(0.999245012319936)}, {FRAC_CONST(0.035580842462574), FRAC_CONST(0.999366801354564)}, {FRAC_CONST(0.032310237568951), FRAC_CONST(0.999477887973635)}, + {FRAC_CONST(0.029039286658643), FRAC_CONST(0.999578270987499)}, {FRAC_CONST(0.025768024760904), FRAC_CONST(0.999667949321134)}, {FRAC_CONST(0.022496486908322), FRAC_CONST(0.999746922014158)}, + {FRAC_CONST(0.019224708136438), FRAC_CONST(0.999815188220837)}, {FRAC_CONST(0.015952723483375), FRAC_CONST(0.999872747210095)}, {FRAC_CONST(0.012680567989461), FRAC_CONST(0.999919598365521)}, + {FRAC_CONST(0.009408276696850), FRAC_CONST(0.999955741185376)}, {FRAC_CONST(0.006135884649155), FRAC_CONST(0.999981175282601)}, {FRAC_CONST(0.002863426891064), FRAC_CONST(0.999995900384816)}}; + #ifdef LD_DEC +/* 240 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_960[] = { + {FRAC_CONST(0.999999665337326), FRAC_CONST(0.000818122995607)}, {FRAC_CONST(0.999972892444367), FRAC_CONST(0.007363041249780)}, {FRAC_CONST(0.999903284040864), FRAC_CONST(0.013907644095771)}, + {FRAC_CONST(0.999790843108610), FRAC_CONST(0.020451651184577)}, {FRAC_CONST(0.999635574464198), FRAC_CONST(0.026994782192715)}, {FRAC_CONST(0.999437484758823), FRAC_CONST(0.033536756834230)}, + {FRAC_CONST(0.999196582477986), FRAC_CONST(0.040077294872701)}, {FRAC_CONST(0.998912877941140), FRAC_CONST(0.046616116133247)}, {FRAC_CONST(0.998586383301244), FRAC_CONST(0.053152940514528)}, + {FRAC_CONST(0.998217112544241), FRAC_CONST(0.059687488000744)}, {FRAC_CONST(0.997805081488460), FRAC_CONST(0.066219478673630)}, {FRAC_CONST(0.997350307783942), FRAC_CONST(0.072748632724445)}, + {FRAC_CONST(0.996852810911678), FRAC_CONST(0.079274670465961)}, {FRAC_CONST(0.996312612182778), FRAC_CONST(0.085797312344440)}, {FRAC_CONST(0.995729734737558), FRAC_CONST(0.092316278951614)}, + {FRAC_CONST(0.995104203544548), FRAC_CONST(0.098831291036650)}, {FRAC_CONST(0.994436045399422), FRAC_CONST(0.105342069518114)}, {FRAC_CONST(0.993725288923851), FRAC_CONST(0.111848335495926)}, + {FRAC_CONST(0.992971964564277), FRAC_CONST(0.118349810263305)}, {FRAC_CONST(0.992176104590608), FRAC_CONST(0.124846215318711)}, {FRAC_CONST(0.991337743094838), FRAC_CONST(0.131337272377774)}, + {FRAC_CONST(0.990456915989581), FRAC_CONST(0.137822703385212)}, {FRAC_CONST(0.989533661006540), FRAC_CONST(0.144302230526747)}, {FRAC_CONST(0.988568017694885), FRAC_CONST(0.150775576241001)}, + {FRAC_CONST(0.987560027419562), FRAC_CONST(0.157242463231389)}, {FRAC_CONST(0.986509733359519), FRAC_CONST(0.163702614477995)}, {FRAC_CONST(0.985417180505858), FRAC_CONST(0.170155753249442)}, + {FRAC_CONST(0.984282415659907), FRAC_CONST(0.176601603114742)}, {FRAC_CONST(0.983105487431216), FRAC_CONST(0.183039887955141)}, {FRAC_CONST(0.981886446235473), FRAC_CONST(0.189470331975943)}, + {FRAC_CONST(0.980625344292344), FRAC_CONST(0.195892659718330)}, {FRAC_CONST(0.979322235623241), FRAC_CONST(0.202306596071156)}, {FRAC_CONST(0.977977176049000), FRAC_CONST(0.208711866282735)}, + {FRAC_CONST(0.976590223187499), FRAC_CONST(0.215108195972610)}, {FRAC_CONST(0.975161436451181), FRAC_CONST(0.221495311143304)}, {FRAC_CONST(0.973690877044515), FRAC_CONST(0.227872938192063)}, + {FRAC_CONST(0.972178607961371), FRAC_CONST(0.234240803922570)}, {FRAC_CONST(0.970624693982323), FRAC_CONST(0.240598635556650)}, {FRAC_CONST(0.969029201671875), FRAC_CONST(0.246946160745958)}, + {FRAC_CONST(0.967392199375607), FRAC_CONST(0.253283107583640)}, {FRAC_CONST(0.965713757217249), FRAC_CONST(0.259609204615985)}, {FRAC_CONST(0.963993947095677), FRAC_CONST(0.265924180854051)}, + {FRAC_CONST(0.962232842681832), FRAC_CONST(0.272227765785273)}, {FRAC_CONST(0.960430519415566), FRAC_CONST(0.278519689385053)}, {FRAC_CONST(0.958587054502409), FRAC_CONST(0.284799682128326)}, + {FRAC_CONST(0.956702526910263), FRAC_CONST(0.291067475001103)}, {FRAC_CONST(0.954777017366017), FRAC_CONST(0.297322799511998)}, {FRAC_CONST(0.952810608352092), FRAC_CONST(0.303565387703730)}, + {FRAC_CONST(0.950803384102905), FRAC_CONST(0.309794972164597)}, {FRAC_CONST(0.948755430601263), FRAC_CONST(0.316011286039934)}, {FRAC_CONST(0.946666835574676), FRAC_CONST(0.322214063043544)}, + {FRAC_CONST(0.944537688491606), FRAC_CONST(0.328403037469105)}, {FRAC_CONST(0.942368080557626), FRAC_CONST(0.334577944201551)}, {FRAC_CONST(0.940158104711519), FRAC_CONST(0.340738518728429)}, + {FRAC_CONST(0.937907855621296), FRAC_CONST(0.346884497151231)}, {FRAC_CONST(0.935617429680138), FRAC_CONST(0.353015616196696)}, {FRAC_CONST(0.933286925002268), FRAC_CONST(0.359131613228090)}, + {FRAC_CONST(0.930916441418752), FRAC_CONST(0.365232226256457)}, {FRAC_CONST(0.928506080473216), FRAC_CONST(0.371317193951838)}, {FRAC_CONST(0.926055945417500), FRAC_CONST(0.377386255654469)}, + {FRAC_CONST(0.923566141207236), FRAC_CONST(0.383439151385947)}, {FRAC_CONST(0.921036774497350), FRAC_CONST(0.389475621860365)}, {FRAC_CONST(0.918467953637492), FRAC_CONST(0.395495408495417)}, + {FRAC_CONST(0.915859788667400), FRAC_CONST(0.401498253423481)}, {FRAC_CONST(0.913212391312179), FRAC_CONST(0.407483899502658)}, {FRAC_CONST(0.910525874977521), FRAC_CONST(0.413452090327791)}, + {FRAC_CONST(0.907800354744844), FRAC_CONST(0.419402570241451)}, {FRAC_CONST(0.905035947366364), FRAC_CONST(0.425335084344881)}, {FRAC_CONST(0.902232771260093), FRAC_CONST(0.431249378508924)}, + {FRAC_CONST(0.899390946504764), FRAC_CONST(0.437145199384900)}, {FRAC_CONST(0.896510594834693), FRAC_CONST(0.443022294415467)}, {FRAC_CONST(0.893591839634558), FRAC_CONST(0.448880411845433)}, + {FRAC_CONST(0.890634805934118), FRAC_CONST(0.454719300732547)}, {FRAC_CONST(0.887639620402854), FRAC_CONST(0.460538710958240)}, {FRAC_CONST(0.884606411344546), FRAC_CONST(0.466338393238348)}, + {FRAC_CONST(0.881535308691775), FRAC_CONST(0.472118099133784)}, {FRAC_CONST(0.878426444000357), FRAC_CONST(0.477877581061184)}, {FRAC_CONST(0.875279950443708), FRAC_CONST(0.483616592303511)}, + {FRAC_CONST(0.872095962807140), FRAC_CONST(0.489334887020625)}, {FRAC_CONST(0.868874617482085), FRAC_CONST(0.495032220259813)}, {FRAC_CONST(0.865616052460258), FRAC_CONST(0.500708347966279)}, + {FRAC_CONST(0.862320407327736), FRAC_CONST(0.506363026993605)}, {FRAC_CONST(0.858987823258990), FRAC_CONST(0.511996015114162)}, {FRAC_CONST(0.855618443010829), FRAC_CONST(0.517607071029487)}, + {FRAC_CONST(0.852212410916289), FRAC_CONST(0.523195954380619)}, {FRAC_CONST(0.848769872878448), FRAC_CONST(0.528762425758396)}, {FRAC_CONST(0.845290976364179), FRAC_CONST(0.534306246713712)}, + {FRAC_CONST(0.841775870397828), FRAC_CONST(0.539827179767727)}, {FRAC_CONST(0.838224705554838), FRAC_CONST(0.545324988422046)}, {FRAC_CONST(0.834637633955290), FRAC_CONST(0.550799437168844)}, + {FRAC_CONST(0.831014809257393), FRAC_CONST(0.556250291500956)}, {FRAC_CONST(0.827356386650900), FRAC_CONST(0.561677317921925)}, {FRAC_CONST(0.823662522850458), FRAC_CONST(0.567080283956001)}, + {FRAC_CONST(0.819933376088899), FRAC_CONST(0.572458958158102)}, {FRAC_CONST(0.816169106110459), FRAC_CONST(0.577813110123727)}, {FRAC_CONST(0.812369874163934), FRAC_CONST(0.583142510498826)}, + {FRAC_CONST(0.808535842995778), FRAC_CONST(0.588446930989624)}, {FRAC_CONST(0.804667176843123), FRAC_CONST(0.593726144372402)}, {FRAC_CONST(0.800764041426753), FRAC_CONST(0.598979924503229)}, + {FRAC_CONST(0.796826603943998), FRAC_CONST(0.604208046327650)}, {FRAC_CONST(0.792855033061574), FRAC_CONST(0.609410285890327)}, {FRAC_CONST(0.788849498908361), FRAC_CONST(0.614586420344631)}, + {FRAC_CONST(0.784810173068109), FRAC_CONST(0.619736227962191)}, {FRAC_CONST(0.780737228572094), FRAC_CONST(0.624859488142386)}, {FRAC_CONST(0.776630839891703), FRAC_CONST(0.629955981421804)}, + {FRAC_CONST(0.772491182930959), FRAC_CONST(0.635025489483633)}, {FRAC_CONST(0.768318435018988), FRAC_CONST(0.640067795167023)}, {FRAC_CONST(0.764112774902423), FRAC_CONST(0.645082682476378)}, + {FRAC_CONST(0.759874382737746), FRAC_CONST(0.650069936590618)}, {FRAC_CONST(0.755603440083571), FRAC_CONST(0.655029343872374)}, {FRAC_CONST(0.751300129892866), FRAC_CONST(0.659960691877147)}, + {FRAC_CONST(0.746964636505118), FRAC_CONST(0.664863769362399)}, {FRAC_CONST(0.742597145638433), FRAC_CONST(0.669738366296610)}, {FRAC_CONST(0.738197844381584), FRAC_CONST(0.674584273868271)}, + {FRAC_CONST(0.733766921185995), FRAC_CONST(0.679401284494831)}, {FRAC_CONST(0.729304565857668), FRAC_CONST(0.684189191831585)}, {FRAC_CONST(0.724810969549055), FRAC_CONST(0.688947790780520)}, + {FRAC_CONST(0.720286324750863), FRAC_CONST(0.693676877499095)}, {FRAC_CONST(0.715730825283819), FRAC_CONST(0.698376249408973)}, {FRAC_CONST(0.711144666290356), FRAC_CONST(0.703045705204703)}, + {FRAC_CONST(0.706528044226263), FRAC_CONST(0.707685044862340)}, {FRAC_CONST(0.701881156852263), FRAC_CONST(0.712294069648014)}, {FRAC_CONST(0.697204203225545), FRAC_CONST(0.716872582126442)}, + {FRAC_CONST(0.692497383691237), FRAC_CONST(0.721420386169390)}, {FRAC_CONST(0.687760899873822), FRAC_CONST(0.725937286964068)}, {FRAC_CONST(0.682994954668502), FRAC_CONST(0.730423091021479)}, + {FRAC_CONST(0.678199752232508), FRAC_CONST(0.734877606184707)}, {FRAC_CONST(0.673375497976352), FRAC_CONST(0.739300641637149)}, {FRAC_CONST(0.668522398555031), FRAC_CONST(0.743692007910687)}, + {FRAC_CONST(0.663640661859171), FRAC_CONST(0.748051516893805)}, {FRAC_CONST(0.658730497006124), FRAC_CONST(0.752378981839648)}, {FRAC_CONST(0.653792114331011), FRAC_CONST(0.756674217374021)}, + {FRAC_CONST(0.648825725377709), FRAC_CONST(0.760937039503328)}, {FRAC_CONST(0.643831542889792), FRAC_CONST(0.765167265622459)}, {FRAC_CONST(0.638809780801414), FRAC_CONST(0.769364714522605)}, + {FRAC_CONST(0.633760654228152), FRAC_CONST(0.773529206399025)}, {FRAC_CONST(0.628684379457781), FRAC_CONST(0.777660562858748)}, {FRAC_CONST(0.623581173941019), FRAC_CONST(0.781758606928213)}, + {FRAC_CONST(0.618451256282204), FRAC_CONST(0.785823163060853)}, {FRAC_CONST(0.613294846229936), FRAC_CONST(0.789854057144609)}, {FRAC_CONST(0.608112164667659), FRAC_CONST(0.793851116509396)}, + {FRAC_CONST(0.602903433604202), FRAC_CONST(0.797814169934493)}, {FRAC_CONST(0.597668876164268), FRAC_CONST(0.801743047655882)}, {FRAC_CONST(0.592408716578875), FRAC_CONST(0.805637581373517)}, + {FRAC_CONST(0.587123180175754), FRAC_CONST(0.809497604258536)}, {FRAC_CONST(0.581812493369691), FRAC_CONST(0.813322950960406)}, {FRAC_CONST(0.576476883652835), FRAC_CONST(0.817113457614006)}, + {FRAC_CONST(0.571116579584947), FRAC_CONST(0.820868961846646)}, {FRAC_CONST(0.565731810783613), FRAC_CONST(0.824589302785025)}, {FRAC_CONST(0.560322807914407), FRAC_CONST(0.828274321062119)}, + {FRAC_CONST(0.554889802681009), FRAC_CONST(0.831923858824010)}, {FRAC_CONST(0.549433027815281), FRAC_CONST(0.835537759736646)}, {FRAC_CONST(0.543952717067296), FRAC_CONST(0.839115868992540)}, + {FRAC_CONST(0.538449105195327), FRAC_CONST(0.842658033317402)}, {FRAC_CONST(0.532922427955790), FRAC_CONST(0.846164100976699)}, {FRAC_CONST(0.527372922093142), FRAC_CONST(0.849633921782164)}, + {FRAC_CONST(0.521800825329746), FRAC_CONST(0.853067347098221)}, {FRAC_CONST(0.516206376355680), FRAC_CONST(0.856464229848356)}, {FRAC_CONST(0.510589814818519), FRAC_CONST(0.859824424521420)}, + {FRAC_CONST(0.504951381313066), FRAC_CONST(0.863147787177854)}, {FRAC_CONST(0.499291317371047), FRAC_CONST(0.866434175455865)}, {FRAC_CONST(0.493609865450762), FRAC_CONST(0.869683448577516)}, + {FRAC_CONST(0.487907268926702), FRAC_CONST(0.872895467354761)}, {FRAC_CONST(0.482183772079123), FRAC_CONST(0.876070094195407)}, {FRAC_CONST(0.476439620083580), FRAC_CONST(0.879207193109004)}, + {FRAC_CONST(0.470675059000427), FRAC_CONST(0.882306629712678)}, {FRAC_CONST(0.464890335764274), FRAC_CONST(0.885368271236879)}, {FRAC_CONST(0.459085698173413), FRAC_CONST(0.888391986531075)}, + {FRAC_CONST(0.453261394879198), FRAC_CONST(0.891377646069366)}, {FRAC_CONST(0.447417675375397), FRAC_CONST(0.894325121956035)}, {FRAC_CONST(0.441554789987504), FRAC_CONST(0.897234287931024)}, + {FRAC_CONST(0.435672989862017), FRAC_CONST(0.900105019375345)}, {FRAC_CONST(0.429772526955677), FRAC_CONST(0.902937193316419)}, {FRAC_CONST(0.423853654024676), FRAC_CONST(0.905730688433339)}, + {FRAC_CONST(0.417916624613831), FRAC_CONST(0.908485385062073)}, {FRAC_CONST(0.411961693045722), FRAC_CONST(0.911201165200584)}, {FRAC_CONST(0.405989114409798), FRAC_CONST(0.913877912513892)}, + {FRAC_CONST(0.399999144551449), FRAC_CONST(0.916515512339049)}, {FRAC_CONST(0.393992040061048), FRAC_CONST(0.919113851690058)}, {FRAC_CONST(0.387968058262959), FRAC_CONST(0.921672819262709)}, + {FRAC_CONST(0.381927457204511), FRAC_CONST(0.924192305439348)}, {FRAC_CONST(0.375870495644949), FRAC_CONST(0.926672202293573)}, {FRAC_CONST(0.369797433044349), FRAC_CONST(0.929112403594856)}, + {FRAC_CONST(0.363708529552499), FRAC_CONST(0.931512804813095)}, {FRAC_CONST(0.357604045997758), FRAC_CONST(0.933873303123091)}, {FRAC_CONST(0.351484243875885), FRAC_CONST(0.936193797408954)}, + {FRAC_CONST(0.345349385338836), FRAC_CONST(0.938474188268430)}, {FRAC_CONST(0.339199733183530), FRAC_CONST(0.940714378017165)}, {FRAC_CONST(0.333035550840599), FRAC_CONST(0.942914270692887)}, + {FRAC_CONST(0.326857102363098), FRAC_CONST(0.945073772059514)}, {FRAC_CONST(0.320664652415198), FRAC_CONST(0.947192789611197)}, {FRAC_CONST(0.314458466260842), FRAC_CONST(0.949271232576274)}, + {FRAC_CONST(0.308238809752391), FRAC_CONST(0.951309011921168)}, {FRAC_CONST(0.302005949319228), FRAC_CONST(0.953306040354194)}, {FRAC_CONST(0.295760151956351), FRAC_CONST(0.955262232329299)}, + {FRAC_CONST(0.289501685212929), FRAC_CONST(0.957177504049732)}, {FRAC_CONST(0.283230817180850), FRAC_CONST(0.959051773471624)}, {FRAC_CONST(0.276947816483228), FRAC_CONST(0.960884960307514)}, + {FRAC_CONST(0.270652952262902), FRAC_CONST(0.962676986029777)}, {FRAC_CONST(0.264346494170904), FRAC_CONST(0.964427773873996)}, {FRAC_CONST(0.258028712354909), FRAC_CONST(0.966137248842248)}, + {FRAC_CONST(0.251699877447663), FRAC_CONST(0.967805337706313)}, {FRAC_CONST(0.245360260555389), FRAC_CONST(0.969431969010818)}, {FRAC_CONST(0.239010133246176), FRAC_CONST(0.971017073076290)}, + {FRAC_CONST(0.232649767538342), FRAC_CONST(0.972560582002147)}, {FRAC_CONST(0.226279435888785), FRAC_CONST(0.974062429669605)}, {FRAC_CONST(0.219899411181310), FRAC_CONST(0.975522551744506)}, + {FRAC_CONST(0.213509966714943), FRAC_CONST(0.976940885680082)}, {FRAC_CONST(0.207111376192219), FRAC_CONST(0.978317370719628)}, {FRAC_CONST(0.200703913707458), FRAC_CONST(0.979651947899104)}, + {FRAC_CONST(0.194287853735029), FRAC_CONST(0.980944560049668)}, {FRAC_CONST(0.187863471117585), FRAC_CONST(0.982195151800116)}, {FRAC_CONST(0.181431041054297), FRAC_CONST(0.983403669579260)}, + {FRAC_CONST(0.174990839089060), FRAC_CONST(0.984570061618221)}, {FRAC_CONST(0.168543141098691), FRAC_CONST(0.985694277952645)}, {FRAC_CONST(0.162088223281113), FRAC_CONST(0.986776270424848)}, + {FRAC_CONST(0.155626362143520), FRAC_CONST(0.987815992685872)}, {FRAC_CONST(0.149157834490539), FRAC_CONST(0.988813400197476)}, {FRAC_CONST(0.142682917412363), FRAC_CONST(0.989768450234042)}, + {FRAC_CONST(0.136201888272891), FRAC_CONST(0.990681101884405)}, {FRAC_CONST(0.129715024697841), FRAC_CONST(0.991551316053606)}, {FRAC_CONST(0.123222604562857), FRAC_CONST(0.992379055464567)}, + {FRAC_CONST(0.116724905981611), FRAC_CONST(0.993164284659685)}, {FRAC_CONST(0.110222207293883), FRAC_CONST(0.993906970002356)}, {FRAC_CONST(0.103714787053643), FRAC_CONST(0.994607079678411)}, + {FRAC_CONST(0.097202924017115), FRAC_CONST(0.995264583697482)}, {FRAC_CONST(0.090686897130838), FRAC_CONST(0.995879453894286)}, {FRAC_CONST(0.084166985519718), FRAC_CONST(0.996451663929828)}, + {FRAC_CONST(0.077643468475068), FRAC_CONST(0.996981189292537)}, {FRAC_CONST(0.071116625442645), FRAC_CONST(0.997468007299307)}, {FRAC_CONST(0.064586736010684), FRAC_CONST(0.997912097096476)}, + {FRAC_CONST(0.058054079897912), FRAC_CONST(0.998313439660714)}, {FRAC_CONST(0.051518936941578), FRAC_CONST(0.998672017799843)}, {FRAC_CONST(0.044981587085452), FRAC_CONST(0.998987816153567)}, + {FRAC_CONST(0.038442310367847), FRAC_CONST(0.999260821194138)}, {FRAC_CONST(0.031901386909611), FRAC_CONST(0.999491021226926)}, {FRAC_CONST(0.025359096902136), FRAC_CONST(0.999678406390929)}, + {FRAC_CONST(0.018815720595351), FRAC_CONST(0.999822968659191)}, {FRAC_CONST(0.012271538285720), FRAC_CONST(0.999924701839145)}, {FRAC_CONST(0.005726830304231), FRAC_CONST(0.999983601572879)}}; + #endif // LD_DEC +/* 60 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_240[] = { + {FRAC_CONST(0.999994645401696), FRAC_CONST(0.003272486506527)}, {FRAC_CONST(0.999566308502021), FRAC_CONST(0.029448173247963)}, {FRAC_CONST(0.998452918783950), FRAC_CONST(0.055603677682425)}, + {FRAC_CONST(0.996655239309180), FRAC_CONST(0.081721074133668)}, {FRAC_CONST(0.994174502117428), FRAC_CONST(0.107782463042759)}, {FRAC_CONST(0.991012407382049), FRAC_CONST(0.133769983235535)}, + {FRAC_CONST(0.987171122244825), FRAC_CONST(0.159665824163761)}, {FRAC_CONST(0.982653279330712), FRAC_CONST(0.185452238111591)}, {FRAC_CONST(0.977461974943572), FRAC_CONST(0.211111552358965)}, + {FRAC_CONST(0.971600766944121), FRAC_CONST(0.236626181293610)}, {FRAC_CONST(0.965073672311547), FRAC_CONST(0.261978638463337)}, {FRAC_CONST(0.957885164390477), FRAC_CONST(0.287151548560387)}, + {FRAC_CONST(0.950040169825165), FRAC_CONST(0.312127659329594)}, {FRAC_CONST(0.941544065183021), FRAC_CONST(0.336889853392220)}, {FRAC_CONST(0.932402673269775), FRAC_CONST(0.361421159977355)}, + {FRAC_CONST(0.922622259138823), FRAC_CONST(0.385704766552831)}, {FRAC_CONST(0.912209525797468), FRAC_CONST(0.409724030347695)}, {FRAC_CONST(0.901171609613013), FRAC_CONST(0.433462489758331)}, + {FRAC_CONST(0.889516075421856), FRAC_CONST(0.456903875630421)}, {FRAC_CONST(0.877250911344924), FRAC_CONST(0.480032122409011)}, {FRAC_CONST(0.864384523313017), FRAC_CONST(0.502831379149042)}, + {FRAC_CONST(0.850925729305802), FRAC_CONST(0.525286020378792)}, {FRAC_CONST(0.836883753308409), FRAC_CONST(0.547380656808797)}, {FRAC_CONST(0.822268218989775), FRAC_CONST(0.569100145878898)}, + {FRAC_CONST(0.807089143107059), FRAC_CONST(0.590429602136201)}, {FRAC_CONST(0.791356928640660), FRAC_CONST(0.611354407436816)}, {FRAC_CONST(0.775082357664531), FRAC_CONST(0.631860220964409)}, + {FRAC_CONST(0.758276583956687), FRAC_CONST(0.651932989058674)}, {FRAC_CONST(0.740951125354959), FRAC_CONST(0.671558954847018)}, {FRAC_CONST(0.723117855863248), FRAC_CONST(0.690724667672829)}, + {FRAC_CONST(0.704788997513670), FRAC_CONST(0.709416992313883)}, {FRAC_CONST(0.685977111990193), FRAC_CONST(0.727623117984575)}, {FRAC_CONST(0.666695092019479), FRAC_CONST(0.745330567115786)}, + {FRAC_CONST(0.646956152534857), FRAC_CONST(0.762527203906388)}, {FRAC_CONST(0.626773821619469), FRAC_CONST(0.779201242640517)}, {FRAC_CONST(0.606161931234795), FRAC_CONST(0.795341255764910)}, + {FRAC_CONST(0.585134607740916), FRAC_CONST(0.810936181720784)}, {FRAC_CONST(0.563706262215017), FRAC_CONST(0.825975332524873)}, {FRAC_CONST(0.541891580574752), FRAC_CONST(0.840448401094438)}, + {FRAC_CONST(0.519705513513249), FRAC_CONST(0.854345468311227)}, {FRAC_CONST(0.497163266252654), FRAC_CONST(0.867657009819544)}, {FRAC_CONST(0.474280288123229), FRAC_CONST(0.880373902553765)}, + {FRAC_CONST(0.451072261975153), FRAC_CONST(0.892487430990834)}, {FRAC_CONST(0.427555093430282), FRAC_CONST(0.903989293123443)}, {FRAC_CONST(0.403744899981227), FRAC_CONST(0.914871606149819)}, + {FRAC_CONST(0.379657999945233), FRAC_CONST(0.925126911876195)}, {FRAC_CONST(0.355310901280416), FRAC_CONST(0.934748181828292)}, {FRAC_CONST(0.330720290272038), FRAC_CONST(0.943728822068278)}, + {FRAC_CONST(0.305903020096554), FRAC_CONST(0.952062677713924)}, {FRAC_CONST(0.280876099271292), FRAC_CONST(0.959744037156857)}, {FRAC_CONST(0.255656679997665), FRAC_CONST(0.966767635977008)}, + {FRAC_CONST(0.230262046405902), FRAC_CONST(0.973128660550580)}, {FRAC_CONST(0.204709602709380), FRAC_CONST(0.978822751349072)}, {FRAC_CONST(0.179016861276633), FRAC_CONST(0.983846005927077)}, + {FRAC_CONST(0.153201430629259), FRAC_CONST(0.988194981596825)}, {FRAC_CONST(0.127281003373913), FRAC_CONST(0.991866697787626)}, {FRAC_CONST(0.101273344076683), FRAC_CONST(0.994858638088611)}, + {FRAC_CONST(0.075196277088140), FRAC_CONST(0.997168751973348)}, {FRAC_CONST(0.049067674327418), FRAC_CONST(0.998795456205172)}, {FRAC_CONST(0.022905443033697), FRAC_CONST(0.999737635922260)}}; + #endif // ALLOW_SMALL_FRAMELENGTH + #ifdef SSR_DEC +/* 128 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_512[] = { + {FRAC_CONST(0.999998823451702), FRAC_CONST(0.001533980186285)}, {FRAC_CONST(0.999904701082853), FRAC_CONST(0.013805388528060)}, {FRAC_CONST(0.999659996743959), FRAC_CONST(0.026074717829104)}, + {FRAC_CONST(0.999264747286594), FRAC_CONST(0.038340120373553)}, {FRAC_CONST(0.998719012233873), FRAC_CONST(0.050599749036899)}, {FRAC_CONST(0.998022873771486), FRAC_CONST(0.062851757564161)}, + {FRAC_CONST(0.997176436735326), FRAC_CONST(0.075094300847921)}, {FRAC_CONST(0.996179828595697), FRAC_CONST(0.087325535206192)}, {FRAC_CONST(0.995033199438119), FRAC_CONST(0.099543618660069)}, + {FRAC_CONST(0.993736721940725), FRAC_CONST(0.111746711211127)}, {FRAC_CONST(0.992290591348257), FRAC_CONST(0.123932975118512)}, {FRAC_CONST(0.990695025442665), FRAC_CONST(0.136100575175706)}, + {FRAC_CONST(0.988950264510303), FRAC_CONST(0.148247678986896)}, {FRAC_CONST(0.987056571305751), FRAC_CONST(0.160372457242928)}, {FRAC_CONST(0.985014231012240), FRAC_CONST(0.172473083996796)}, + {FRAC_CONST(0.982823551198705), FRAC_CONST(0.184547736938620)}, {FRAC_CONST(0.980484861773469), FRAC_CONST(0.196594597670080)}, {FRAC_CONST(0.977998514934557), FRAC_CONST(0.208611851978263)}, + {FRAC_CONST(0.975364885116657), FRAC_CONST(0.220597690108874)}, {FRAC_CONST(0.972584368934732), FRAC_CONST(0.232550307038775)}, {FRAC_CONST(0.969657385124292), FRAC_CONST(0.244467902747824)}, + {FRAC_CONST(0.966584374478333), FRAC_CONST(0.256348682489943)}, {FRAC_CONST(0.963365799780954), FRAC_CONST(0.268190857063403)}, {FRAC_CONST(0.960002145737666), FRAC_CONST(0.279992643080273)}, + {FRAC_CONST(0.956493918902395), FRAC_CONST(0.291752263234989)}, {FRAC_CONST(0.952841647601199), FRAC_CONST(0.303467946572011)}, {FRAC_CONST(0.949045881852701), FRAC_CONST(0.315137928752522)}, + {FRAC_CONST(0.945107193285261), FRAC_CONST(0.326760452320132)}, {FRAC_CONST(0.941026175050889), FRAC_CONST(0.338333766965541)}, {FRAC_CONST(0.936803441735922), FRAC_CONST(0.349856129790135)}, + {FRAC_CONST(0.932439629268462), FRAC_CONST(0.361325805568454)}, {FRAC_CONST(0.927935394822618), FRAC_CONST(0.372741067009516)}, {FRAC_CONST(0.923291416719528), FRAC_CONST(0.384100195016935)}, + {FRAC_CONST(0.918508394325212), FRAC_CONST(0.395401478947816)}, {FRAC_CONST(0.913587047945251), FRAC_CONST(0.406643216870369)}, {FRAC_CONST(0.908528118716306), FRAC_CONST(0.417823715820212)}, + {FRAC_CONST(0.903332368494512), FRAC_CONST(0.428941292055329)}, {FRAC_CONST(0.898000579740740), FRAC_CONST(0.439994271309633)}, {FRAC_CONST(0.892533555402765), FRAC_CONST(0.450980989045104)}, + {FRAC_CONST(0.886932118794342), FRAC_CONST(0.461899790702463)}, {FRAC_CONST(0.881197113471222), FRAC_CONST(0.472749031950343)}, {FRAC_CONST(0.875329403104111), FRAC_CONST(0.483527078932919)}, + {FRAC_CONST(0.869329871348607), FRAC_CONST(0.494232308515960)}, {FRAC_CONST(0.863199421712124), FRAC_CONST(0.504863108531268)}, {FRAC_CONST(0.856938977417829), FRAC_CONST(0.515417878019463)}, + {FRAC_CONST(0.850549481265603), FRAC_CONST(0.525895027471085)}, {FRAC_CONST(0.844031895490066), FRAC_CONST(0.536292979065963)}, {FRAC_CONST(0.837387201615662), FRAC_CONST(0.546610166910835)}, + {FRAC_CONST(0.830616400308846), FRAC_CONST(0.556845037275160)}, {FRAC_CONST(0.823720511227391), FRAC_CONST(0.566996048825109)}, {FRAC_CONST(0.816700572866828), FRAC_CONST(0.577061672855679)}, + {FRAC_CONST(0.809557642404051), FRAC_CONST(0.587040393520918)}, {FRAC_CONST(0.802292795538116), FRAC_CONST(0.596930708062197)}, {FRAC_CONST(0.794907126328237), FRAC_CONST(0.606731127034524)}, + {FRAC_CONST(0.787401747029031), FRAC_CONST(0.616440174530854)}, {FRAC_CONST(0.779777787923015), FRAC_CONST(0.626056388404344)}, {FRAC_CONST(0.772036397150385), FRAC_CONST(0.635578320488556)}, + {FRAC_CONST(0.764178740536117), FRAC_CONST(0.645004536815544)}, {FRAC_CONST(0.756206001414395), FRAC_CONST(0.654333617831800)}, {FRAC_CONST(0.748119380450404), FRAC_CONST(0.663564158612040)}, + {FRAC_CONST(0.739920095459516), FRAC_CONST(0.672694769070773)}, {FRAC_CONST(0.731609381223893), FRAC_CONST(0.681724074171650)}, {FRAC_CONST(0.723188489306527), FRAC_CONST(0.690650714134535)}, + {FRAC_CONST(0.714658687862769), FRAC_CONST(0.699473344640284)}, {FRAC_CONST(0.706021261449340), FRAC_CONST(0.708190637033195)}, {FRAC_CONST(0.697277510830887), FRAC_CONST(0.716801278521100)}, + {FRAC_CONST(0.688428752784091), FRAC_CONST(0.725303972373061)}, {FRAC_CONST(0.679476319899365), FRAC_CONST(0.733697438114660)}, {FRAC_CONST(0.670421560380173), FRAC_CONST(0.741980411720831)}, + {FRAC_CONST(0.661265837839992), FRAC_CONST(0.750151645806215)}, {FRAC_CONST(0.652010531096960), FRAC_CONST(0.758209909813015)}, {FRAC_CONST(0.642657033966227), FRAC_CONST(0.766153990196313)}, + {FRAC_CONST(0.633206755050057), FRAC_CONST(0.773982690606823)}, {FRAC_CONST(0.623661117525695), FRAC_CONST(0.781694832071059)}, {FRAC_CONST(0.614021558931038), FRAC_CONST(0.789289253168886)}, + {FRAC_CONST(0.604289530948156), FRAC_CONST(0.796764810208419)}, {FRAC_CONST(0.594466499184665), FRAC_CONST(0.804120377398266)}, {FRAC_CONST(0.584553942953015), FRAC_CONST(0.811354847017064)}, + {FRAC_CONST(0.574553355047716), FRAC_CONST(0.818467129580299)}, {FRAC_CONST(0.564466241520520), FRAC_CONST(0.825456154004377)}, {FRAC_CONST(0.554294121453620), FRAC_CONST(0.832320867767930)}, + {FRAC_CONST(0.544038526730884), FRAC_CONST(0.839060237070313)}, {FRAC_CONST(0.533701001807153), FRAC_CONST(0.845673246987299)}, {FRAC_CONST(0.523283103475656), FRAC_CONST(0.852158901623920)}, + {FRAC_CONST(0.512786400633563), FRAC_CONST(0.858516224264443)}, {FRAC_CONST(0.502212474045711), FRAC_CONST(0.864744257519462)}, {FRAC_CONST(0.491562916106550), FRAC_CONST(0.870842063470079)}, + {FRAC_CONST(0.480839330600334), FRAC_CONST(0.876808723809146)}, {FRAC_CONST(0.470043332459596), FRAC_CONST(0.882643339979563)}, {FRAC_CONST(0.459176547521944), FRAC_CONST(0.888345033309596)}, + {FRAC_CONST(0.448240612285220), FRAC_CONST(0.893912945145203)}, {FRAC_CONST(0.437237173661044), FRAC_CONST(0.899346236979341)}, {FRAC_CONST(0.426167888726800), FRAC_CONST(0.904644090578246)}, + {FRAC_CONST(0.415034424476082), FRAC_CONST(0.909805708104652)}, {FRAC_CONST(0.403838457567654), FRAC_CONST(0.914830312237946)}, {FRAC_CONST(0.392581674072952), FRAC_CONST(0.919717146291227)}, + {FRAC_CONST(0.381265769222162), FRAC_CONST(0.924465474325263)}, {FRAC_CONST(0.369892447148934), FRAC_CONST(0.929074581259316)}, {FRAC_CONST(0.358463420633737), FRAC_CONST(0.933543772978836)}, + {FRAC_CONST(0.346980410845924), FRAC_CONST(0.937872376439990)}, {FRAC_CONST(0.335445147084532), FRAC_CONST(0.942059739771017)}, {FRAC_CONST(0.323859366517853), FRAC_CONST(0.946105232370403)}, + {FRAC_CONST(0.312224813921825), FRAC_CONST(0.950008245001843)}, {FRAC_CONST(0.300543241417273), FRAC_CONST(0.953768189885990)}, {FRAC_CONST(0.288816408206049), FRAC_CONST(0.957384500788976)}, + {FRAC_CONST(0.277046080306100), FRAC_CONST(0.960856633107680)}, {FRAC_CONST(0.265234030285512), FRAC_CONST(0.964184063951746)}, {FRAC_CONST(0.253382036995570), FRAC_CONST(0.967366292222329)}, + {FRAC_CONST(0.241491885302869), FRAC_CONST(0.970402838687556)}, {FRAC_CONST(0.229565365820519), FRAC_CONST(0.973293246054698)}, {FRAC_CONST(0.217604274638484), FRAC_CONST(0.976037079039039)}, + {FRAC_CONST(0.205610413053099), FRAC_CONST(0.978633924429423)}, {FRAC_CONST(0.193585587295804), FRAC_CONST(0.981083391150487)}, {FRAC_CONST(0.181531608261125), FRAC_CONST(0.983385110321551)}, + {FRAC_CONST(0.169450291233968), FRAC_CONST(0.985538735312176)}, {FRAC_CONST(0.157343455616238), FRAC_CONST(0.987543941794359)}, {FRAC_CONST(0.145212924652848), FRAC_CONST(0.989400427791380)}, + {FRAC_CONST(0.133060525157139), FRAC_CONST(0.991107913723277)}, {FRAC_CONST(0.120888087235777), FRAC_CONST(0.992666142448948)}, {FRAC_CONST(0.108697444013139), FRAC_CONST(0.994074879304879)}, + {FRAC_CONST(0.096490431355253), FRAC_CONST(0.995333912140482)}, {FRAC_CONST(0.084268887593324), FRAC_CONST(0.996443051350043)}, {FRAC_CONST(0.072034653246889), FRAC_CONST(0.997402129901275)}, + {FRAC_CONST(0.059789570746640), FRAC_CONST(0.998211003360478)}, {FRAC_CONST(0.047535484156959), FRAC_CONST(0.998869549914284)}, {FRAC_CONST(0.035274238898214), FRAC_CONST(0.999377670388003)}, + {FRAC_CONST(0.023007681468839), FRAC_CONST(0.999735288260562)}, {FRAC_CONST(0.010737659167265), FRAC_CONST(0.999942349676024)}}; +/* 16 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_64[] = { + {FRAC_CONST(0.999924701839145), FRAC_CONST(0.012271538285720)}, {FRAC_CONST(0.993906970002356), FRAC_CONST(0.110222207293883)}, {FRAC_CONST(0.978317370719628), FRAC_CONST(0.207111376192219)}, + {FRAC_CONST(0.953306040354194), FRAC_CONST(0.302005949319228)}, {FRAC_CONST(0.919113851690058), FRAC_CONST(0.393992040061048)}, {FRAC_CONST(0.876070094195407), FRAC_CONST(0.482183772079123)}, + {FRAC_CONST(0.824589302785025), FRAC_CONST(0.565731810783613)}, {FRAC_CONST(0.765167265622459), FRAC_CONST(0.643831542889791)}, {FRAC_CONST(0.698376249408973), FRAC_CONST(0.715730825283819)}, + {FRAC_CONST(0.624859488142386), FRAC_CONST(0.780737228572094)}, {FRAC_CONST(0.545324988422046), FRAC_CONST(0.838224705554838)}, {FRAC_CONST(0.460538710958240), FRAC_CONST(0.887639620402854)}, + {FRAC_CONST(0.371317193951838), FRAC_CONST(0.928506080473215)}, {FRAC_CONST(0.278519689385053), FRAC_CONST(0.960430519415566)}, {FRAC_CONST(0.183039887955141), FRAC_CONST(0.983105487431216)}, + {FRAC_CONST(0.085797312344440), FRAC_CONST(0.996312612182778)}}; + #endif // SSR_DEC +#else // FIXED_POINT +/* 256 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_2048[] = { + {FRAC_CONST(0.031249997702054), FRAC_CONST(0.000011984224612)}, {FRAC_CONST(0.031249813866531), FRAC_CONST(0.000107857810004)}, {FRAC_CONST(0.031249335895858), FRAC_CONST(0.000203730380198)}, + {FRAC_CONST(0.031248563794535), FRAC_CONST(0.000299601032804)}, {FRAC_CONST(0.031247497569829), FRAC_CONST(0.000395468865451)}, {FRAC_CONST(0.031246137231775), FRAC_CONST(0.000491332975794)}, + {FRAC_CONST(0.031244482793177), FRAC_CONST(0.000587192461525)}, {FRAC_CONST(0.031242534269608), FRAC_CONST(0.000683046420376)}, {FRAC_CONST(0.031240291679407), FRAC_CONST(0.000778893950134)}, + {FRAC_CONST(0.031237755043684), FRAC_CONST(0.000874734148645)}, {FRAC_CONST(0.031234924386313), FRAC_CONST(0.000970566113826)}, {FRAC_CONST(0.031231799733938), FRAC_CONST(0.001066388943669)}, + {FRAC_CONST(0.031228381115970), FRAC_CONST(0.001162201736253)}, {FRAC_CONST(0.031224668564585), FRAC_CONST(0.001258003589751)}, {FRAC_CONST(0.031220662114728), FRAC_CONST(0.001353793602441)}, + {FRAC_CONST(0.031216361804108), FRAC_CONST(0.001449570872710)}, {FRAC_CONST(0.031211767673203), FRAC_CONST(0.001545334499065)}, {FRAC_CONST(0.031206879765253), FRAC_CONST(0.001641083580144)}, + {FRAC_CONST(0.031201698126266), FRAC_CONST(0.001736817214719)}, {FRAC_CONST(0.031196222805014), FRAC_CONST(0.001832534501709)}, {FRAC_CONST(0.031190453853031), FRAC_CONST(0.001928234540186)}, + {FRAC_CONST(0.031184391324617), FRAC_CONST(0.002023916429386)}, {FRAC_CONST(0.031178035276836), FRAC_CONST(0.002119579268713)}, {FRAC_CONST(0.031171385769513), FRAC_CONST(0.002215222157753)}, + {FRAC_CONST(0.031164442865236), FRAC_CONST(0.002310844196278)}, {FRAC_CONST(0.031157206629353), FRAC_CONST(0.002406444484258)}, {FRAC_CONST(0.031149677129975), FRAC_CONST(0.002502022121865)}, + {FRAC_CONST(0.031141854437973), FRAC_CONST(0.002597576209488)}, {FRAC_CONST(0.031133738626977), FRAC_CONST(0.002693105847734)}, {FRAC_CONST(0.031125329773375), FRAC_CONST(0.002788610137442)}, + {FRAC_CONST(0.031116627956316), FRAC_CONST(0.002884088179689)}, {FRAC_CONST(0.031107633257703), FRAC_CONST(0.002979539075801)}, {FRAC_CONST(0.031098345762200), FRAC_CONST(0.003074961927355)}, + {FRAC_CONST(0.031088765557222), FRAC_CONST(0.003170355836197)}, {FRAC_CONST(0.031078892732942), FRAC_CONST(0.003265719904442)}, {FRAC_CONST(0.031068727382288), FRAC_CONST(0.003361053234488)}, + {FRAC_CONST(0.031058269600939), FRAC_CONST(0.003456354929021)}, {FRAC_CONST(0.031047519487329), FRAC_CONST(0.003551624091024)}, {FRAC_CONST(0.031036477142640), FRAC_CONST(0.003646859823790)}, + {FRAC_CONST(0.031025142670809), FRAC_CONST(0.003742061230921)}, {FRAC_CONST(0.031013516178519), FRAC_CONST(0.003837227416347)}, {FRAC_CONST(0.031001597775203), FRAC_CONST(0.003932357484328)}, + {FRAC_CONST(0.030989387573042), FRAC_CONST(0.004027450539462)}, {FRAC_CONST(0.030976885686963), FRAC_CONST(0.004122505686697)}, {FRAC_CONST(0.030964092234638), FRAC_CONST(0.004217522031340)}, + {FRAC_CONST(0.030951007336485), FRAC_CONST(0.004312498679058)}, {FRAC_CONST(0.030937631115663), FRAC_CONST(0.004407434735897)}, {FRAC_CONST(0.030923963698074), FRAC_CONST(0.004502329308281)}, + {FRAC_CONST(0.030910005212362), FRAC_CONST(0.004597181503027)}, {FRAC_CONST(0.030895755789908), FRAC_CONST(0.004691990427350)}, {FRAC_CONST(0.030881215564835), FRAC_CONST(0.004786755188872)}, + {FRAC_CONST(0.030866384674000), FRAC_CONST(0.004881474895632)}, {FRAC_CONST(0.030851263256996), FRAC_CONST(0.004976148656090)}, {FRAC_CONST(0.030835851456154), FRAC_CONST(0.005070775579142)}, + {FRAC_CONST(0.030820149416533), FRAC_CONST(0.005165354774124)}, {FRAC_CONST(0.030804157285929), FRAC_CONST(0.005259885350819)}, {FRAC_CONST(0.030787875214864), FRAC_CONST(0.005354366419469)}, + {FRAC_CONST(0.030771303356593), FRAC_CONST(0.005448797090784)}, {FRAC_CONST(0.030754441867095), FRAC_CONST(0.005543176475946)}, {FRAC_CONST(0.030737290905077), FRAC_CONST(0.005637503686619)}, + {FRAC_CONST(0.030719850631972), FRAC_CONST(0.005731777834961)}, {FRAC_CONST(0.030702121211932), FRAC_CONST(0.005825998033626)}, {FRAC_CONST(0.030684102811835), FRAC_CONST(0.005920163395780)}, + {FRAC_CONST(0.030665795601276), FRAC_CONST(0.006014273035101)}, {FRAC_CONST(0.030647199752570), FRAC_CONST(0.006108326065793)}, {FRAC_CONST(0.030628315440748), FRAC_CONST(0.006202321602594)}, + {FRAC_CONST(0.030609142843557), FRAC_CONST(0.006296258760782)}, {FRAC_CONST(0.030589682141455), FRAC_CONST(0.006390136656185)}, {FRAC_CONST(0.030569933517616), FRAC_CONST(0.006483954405188)}, + {FRAC_CONST(0.030549897157919), FRAC_CONST(0.006577711124743)}, {FRAC_CONST(0.030529573250956), FRAC_CONST(0.006671405932375)}, {FRAC_CONST(0.030508961988022), FRAC_CONST(0.006765037946194)}, + {FRAC_CONST(0.030488063563118), FRAC_CONST(0.006858606284900)}, {FRAC_CONST(0.030466878172949), FRAC_CONST(0.006952110067791)}, {FRAC_CONST(0.030445406016919), FRAC_CONST(0.007045548414774)}, + {FRAC_CONST(0.030423647297133), FRAC_CONST(0.007138920446372)}, {FRAC_CONST(0.030401602218392), FRAC_CONST(0.007232225283733)}, {FRAC_CONST(0.030379270988192), FRAC_CONST(0.007325462048634)}, + {FRAC_CONST(0.030356653816724), FRAC_CONST(0.007418629863497)}, {FRAC_CONST(0.030333750916869), FRAC_CONST(0.007511727851390)}, {FRAC_CONST(0.030310562504198), FRAC_CONST(0.007604755136040)}, + {FRAC_CONST(0.030287088796968), FRAC_CONST(0.007697710841838)}, {FRAC_CONST(0.030263330016124), FRAC_CONST(0.007790594093851)}, {FRAC_CONST(0.030239286385293), FRAC_CONST(0.007883404017824)}, + {FRAC_CONST(0.030214958130781), FRAC_CONST(0.007976139740197)}, {FRAC_CONST(0.030190345481576), FRAC_CONST(0.008068800388104)}, {FRAC_CONST(0.030165448669342), FRAC_CONST(0.008161385089390)}, + {FRAC_CONST(0.030140267928416), FRAC_CONST(0.008253892972610)}, {FRAC_CONST(0.030114803495809), FRAC_CONST(0.008346323167047)}, {FRAC_CONST(0.030089055611203), FRAC_CONST(0.008438674802711)}, + {FRAC_CONST(0.030063024516947), FRAC_CONST(0.008530947010354)}, {FRAC_CONST(0.030036710458054), FRAC_CONST(0.008623138921475)}, {FRAC_CONST(0.030010113682202), FRAC_CONST(0.008715249668328)}, + {FRAC_CONST(0.029983234439732), FRAC_CONST(0.008807278383932)}, {FRAC_CONST(0.029956072983640), FRAC_CONST(0.008899224202078)}, {FRAC_CONST(0.029928629569580), FRAC_CONST(0.008991086257336)}, + {FRAC_CONST(0.029900904455860), FRAC_CONST(0.009082863685067)}, {FRAC_CONST(0.029872897903441), FRAC_CONST(0.009174555621425)}, {FRAC_CONST(0.029844610175929), FRAC_CONST(0.009266161203371)}, + {FRAC_CONST(0.029816041539579), FRAC_CONST(0.009357679568679)}, {FRAC_CONST(0.029787192263292), FRAC_CONST(0.009449109855944)}, {FRAC_CONST(0.029758062618606), FRAC_CONST(0.009540451204587)}, + {FRAC_CONST(0.029728652879702), FRAC_CONST(0.009631702754871)}, {FRAC_CONST(0.029698963323395), FRAC_CONST(0.009722863647900)}, {FRAC_CONST(0.029668994229134), FRAC_CONST(0.009813933025633)}, + {FRAC_CONST(0.029638745879000), FRAC_CONST(0.009904910030891)}, {FRAC_CONST(0.029608218557702), FRAC_CONST(0.009995793807363)}, {FRAC_CONST(0.029577412552575), FRAC_CONST(0.010086583499618)}, + {FRAC_CONST(0.029546328153577), FRAC_CONST(0.010177278253107)}, {FRAC_CONST(0.029514965653285), FRAC_CONST(0.010267877214177)}, {FRAC_CONST(0.029483325346896), FRAC_CONST(0.010358379530076)}, + {FRAC_CONST(0.029451407532220), FRAC_CONST(0.010448784348962)}, {FRAC_CONST(0.029419212509679), FRAC_CONST(0.010539090819911)}, {FRAC_CONST(0.029386740582307), FRAC_CONST(0.010629298092923)}, + {FRAC_CONST(0.029353992055740), FRAC_CONST(0.010719405318933)}, {FRAC_CONST(0.029320967238220), FRAC_CONST(0.010809411649818)}, {FRAC_CONST(0.029287666440590), FRAC_CONST(0.010899316238403)}, + {FRAC_CONST(0.029254089976290), FRAC_CONST(0.010989118238474)}, {FRAC_CONST(0.029220238161353), FRAC_CONST(0.011078816804778)}, {FRAC_CONST(0.029186111314406), FRAC_CONST(0.011168411093039)}, + {FRAC_CONST(0.029151709756664), FRAC_CONST(0.011257900259961)}, {FRAC_CONST(0.029117033811927), FRAC_CONST(0.011347283463239)}, {FRAC_CONST(0.029082083806579), FRAC_CONST(0.011436559861563)}, + {FRAC_CONST(0.029046860069582), FRAC_CONST(0.011525728614630)}, {FRAC_CONST(0.029011362932476), FRAC_CONST(0.011614788883150)}, {FRAC_CONST(0.028975592729373), FRAC_CONST(0.011703739828853)}, + {FRAC_CONST(0.028939549796957), FRAC_CONST(0.011792580614500)}, {FRAC_CONST(0.028903234474475), FRAC_CONST(0.011881310403886)}, {FRAC_CONST(0.028866647103744), FRAC_CONST(0.011969928361855)}, + {FRAC_CONST(0.028829788029135), FRAC_CONST(0.012058433654299)}, {FRAC_CONST(0.028792657597583), FRAC_CONST(0.012146825448172)}, {FRAC_CONST(0.028755256158571), FRAC_CONST(0.012235102911499)}, + {FRAC_CONST(0.028717584064137), FRAC_CONST(0.012323265213377)}, {FRAC_CONST(0.028679641668864), FRAC_CONST(0.012411311523990)}, {FRAC_CONST(0.028641429329882), FRAC_CONST(0.012499241014612)}, + {FRAC_CONST(0.028602947406859), FRAC_CONST(0.012587052857618)}, {FRAC_CONST(0.028564196262001), FRAC_CONST(0.012674746226488)}, {FRAC_CONST(0.028525176260050), FRAC_CONST(0.012762320295819)}, + {FRAC_CONST(0.028485887768276), FRAC_CONST(0.012849774241331)}, {FRAC_CONST(0.028446331156478), FRAC_CONST(0.012937107239875)}, {FRAC_CONST(0.028406506796976), FRAC_CONST(0.013024318469437)}, + {FRAC_CONST(0.028366415064615), FRAC_CONST(0.013111407109155)}, {FRAC_CONST(0.028326056336751), FRAC_CONST(0.013198372339315)}, {FRAC_CONST(0.028285430993258), FRAC_CONST(0.013285213341368)}, + {FRAC_CONST(0.028244539416515), FRAC_CONST(0.013371929297933)}, {FRAC_CONST(0.028203381991411), FRAC_CONST(0.013458519392807)}, {FRAC_CONST(0.028161959105334), FRAC_CONST(0.013544982810971)}, + {FRAC_CONST(0.028120271148172), FRAC_CONST(0.013631318738598)}, {FRAC_CONST(0.028078318512309), FRAC_CONST(0.013717526363062)}, {FRAC_CONST(0.028036101592619), FRAC_CONST(0.013803604872943)}, + {FRAC_CONST(0.027993620786463), FRAC_CONST(0.013889553458039)}, {FRAC_CONST(0.027950876493687), FRAC_CONST(0.013975371309367)}, {FRAC_CONST(0.027907869116616), FRAC_CONST(0.014061057619178)}, + {FRAC_CONST(0.027864599060052), FRAC_CONST(0.014146611580959)}, {FRAC_CONST(0.027821066731270), FRAC_CONST(0.014232032389445)}, {FRAC_CONST(0.027777272540012), FRAC_CONST(0.014317319240622)}, + {FRAC_CONST(0.027733216898487), FRAC_CONST(0.014402471331737)}, {FRAC_CONST(0.027688900221361), FRAC_CONST(0.014487487861307)}, {FRAC_CONST(0.027644322925762), FRAC_CONST(0.014572368029123)}, + {FRAC_CONST(0.027599485431266), FRAC_CONST(0.014657111036262)}, {FRAC_CONST(0.027554388159903), FRAC_CONST(0.014741716085090)}, {FRAC_CONST(0.027509031536144), FRAC_CONST(0.014826182379271)}, + {FRAC_CONST(0.027463415986904), FRAC_CONST(0.014910509123778)}, {FRAC_CONST(0.027417541941533), FRAC_CONST(0.014994695524894)}, {FRAC_CONST(0.027371409831816), FRAC_CONST(0.015078740790225)}, + {FRAC_CONST(0.027325020091965), FRAC_CONST(0.015162644128704)}, {FRAC_CONST(0.027278373158618), FRAC_CONST(0.015246404750603)}, {FRAC_CONST(0.027231469470833), FRAC_CONST(0.015330021867534)}, + {FRAC_CONST(0.027184309470088), FRAC_CONST(0.015413494692460)}, {FRAC_CONST(0.027136893600268), FRAC_CONST(0.015496822439704)}, {FRAC_CONST(0.027089222307671), FRAC_CONST(0.015580004324954)}, + {FRAC_CONST(0.027041296040997), FRAC_CONST(0.015663039565269)}, {FRAC_CONST(0.026993115251345), FRAC_CONST(0.015745927379091)}, {FRAC_CONST(0.026944680392213), FRAC_CONST(0.015828666986247)}, + {FRAC_CONST(0.026895991919487), FRAC_CONST(0.015911257607961)}, {FRAC_CONST(0.026847050291442), FRAC_CONST(0.015993698466859)}, {FRAC_CONST(0.026797855968734), FRAC_CONST(0.016075988786976)}, + {FRAC_CONST(0.026748409414401), FRAC_CONST(0.016158127793763)}, {FRAC_CONST(0.026698711093851), FRAC_CONST(0.016240114714099)}, {FRAC_CONST(0.026648761474864), FRAC_CONST(0.016321948776289)}, + {FRAC_CONST(0.026598561027585), FRAC_CONST(0.016403629210082)}, {FRAC_CONST(0.026548110224519), FRAC_CONST(0.016485155246669)}, {FRAC_CONST(0.026497409540530), FRAC_CONST(0.016566526118696)}, + {FRAC_CONST(0.026446459452830), FRAC_CONST(0.016647741060271)}, {FRAC_CONST(0.026395260440982), FRAC_CONST(0.016728799306966)}, {FRAC_CONST(0.026343812986890), FRAC_CONST(0.016809700095831)}, + {FRAC_CONST(0.026292117574797), FRAC_CONST(0.016890442665397)}, {FRAC_CONST(0.026240174691280), FRAC_CONST(0.016971026255683)}, {FRAC_CONST(0.026187984825246), FRAC_CONST(0.017051450108208)}, + {FRAC_CONST(0.026135548467924), FRAC_CONST(0.017131713465990)}, {FRAC_CONST(0.026082866112867), FRAC_CONST(0.017211815573560)}, {FRAC_CONST(0.026029938255941), FRAC_CONST(0.017291755676967)}, + {FRAC_CONST(0.025976765395322), FRAC_CONST(0.017371533023784)}, {FRAC_CONST(0.025923348031494), FRAC_CONST(0.017451146863116)}, {FRAC_CONST(0.025869686667242), FRAC_CONST(0.017530596445607)}, + {FRAC_CONST(0.025815781807646), FRAC_CONST(0.017609881023449)}, {FRAC_CONST(0.025761633960080), FRAC_CONST(0.017688999850383)}, {FRAC_CONST(0.025707243634204), FRAC_CONST(0.017767952181715)}, + {FRAC_CONST(0.025652611341960), FRAC_CONST(0.017846737274313)}, {FRAC_CONST(0.025597737597568), FRAC_CONST(0.017925354386623)}, {FRAC_CONST(0.025542622917522), FRAC_CONST(0.018003802778671)}, + {FRAC_CONST(0.025487267820581), FRAC_CONST(0.018082081712071)}, {FRAC_CONST(0.025431672827768), FRAC_CONST(0.018160190450031)}, {FRAC_CONST(0.025375838462365), FRAC_CONST(0.018238128257362)}, + {FRAC_CONST(0.025319765249906), FRAC_CONST(0.018315894400484)}, {FRAC_CONST(0.025263453718173), FRAC_CONST(0.018393488147432)}, {FRAC_CONST(0.025206904397193), FRAC_CONST(0.018470908767865)}, + {FRAC_CONST(0.025150117819228), FRAC_CONST(0.018548155533070)}, {FRAC_CONST(0.025093094518776), FRAC_CONST(0.018625227715971)}, {FRAC_CONST(0.025035835032562), FRAC_CONST(0.018702124591135)}, + {FRAC_CONST(0.024978339899534), FRAC_CONST(0.018778845434780)}, {FRAC_CONST(0.024920609660858), FRAC_CONST(0.018855389524780)}, {FRAC_CONST(0.024862644859912), FRAC_CONST(0.018931756140672)}, + {FRAC_CONST(0.024804446042284), FRAC_CONST(0.019007944563666)}, {FRAC_CONST(0.024746013755764), FRAC_CONST(0.019083954076646)}, {FRAC_CONST(0.024687348550337), FRAC_CONST(0.019159783964183)}, + {FRAC_CONST(0.024628450978184), FRAC_CONST(0.019235433512536)}, {FRAC_CONST(0.024569321593670), FRAC_CONST(0.019310902009663)}, {FRAC_CONST(0.024509960953345), FRAC_CONST(0.019386188745225)}, + {FRAC_CONST(0.024450369615932), FRAC_CONST(0.019461293010596)}, {FRAC_CONST(0.024390548142329), FRAC_CONST(0.019536214098866)}, {FRAC_CONST(0.024330497095598), FRAC_CONST(0.019610951304848)}, + {FRAC_CONST(0.024270217040961), FRAC_CONST(0.019685503925087)}, {FRAC_CONST(0.024209708545799), FRAC_CONST(0.019759871257867)}, {FRAC_CONST(0.024148972179639), FRAC_CONST(0.019834052603212)}, + {FRAC_CONST(0.024088008514157), FRAC_CONST(0.019908047262901)}, {FRAC_CONST(0.024026818123164), FRAC_CONST(0.019981854540467)}, {FRAC_CONST(0.023965401582609), FRAC_CONST(0.020055473741208)}, + {FRAC_CONST(0.023903759470567), FRAC_CONST(0.020128904172192)}, {FRAC_CONST(0.023841892367236), FRAC_CONST(0.020202145142264)}, {FRAC_CONST(0.023779800854935), FRAC_CONST(0.020275195962052)}, + {FRAC_CONST(0.023717485518092), FRAC_CONST(0.020348055943974)}, {FRAC_CONST(0.023654946943242), FRAC_CONST(0.020420724402244)}, {FRAC_CONST(0.023592185719023), FRAC_CONST(0.020493200652878)}, + {FRAC_CONST(0.023529202436167), FRAC_CONST(0.020565484013703)}, {FRAC_CONST(0.023465997687496), FRAC_CONST(0.020637573804361)}, {FRAC_CONST(0.023402572067918), FRAC_CONST(0.020709469346314)}, + {FRAC_CONST(0.023338926174419), FRAC_CONST(0.020781169962854)}, {FRAC_CONST(0.023275060606058), FRAC_CONST(0.020852674979108)}, {FRAC_CONST(0.023210975963963), FRAC_CONST(0.020923983722044)}, + {FRAC_CONST(0.023146672851322), FRAC_CONST(0.020995095520475)}, {FRAC_CONST(0.023082151873380), FRAC_CONST(0.021066009705072)}, {FRAC_CONST(0.023017413637435), FRAC_CONST(0.021136725608363)}, + {FRAC_CONST(0.022952458752826), FRAC_CONST(0.021207242564742)}, {FRAC_CONST(0.022887287830934), FRAC_CONST(0.021277559910478)}, {FRAC_CONST(0.022821901485173), FRAC_CONST(0.021347676983716)}, + {FRAC_CONST(0.022756300330983), FRAC_CONST(0.021417593124488)}, {FRAC_CONST(0.022690484985827), FRAC_CONST(0.021487307674717)}, {FRAC_CONST(0.022624456069185), FRAC_CONST(0.021556819978223)}, + {FRAC_CONST(0.022558214202547), FRAC_CONST(0.021626129380729)}, {FRAC_CONST(0.022491760009405), FRAC_CONST(0.021695235229869)}, {FRAC_CONST(0.022425094115252), FRAC_CONST(0.021764136875192)}, + {FRAC_CONST(0.022358217147572), FRAC_CONST(0.021832833668171)}, {FRAC_CONST(0.022291129735838), FRAC_CONST(0.021901324962204)}, {FRAC_CONST(0.022223832511501), FRAC_CONST(0.021969610112625)}, + {FRAC_CONST(0.022156326107988), FRAC_CONST(0.022037688476709)}, {FRAC_CONST(0.022088611160696), FRAC_CONST(0.022105559413676)}, {FRAC_CONST(0.022020688306983), FRAC_CONST(0.022173222284699)}, + {FRAC_CONST(0.021952558186166), FRAC_CONST(0.022240676452909)}, {FRAC_CONST(0.021884221439510), FRAC_CONST(0.022307921283403)}, {FRAC_CONST(0.021815678710228), FRAC_CONST(0.022374956143245)}, + {FRAC_CONST(0.021746930643469), FRAC_CONST(0.022441780401478)}, {FRAC_CONST(0.021677977886316), FRAC_CONST(0.022508393429127)}, {FRAC_CONST(0.021608821087780), FRAC_CONST(0.022574794599206)}, + {FRAC_CONST(0.021539460898790), FRAC_CONST(0.022640983286719)}, {FRAC_CONST(0.021469897972190), FRAC_CONST(0.022706958868676)}, {FRAC_CONST(0.021400132962735), FRAC_CONST(0.022772720724087)}, + {FRAC_CONST(0.021330166527077), FRAC_CONST(0.022838268233979)}, {FRAC_CONST(0.021259999323769), FRAC_CONST(0.022903600781391)}, {FRAC_CONST(0.021189632013250), FRAC_CONST(0.022968717751391)}, + {FRAC_CONST(0.021119065257845), FRAC_CONST(0.023033618531071)}, {FRAC_CONST(0.021048299721754), FRAC_CONST(0.023098302509561)}, {FRAC_CONST(0.020977336071050), FRAC_CONST(0.023162769078031)}, + {FRAC_CONST(0.020906174973670), FRAC_CONST(0.023227017629698)}, {FRAC_CONST(0.020834817099409), FRAC_CONST(0.023291047559828)}, {FRAC_CONST(0.020763263119915), FRAC_CONST(0.023354858265748)}, + {FRAC_CONST(0.020691513708680), FRAC_CONST(0.023418449146848)}, {FRAC_CONST(0.020619569541038), FRAC_CONST(0.023481819604585)}, {FRAC_CONST(0.020547431294155), FRAC_CONST(0.023544969042494)}, + {FRAC_CONST(0.020475099647023), FRAC_CONST(0.023607896866186)}, {FRAC_CONST(0.020402575280455), FRAC_CONST(0.023670602483363)}, {FRAC_CONST(0.020329858877078), FRAC_CONST(0.023733085303813)}, + {FRAC_CONST(0.020256951121327), FRAC_CONST(0.023795344739427)}, {FRAC_CONST(0.020183852699437), FRAC_CONST(0.023857380204193)}, {FRAC_CONST(0.020110564299439), FRAC_CONST(0.023919191114211)}, + {FRAC_CONST(0.020037086611150), FRAC_CONST(0.023980776887692)}, {FRAC_CONST(0.019963420326171), FRAC_CONST(0.024042136944968)}, {FRAC_CONST(0.019889566137877), FRAC_CONST(0.024103270708495)}, + {FRAC_CONST(0.019815524741412), FRAC_CONST(0.024164177602859)}, {FRAC_CONST(0.019741296833681), FRAC_CONST(0.024224857054779)}, {FRAC_CONST(0.019666883113346), FRAC_CONST(0.024285308493120)}, + {FRAC_CONST(0.019592284280817), FRAC_CONST(0.024345531348888)}, {FRAC_CONST(0.019517501038246), FRAC_CONST(0.024405525055242)}, {FRAC_CONST(0.019442534089523), FRAC_CONST(0.024465289047500)}, + {FRAC_CONST(0.019367384140264), FRAC_CONST(0.024524822763141)}, {FRAC_CONST(0.019292051897809), FRAC_CONST(0.024584125641809)}, {FRAC_CONST(0.019216538071215), FRAC_CONST(0.024643197125323)}, + {FRAC_CONST(0.019140843371246), FRAC_CONST(0.024702036657681)}, {FRAC_CONST(0.019064968510369), FRAC_CONST(0.024760643685063)}, {FRAC_CONST(0.018988914202748), FRAC_CONST(0.024819017655836)}, + {FRAC_CONST(0.018912681164234), FRAC_CONST(0.024877158020562)}, {FRAC_CONST(0.018836270112363), FRAC_CONST(0.024935064232003)}, {FRAC_CONST(0.018759681766343), FRAC_CONST(0.024992735745123)}, + {FRAC_CONST(0.018682916847054), FRAC_CONST(0.025050172017095)}, {FRAC_CONST(0.018605976077037), FRAC_CONST(0.025107372507308)}, {FRAC_CONST(0.018528860180486), FRAC_CONST(0.025164336677369)}, + {FRAC_CONST(0.018451569883247), FRAC_CONST(0.025221063991110)}, {FRAC_CONST(0.018374105912805), FRAC_CONST(0.025277553914591)}, {FRAC_CONST(0.018296468998280), FRAC_CONST(0.025333805916107)}, + {FRAC_CONST(0.018218659870421), FRAC_CONST(0.025389819466194)}, {FRAC_CONST(0.018140679261596), FRAC_CONST(0.025445594037630)}, {FRAC_CONST(0.018062527905790), FRAC_CONST(0.025501129105445)}, + {FRAC_CONST(0.017984206538592), FRAC_CONST(0.025556424146920)}, {FRAC_CONST(0.017905715897192), FRAC_CONST(0.025611478641598)}, {FRAC_CONST(0.017827056720375), FRAC_CONST(0.025666292071285)}, + {FRAC_CONST(0.017748229748511), FRAC_CONST(0.025720863920056)}, {FRAC_CONST(0.017669235723550), FRAC_CONST(0.025775193674260)}, {FRAC_CONST(0.017590075389012), FRAC_CONST(0.025829280822525)}, + {FRAC_CONST(0.017510749489986), FRAC_CONST(0.025883124855762)}, {FRAC_CONST(0.017431258773116), FRAC_CONST(0.025936725267170)}, {FRAC_CONST(0.017351603986600), FRAC_CONST(0.025990081552242)}, + {FRAC_CONST(0.017271785880180), FRAC_CONST(0.026043193208768)}, {FRAC_CONST(0.017191805205132), FRAC_CONST(0.026096059736841)}, {FRAC_CONST(0.017111662714267), FRAC_CONST(0.026148680638861)}, + {FRAC_CONST(0.017031359161915), FRAC_CONST(0.026201055419541)}, {FRAC_CONST(0.016950895303924), FRAC_CONST(0.026253183585908)}, {FRAC_CONST(0.016870271897651), FRAC_CONST(0.026305064647313)}, + {FRAC_CONST(0.016789489701954), FRAC_CONST(0.026356698115431)}, {FRAC_CONST(0.016708549477186), FRAC_CONST(0.026408083504269)}, {FRAC_CONST(0.016627451985187), FRAC_CONST(0.026459220330167)}, + {FRAC_CONST(0.016546197989277), FRAC_CONST(0.026510108111806)}, {FRAC_CONST(0.016464788254250), FRAC_CONST(0.026560746370212)}, {FRAC_CONST(0.016383223546365), FRAC_CONST(0.026611134628757)}, + {FRAC_CONST(0.016301504633341), FRAC_CONST(0.026661272413168)}, {FRAC_CONST(0.016219632284346), FRAC_CONST(0.026711159251530)}, {FRAC_CONST(0.016137607269996), FRAC_CONST(0.026760794674288)}, + {FRAC_CONST(0.016055430362340), FRAC_CONST(0.026810178214254)}, {FRAC_CONST(0.015973102334858), FRAC_CONST(0.026859309406613)}, {FRAC_CONST(0.015890623962454), FRAC_CONST(0.026908187788922)}, + {FRAC_CONST(0.015807996021446), FRAC_CONST(0.026956812901119)}, {FRAC_CONST(0.015725219289558), FRAC_CONST(0.027005184285527)}, {FRAC_CONST(0.015642294545918), FRAC_CONST(0.027053301486856)}, + {FRAC_CONST(0.015559222571044), FRAC_CONST(0.027101164052208)}, {FRAC_CONST(0.015476004146842), FRAC_CONST(0.027148771531083)}, {FRAC_CONST(0.015392640056594), FRAC_CONST(0.027196123475380)}, + {FRAC_CONST(0.015309131084956), FRAC_CONST(0.027243219439406)}, {FRAC_CONST(0.015225478017946), FRAC_CONST(0.027290058979875)}, {FRAC_CONST(0.015141681642938), FRAC_CONST(0.027336641655915)}, + {FRAC_CONST(0.015057742748656), FRAC_CONST(0.027382967029073)}, {FRAC_CONST(0.014973662125164), FRAC_CONST(0.027429034663317)}, {FRAC_CONST(0.014889440563862), FRAC_CONST(0.027474844125040)}, + {FRAC_CONST(0.014805078857474), FRAC_CONST(0.027520394983066)}, {FRAC_CONST(0.014720577800046), FRAC_CONST(0.027565686808654)}, {FRAC_CONST(0.014635938186934), FRAC_CONST(0.027610719175499)}, + {FRAC_CONST(0.014551160814797), FRAC_CONST(0.027655491659740)}, {FRAC_CONST(0.014466246481592), FRAC_CONST(0.027700003839960)}, {FRAC_CONST(0.014381195986567), FRAC_CONST(0.027744255297195)}, + {FRAC_CONST(0.014296010130247), FRAC_CONST(0.027788245614933)}, {FRAC_CONST(0.014210689714436), FRAC_CONST(0.027831974379120)}, {FRAC_CONST(0.014125235542201), FRAC_CONST(0.027875441178165)}, + {FRAC_CONST(0.014039648417870), FRAC_CONST(0.027918645602941)}, {FRAC_CONST(0.013953929147020), FRAC_CONST(0.027961587246792)}, {FRAC_CONST(0.013868078536476), FRAC_CONST(0.028004265705534)}, + {FRAC_CONST(0.013782097394294), FRAC_CONST(0.028046680577462)}, {FRAC_CONST(0.013695986529763), FRAC_CONST(0.028088831463351)}, {FRAC_CONST(0.013609746753390), FRAC_CONST(0.028130717966461)}, + {FRAC_CONST(0.013523378876898), FRAC_CONST(0.028172339692540)}, {FRAC_CONST(0.013436883713214), FRAC_CONST(0.028213696249828)}, {FRAC_CONST(0.013350262076462), FRAC_CONST(0.028254787249062)}, + {FRAC_CONST(0.013263514781960), FRAC_CONST(0.028295612303478)}, {FRAC_CONST(0.013176642646205), FRAC_CONST(0.028336171028814)}, {FRAC_CONST(0.013089646486871), FRAC_CONST(0.028376463043317)}, + {FRAC_CONST(0.013002527122799), FRAC_CONST(0.028416487967743)}, {FRAC_CONST(0.012915285373990), FRAC_CONST(0.028456245425361)}, {FRAC_CONST(0.012827922061597), FRAC_CONST(0.028495735041960)}, + {FRAC_CONST(0.012740438007915), FRAC_CONST(0.028534956445849)}, {FRAC_CONST(0.012652834036379), FRAC_CONST(0.028573909267859)}, {FRAC_CONST(0.012565110971550), FRAC_CONST(0.028612593141354)}, + {FRAC_CONST(0.012477269639111), FRAC_CONST(0.028651007702224)}, {FRAC_CONST(0.012389310865858), FRAC_CONST(0.028689152588899)}, {FRAC_CONST(0.012301235479693), FRAC_CONST(0.028727027442343)}, + {FRAC_CONST(0.012213044309615), FRAC_CONST(0.028764631906065)}, {FRAC_CONST(0.012124738185712), FRAC_CONST(0.028801965626115)}, {FRAC_CONST(0.012036317939156), FRAC_CONST(0.028839028251097)}, + {FRAC_CONST(0.011947784402191), FRAC_CONST(0.028875819432161)}, {FRAC_CONST(0.011859138408130), FRAC_CONST(0.028912338823015)}, {FRAC_CONST(0.011770380791341), FRAC_CONST(0.028948586079925)}, + {FRAC_CONST(0.011681512387245), FRAC_CONST(0.028984560861718)}, {FRAC_CONST(0.011592534032306), FRAC_CONST(0.029020262829785)}, {FRAC_CONST(0.011503446564022), FRAC_CONST(0.029055691648087)}, + {FRAC_CONST(0.011414250820918), FRAC_CONST(0.029090846983152)}, {FRAC_CONST(0.011324947642537), FRAC_CONST(0.029125728504087)}, {FRAC_CONST(0.011235537869437), FRAC_CONST(0.029160335882573)}, + {FRAC_CONST(0.011146022343175), FRAC_CONST(0.029194668792871)}, {FRAC_CONST(0.011056401906305), FRAC_CONST(0.029228726911828)}, {FRAC_CONST(0.010966677402371), FRAC_CONST(0.029262509918876)}, + {FRAC_CONST(0.010876849675891), FRAC_CONST(0.029296017496036)}, {FRAC_CONST(0.010786919572361), FRAC_CONST(0.029329249327922)}, {FRAC_CONST(0.010696887938235), FRAC_CONST(0.029362205101743)}, + {FRAC_CONST(0.010606755620926), FRAC_CONST(0.029394884507308)}, {FRAC_CONST(0.010516523468793), FRAC_CONST(0.029427287237024)}, {FRAC_CONST(0.010426192331137), FRAC_CONST(0.029459412985906)}, + {FRAC_CONST(0.010335763058187), FRAC_CONST(0.029491261451573)}, {FRAC_CONST(0.010245236501099), FRAC_CONST(0.029522832334255)}, {FRAC_CONST(0.010154613511943), FRAC_CONST(0.029554125336796)}, + {FRAC_CONST(0.010063894943698), FRAC_CONST(0.029585140164654)}, {FRAC_CONST(0.009973081650240), FRAC_CONST(0.029615876525905)}, {FRAC_CONST(0.009882174486340), FRAC_CONST(0.029646334131247)}, + {FRAC_CONST(0.009791174307650), FRAC_CONST(0.029676512694001)}, {FRAC_CONST(0.009700081970699), FRAC_CONST(0.029706411930116)}, {FRAC_CONST(0.009608898332881), FRAC_CONST(0.029736031558168)}, + {FRAC_CONST(0.009517624252453), FRAC_CONST(0.029765371299366)}, {FRAC_CONST(0.009426260588521), FRAC_CONST(0.029794430877553)}, {FRAC_CONST(0.009334808201034), FRAC_CONST(0.029823210019210)}, + {FRAC_CONST(0.009243267950778), FRAC_CONST(0.029851708453456)}, {FRAC_CONST(0.009151640699363), FRAC_CONST(0.029879925912053)}, {FRAC_CONST(0.009059927309220), FRAC_CONST(0.029907862129408)}, + {FRAC_CONST(0.008968128643591), FRAC_CONST(0.029935516842573)}, {FRAC_CONST(0.008876245566520), FRAC_CONST(0.029962889791254)}, {FRAC_CONST(0.008784278942845), FRAC_CONST(0.029989980717805)}, + {FRAC_CONST(0.008692229638191), FRAC_CONST(0.030016789367235)}, {FRAC_CONST(0.008600098518961), FRAC_CONST(0.030043315487212)}, {FRAC_CONST(0.008507886452329), FRAC_CONST(0.030069558828062)}, + {FRAC_CONST(0.008415594306230), FRAC_CONST(0.030095519142772)}, {FRAC_CONST(0.008323222949351), FRAC_CONST(0.030121196186994)}, {FRAC_CONST(0.008230773251129), FRAC_CONST(0.030146589719046)}, + {FRAC_CONST(0.008138246081733), FRAC_CONST(0.030171699499915)}, {FRAC_CONST(0.008045642312067), FRAC_CONST(0.030196525293257)}, {FRAC_CONST(0.007952962813750), FRAC_CONST(0.030221066865402)}, + {FRAC_CONST(0.007860208459119), FRAC_CONST(0.030245323985357)}, {FRAC_CONST(0.007767380121212), FRAC_CONST(0.030269296424803)}, {FRAC_CONST(0.007674478673766), FRAC_CONST(0.030292983958103)}, + {FRAC_CONST(0.007581504991203), FRAC_CONST(0.030316386362302)}, {FRAC_CONST(0.007488459948628), FRAC_CONST(0.030339503417126)}, {FRAC_CONST(0.007395344421816), FRAC_CONST(0.030362334904989)}, + {FRAC_CONST(0.007302159287206), FRAC_CONST(0.030384880610993)}, {FRAC_CONST(0.007208905421891), FRAC_CONST(0.030407140322928)}, {FRAC_CONST(0.007115583703613), FRAC_CONST(0.030429113831278)}, + {FRAC_CONST(0.007022195010752), FRAC_CONST(0.030450800929220)}, {FRAC_CONST(0.006928740222316), FRAC_CONST(0.030472201412626)}, {FRAC_CONST(0.006835220217939), FRAC_CONST(0.030493315080068)}, + {FRAC_CONST(0.006741635877866), FRAC_CONST(0.030514141732814)}, {FRAC_CONST(0.006647988082948), FRAC_CONST(0.030534681174838)}, {FRAC_CONST(0.006554277714635), FRAC_CONST(0.030554933212813)}, + {FRAC_CONST(0.006460505654964), FRAC_CONST(0.030574897656119)}, {FRAC_CONST(0.006366672786553), FRAC_CONST(0.030594574316845)}, {FRAC_CONST(0.006272779992593), FRAC_CONST(0.030613963009786)}, + {FRAC_CONST(0.006178828156839), FRAC_CONST(0.030633063552447)}, {FRAC_CONST(0.006084818163601), FRAC_CONST(0.030651875765048)}, {FRAC_CONST(0.005990750897737), FRAC_CONST(0.030670399470520)}, + {FRAC_CONST(0.005896627244644), FRAC_CONST(0.030688634494512)}, {FRAC_CONST(0.005802448090250), FRAC_CONST(0.030706580665388)}, {FRAC_CONST(0.005708214321004), FRAC_CONST(0.030724237814232)}, + {FRAC_CONST(0.005613926823871), FRAC_CONST(0.030741605774849)}, {FRAC_CONST(0.005519586486321), FRAC_CONST(0.030758684383764)}, {FRAC_CONST(0.005425194196321), FRAC_CONST(0.030775473480228)}, + {FRAC_CONST(0.005330750842327), FRAC_CONST(0.030791972906214)}, {FRAC_CONST(0.005236257313276), FRAC_CONST(0.030808182506425)}, {FRAC_CONST(0.005141714498576), FRAC_CONST(0.030824102128288)}, + {FRAC_CONST(0.005047123288102), FRAC_CONST(0.030839731621963)}, {FRAC_CONST(0.004952484572181), FRAC_CONST(0.030855070840339)}, {FRAC_CONST(0.004857799241589), FRAC_CONST(0.030870119639036)}, + {FRAC_CONST(0.004763068187541), FRAC_CONST(0.030884877876411)}, {FRAC_CONST(0.004668292301681), FRAC_CONST(0.030899345413553)}, {FRAC_CONST(0.004573472476075), FRAC_CONST(0.030913522114288)}, + {FRAC_CONST(0.004478609603205), FRAC_CONST(0.030927407845180)}, {FRAC_CONST(0.004383704575956), FRAC_CONST(0.030941002475530)}, {FRAC_CONST(0.004288758287610), FRAC_CONST(0.030954305877381)}, + {FRAC_CONST(0.004193771631837), FRAC_CONST(0.030967317925516)}, {FRAC_CONST(0.004098745502689), FRAC_CONST(0.030980038497461)}, {FRAC_CONST(0.004003680794587), FRAC_CONST(0.030992467473486)}, + {FRAC_CONST(0.003908578402316), FRAC_CONST(0.031004604736602)}, {FRAC_CONST(0.003813439221017), FRAC_CONST(0.031016450172571)}, {FRAC_CONST(0.003718264146176), FRAC_CONST(0.031028003669899)}, + {FRAC_CONST(0.003623054073616), FRAC_CONST(0.031039265119839)}, {FRAC_CONST(0.003527809899492), FRAC_CONST(0.031050234416394)}, {FRAC_CONST(0.003432532520278), FRAC_CONST(0.031060911456318)}, + {FRAC_CONST(0.003337222832760), FRAC_CONST(0.031071296139114)}, {FRAC_CONST(0.003241881734029), FRAC_CONST(0.031081388367037)}, {FRAC_CONST(0.003146510121474), FRAC_CONST(0.031091188045095)}, + {FRAC_CONST(0.003051108892766), FRAC_CONST(0.031100695081051)}, {FRAC_CONST(0.002955678945860), FRAC_CONST(0.031109909385419)}, {FRAC_CONST(0.002860221178978), FRAC_CONST(0.031118830871473)}, + {FRAC_CONST(0.002764736490604), FRAC_CONST(0.031127459455239)}, {FRAC_CONST(0.002669225779478), FRAC_CONST(0.031135795055501)}, {FRAC_CONST(0.002573689944583), FRAC_CONST(0.031143837593803)}, + {FRAC_CONST(0.002478129885137), FRAC_CONST(0.031151586994444)}, {FRAC_CONST(0.002382546500589), FRAC_CONST(0.031159043184484)}, {FRAC_CONST(0.002286940690606), FRAC_CONST(0.031166206093743)}, + {FRAC_CONST(0.002191313355067), FRAC_CONST(0.031173075654800)}, {FRAC_CONST(0.002095665394051), FRAC_CONST(0.031179651802998)}, {FRAC_CONST(0.001999997707835), FRAC_CONST(0.031185934476438)}, + {FRAC_CONST(0.001904311196878), FRAC_CONST(0.031191923615985)}, {FRAC_CONST(0.001808606761820), FRAC_CONST(0.031197619165268)}, {FRAC_CONST(0.001712885303465), FRAC_CONST(0.031203021070678)}, + {FRAC_CONST(0.001617147722782), FRAC_CONST(0.031208129281370)}, {FRAC_CONST(0.001521394920889), FRAC_CONST(0.031212943749264)}, {FRAC_CONST(0.001425627799047), FRAC_CONST(0.031217464429043)}, + {FRAC_CONST(0.001329847258653), FRAC_CONST(0.031221691278159)}, {FRAC_CONST(0.001234054201231), FRAC_CONST(0.031225624256825)}, {FRAC_CONST(0.001138249528420), FRAC_CONST(0.031229263328024)}, + {FRAC_CONST(0.001042434141971), FRAC_CONST(0.031232608457502)}, {FRAC_CONST(0.000946608943736), FRAC_CONST(0.031235659613775)}, {FRAC_CONST(0.000850774835656), FRAC_CONST(0.031238416768124)}, + {FRAC_CONST(0.000754932719759), FRAC_CONST(0.031240879894597)}, {FRAC_CONST(0.000659083498149), FRAC_CONST(0.031243048970010)}, {FRAC_CONST(0.000563228072993), FRAC_CONST(0.031244923973948)}, + {FRAC_CONST(0.000467367346520), FRAC_CONST(0.031246504888762)}, {FRAC_CONST(0.000371502221008), FRAC_CONST(0.031247791699571)}, {FRAC_CONST(0.000275633598775), FRAC_CONST(0.031248784394264)}, + {FRAC_CONST(0.000179762382174), FRAC_CONST(0.031249482963498)}, {FRAC_CONST(0.000083889473581), FRAC_CONST(0.031249887400697)}}; +/* 64 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_256[] = { + {FRAC_CONST(0.088387931675923), FRAC_CONST(0.000271171628935)}, {FRAC_CONST(0.088354655998507), FRAC_CONST(0.002440238387037)}, {FRAC_CONST(0.088268158780110), FRAC_CONST(0.004607835236780)}, + {FRAC_CONST(0.088128492123423), FRAC_CONST(0.006772656498875)}, {FRAC_CONST(0.087935740158418), FRAC_CONST(0.008933398165942)}, {FRAC_CONST(0.087690018991670), FRAC_CONST(0.011088758687994)}, + {FRAC_CONST(0.087391476636423), FRAC_CONST(0.013237439756448)}, {FRAC_CONST(0.087040292923427), FRAC_CONST(0.015378147086172)}, {FRAC_CONST(0.086636679392621), FRAC_CONST(0.017509591195118)}, + {FRAC_CONST(0.086180879165703), FRAC_CONST(0.019630488181053)}, {FRAC_CONST(0.085673166799686), FRAC_CONST(0.021739560494940)}, {FRAC_CONST(0.085113848121515), FRAC_CONST(0.023835537710479)}, + {FRAC_CONST(0.084503260043847), FRAC_CONST(0.025917157289369)}, {FRAC_CONST(0.083841770362110), FRAC_CONST(0.027983165341813)}, {FRAC_CONST(0.083129777532952), FRAC_CONST(0.030032317381813)}, + {FRAC_CONST(0.082367710434230), FRAC_CONST(0.032063379076803)}, {FRAC_CONST(0.081556028106671), FRAC_CONST(0.034075126991164)}, {FRAC_CONST(0.080695219477356), FRAC_CONST(0.036066349323177)}, + {FRAC_CONST(0.079785803065216), FRAC_CONST(0.038035846634965)}, {FRAC_CONST(0.078828326668693), FRAC_CONST(0.039982432574992)}, {FRAC_CONST(0.077823367035766), FRAC_CONST(0.041904934592675)}, + {FRAC_CONST(0.076771529516540), FRAC_CONST(0.043802194644686)}, {FRAC_CONST(0.075673447698606), FRAC_CONST(0.045673069892513)}, {FRAC_CONST(0.074529783025390), FRAC_CONST(0.047516433390863)}, + {FRAC_CONST(0.073341224397728), FRAC_CONST(0.049331174766491)}, {FRAC_CONST(0.072108487758894), FRAC_CONST(0.051116200887052)}, {FRAC_CONST(0.070832315663343), FRAC_CONST(0.052870436519557)}, + {FRAC_CONST(0.069513476829429), FRAC_CONST(0.054592824978055)}, {FRAC_CONST(0.068152765676348), FRAC_CONST(0.056282328760143)}, {FRAC_CONST(0.066751001845620), FRAC_CONST(0.057937930171918)}, + {FRAC_CONST(0.065309029707361), FRAC_CONST(0.059558631940996)}, {FRAC_CONST(0.063827717851668), FRAC_CONST(0.061143457817234)}, {FRAC_CONST(0.062307958565413), FRAC_CONST(0.062691453160784)}, + {FRAC_CONST(0.060750667294763), FRAC_CONST(0.064201685517134)}, {FRAC_CONST(0.059156782093749), FRAC_CONST(0.065673245178784)}, {FRAC_CONST(0.057527263059216), FRAC_CONST(0.067105245733220)}, + {FRAC_CONST(0.055863091752499), FRAC_CONST(0.068496824596852)}, {FRAC_CONST(0.054165270608165), FRAC_CONST(0.069847143534609)}, {FRAC_CONST(0.052434822330188), FRAC_CONST(0.071155389164853)}, + {FRAC_CONST(0.050672789275903), FRAC_CONST(0.072420773449336)}, {FRAC_CONST(0.048880232828135), FRAC_CONST(0.073642534167879)}, {FRAC_CONST(0.047058232755862), FRAC_CONST(0.074819935377512)}, + {FRAC_CONST(0.045207886563797), FRAC_CONST(0.075952267855771)}, {FRAC_CONST(0.043330308831298), FRAC_CONST(0.077038849527912)}, {FRAC_CONST(0.041426630540984), FRAC_CONST(0.078079025877766)}, + {FRAC_CONST(0.039497998397473), FRAC_CONST(0.079072170341994)}, {FRAC_CONST(0.037545574136653), FRAC_CONST(0.080017684687506)}, {FRAC_CONST(0.035570533825892), FRAC_CONST(0.080914999371817)}, + {FRAC_CONST(0.033574067155622), FRAC_CONST(0.081763573886112)}, {FRAC_CONST(0.031557376722714), FRAC_CONST(0.082562897080836)}, {FRAC_CONST(0.029521677306074), FRAC_CONST(0.083312487473584)}, + {FRAC_CONST(0.027468195134911), FRAC_CONST(0.084011893539132)}, {FRAC_CONST(0.025398167150101), FRAC_CONST(0.084660693981419)}, {FRAC_CONST(0.023312840259098), FRAC_CONST(0.085258497987320)}, + {FRAC_CONST(0.021213470584847), FRAC_CONST(0.085804945462053)}, {FRAC_CONST(0.019101322709138), FRAC_CONST(0.086299707246093)}, {FRAC_CONST(0.016977668910873), FRAC_CONST(0.086742485313442)}, + {FRAC_CONST(0.014843788399692), FRAC_CONST(0.087133012951149)}, {FRAC_CONST(0.012700966545425), FRAC_CONST(0.087471054919968)}, {FRAC_CONST(0.010550494103830), FRAC_CONST(0.087756407596056)}, + {FRAC_CONST(0.008393666439096), FRAC_CONST(0.087988899093631)}, {FRAC_CONST(0.006231782743558), FRAC_CONST(0.088168389368510)}, {FRAC_CONST(0.004066145255116), FRAC_CONST(0.088294770302461)}, + {FRAC_CONST(0.001898058472816), FRAC_CONST(0.088367965768336)}}; + #ifdef LD_DEC +/* 128 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_1024[] = { + {FRAC_CONST(0.044194160825012), FRAC_CONST(0.000033896503468)}, {FRAC_CONST(0.044193120897389), FRAC_CONST(0.000305066138364)}, {FRAC_CONST(0.044190417123742), FRAC_CONST(0.000576224287693)}, + {FRAC_CONST(0.044186049605866), FRAC_CONST(0.000847360742503)}, {FRAC_CONST(0.044180018508197), FRAC_CONST(0.001118465294660)}, {FRAC_CONST(0.044172324057802), FRAC_CONST(0.001389527737231)}, + {FRAC_CONST(0.044162966544372), FRAC_CONST(0.001660537864867)}, {FRAC_CONST(0.044151946320213), FRAC_CONST(0.001931485474192)}, {FRAC_CONST(0.044139263800230), FRAC_CONST(0.002202360364180)}, + {FRAC_CONST(0.044124919461912), FRAC_CONST(0.002473152336546)}, {FRAC_CONST(0.044108913845316), FRAC_CONST(0.002743851196123)}, {FRAC_CONST(0.044091247553044), FRAC_CONST(0.003014446751254)}, + {FRAC_CONST(0.044071921250223), FRAC_CONST(0.003284928814169)}, {FRAC_CONST(0.044050935664476), FRAC_CONST(0.003555287201370)}, {FRAC_CONST(0.044028291585898), FRAC_CONST(0.003825511734018)}, + {FRAC_CONST(0.044003989867028), FRAC_CONST(0.004095592238311)}, {FRAC_CONST(0.043978031422810), FRAC_CONST(0.004365518545871)}, {FRAC_CONST(0.043950417230565), FRAC_CONST(0.004635280494126)}, + {FRAC_CONST(0.043921148329953), FRAC_CONST(0.004904867926689)}, {FRAC_CONST(0.043890225822930), FRAC_CONST(0.005174270693748)}, {FRAC_CONST(0.043857650873712), FRAC_CONST(0.005443478652439)}, + {FRAC_CONST(0.043823424708727), FRAC_CONST(0.005712481667236)}, {FRAC_CONST(0.043787548616571), FRAC_CONST(0.005981269610326)}, {FRAC_CONST(0.043750023947958), FRAC_CONST(0.006249832361997)}, + {FRAC_CONST(0.043710852115672), FRAC_CONST(0.006518159811011)}, {FRAC_CONST(0.043670034594508), FRAC_CONST(0.006786241854993)}, {FRAC_CONST(0.043627572921225), FRAC_CONST(0.007054068400804)}, + {FRAC_CONST(0.043583468694479), FRAC_CONST(0.007321629364927)}, {FRAC_CONST(0.043537723574771), FRAC_CONST(0.007588914673843)}, {FRAC_CONST(0.043490339284377), FRAC_CONST(0.007855914264410)}, + {FRAC_CONST(0.043441317607290), FRAC_CONST(0.008122618084246)}, {FRAC_CONST(0.043390660389149), FRAC_CONST(0.008389016092101)}, {FRAC_CONST(0.043338369537168), FRAC_CONST(0.008655098258243)}, + {FRAC_CONST(0.043284447020070), FRAC_CONST(0.008920854564826)}, {FRAC_CONST(0.043228894868005), FRAC_CONST(0.009186275006278)}, {FRAC_CONST(0.043171715172482), FRAC_CONST(0.009451349589667)}, + {FRAC_CONST(0.043112910086283), FRAC_CONST(0.009716068335087)}, {FRAC_CONST(0.043052481823387), FRAC_CONST(0.009980421276025)}, {FRAC_CONST(0.042990432658884), FRAC_CONST(0.010244398459743)}, + {FRAC_CONST(0.042926764928889), FRAC_CONST(0.010507989947649)}, {FRAC_CONST(0.042861481030457), FRAC_CONST(0.010771185815673)}, {FRAC_CONST(0.042794583421490), FRAC_CONST(0.011033976154639)}, + {FRAC_CONST(0.042726074620644), FRAC_CONST(0.011296351070639)}, {FRAC_CONST(0.042655957207238), FRAC_CONST(0.011558300685406)}, {FRAC_CONST(0.042584233821153), FRAC_CONST(0.011819815136685)}, + {FRAC_CONST(0.042510907162732), FRAC_CONST(0.012080884578604)}, {FRAC_CONST(0.042435979992684), FRAC_CONST(0.012341499182048)}, {FRAC_CONST(0.042359455131975), FRAC_CONST(0.012601649135022)}, + {FRAC_CONST(0.042281335461721), FRAC_CONST(0.012861324643029)}, {FRAC_CONST(0.042201623923085), FRAC_CONST(0.013120515929433)}, {FRAC_CONST(0.042120323517160), FRAC_CONST(0.013379213235827)}, + {FRAC_CONST(0.042037437304862), FRAC_CONST(0.013637406822406)}, {FRAC_CONST(0.041952968406809), FRAC_CONST(0.013895086968325)}, {FRAC_CONST(0.041866920003207), FRAC_CONST(0.014152243972073)}, + {FRAC_CONST(0.041779295333730), FRAC_CONST(0.014408868151835)}, {FRAC_CONST(0.041690097697398), FRAC_CONST(0.014664949845855)}, {FRAC_CONST(0.041599330452450), FRAC_CONST(0.014920479412801)}, + {FRAC_CONST(0.041506997016224), FRAC_CONST(0.015175447232131)}, {FRAC_CONST(0.041413100865019), FRAC_CONST(0.015429843704450)}, {FRAC_CONST(0.041317645533974), FRAC_CONST(0.015683659251874)}, + {FRAC_CONST(0.041220634616927), FRAC_CONST(0.015936884318392)}, {FRAC_CONST(0.041122071766285), FRAC_CONST(0.016189509370223)}, {FRAC_CONST(0.041021960692883), FRAC_CONST(0.016441524896177)}, + {FRAC_CONST(0.040920305165846), FRAC_CONST(0.016692921408010)}, {FRAC_CONST(0.040817109012449), FRAC_CONST(0.016943689440788)}, {FRAC_CONST(0.040712376117967), FRAC_CONST(0.017193819553235)}, + {FRAC_CONST(0.040606110425535), FRAC_CONST(0.017443302328094)}, {FRAC_CONST(0.040498315935996), FRAC_CONST(0.017692128372479)}, {FRAC_CONST(0.040388996707752), FRAC_CONST(0.017940288318230)}, + {FRAC_CONST(0.040278156856609), FRAC_CONST(0.018187772822267)}, {FRAC_CONST(0.040165800555627), FRAC_CONST(0.018434572566936)}, {FRAC_CONST(0.040051932034955), FRAC_CONST(0.018680678260367)}, + {FRAC_CONST(0.039936555581679), FRAC_CONST(0.018926080636820)}, {FRAC_CONST(0.039819675539659), FRAC_CONST(0.019170770457035)}, {FRAC_CONST(0.039701296309360), FRAC_CONST(0.019414738508577)}, + {FRAC_CONST(0.039581422347694), FRAC_CONST(0.019657975606187)}, {FRAC_CONST(0.039460058167849), FRAC_CONST(0.019900472592126)}, {FRAC_CONST(0.039337208339116), FRAC_CONST(0.020142220336521)}, + {FRAC_CONST(0.039212877486723), FRAC_CONST(0.020383209737704)}, {FRAC_CONST(0.039087070291656), FRAC_CONST(0.020623431722561)}, {FRAC_CONST(0.038959791490485), FRAC_CONST(0.020862877246870)}, + {FRAC_CONST(0.038831045875184), FRAC_CONST(0.021101537295642)}, {FRAC_CONST(0.038700838292953), FRAC_CONST(0.021339402883462)}, {FRAC_CONST(0.038569173646034), FRAC_CONST(0.021576465054824)}, + {FRAC_CONST(0.038436056891527), FRAC_CONST(0.021812714884472)}, {FRAC_CONST(0.038301493041202), FRAC_CONST(0.022048143477734)}, {FRAC_CONST(0.038165487161312), FRAC_CONST(0.022282741970855)}, + {FRAC_CONST(0.038028044372402), FRAC_CONST(0.022516501531335)}, {FRAC_CONST(0.037889169849115), FRAC_CONST(0.022749413358259)}, {FRAC_CONST(0.037748868819998), FRAC_CONST(0.022981468682628)}, + {FRAC_CONST(0.037607146567305), FRAC_CONST(0.023212658767690)}, {FRAC_CONST(0.037464008426800), FRAC_CONST(0.023442974909269)}, {FRAC_CONST(0.037319459787553), FRAC_CONST(0.023672408436094)}, + {FRAC_CONST(0.037173506091737), FRAC_CONST(0.023900950710120)}, {FRAC_CONST(0.037026152834428), FRAC_CONST(0.024128593126861)}, {FRAC_CONST(0.036877405563392), FRAC_CONST(0.024355327115708)}, + {FRAC_CONST(0.036727269878879), FRAC_CONST(0.024581144140255)}, {FRAC_CONST(0.036575751433414), FRAC_CONST(0.024806035698618)}, {FRAC_CONST(0.036422855931580), FRAC_CONST(0.025029993323758)}, + {FRAC_CONST(0.036268589129807), FRAC_CONST(0.025253008583796)}, {FRAC_CONST(0.036112956836151), FRAC_CONST(0.025475073082334)}, {FRAC_CONST(0.035955964910083), FRAC_CONST(0.025696178458769)}, + {FRAC_CONST(0.035797619262257), FRAC_CONST(0.025916316388609)}, {FRAC_CONST(0.035637925854300), FRAC_CONST(0.026135478583784)}, {FRAC_CONST(0.035476890698576), FRAC_CONST(0.026353656792963)}, + {FRAC_CONST(0.035314519857970), FRAC_CONST(0.026570842801858)}, {FRAC_CONST(0.035150819445650), FRAC_CONST(0.026787028433540)}, {FRAC_CONST(0.034985795624846), FRAC_CONST(0.027002205548742)}, + {FRAC_CONST(0.034819454608610), FRAC_CONST(0.027216366046166)}, {FRAC_CONST(0.034651802659589), FRAC_CONST(0.027429501862792)}, {FRAC_CONST(0.034482846089783), FRAC_CONST(0.027641604974175)}, + {FRAC_CONST(0.034312591260311), FRAC_CONST(0.027852667394755)}, {FRAC_CONST(0.034141044581172), FRAC_CONST(0.028062681178149)}, {FRAC_CONST(0.033968212511001), FRAC_CONST(0.028271638417458)}, + {FRAC_CONST(0.033794101556828), FRAC_CONST(0.028479531245560)}, {FRAC_CONST(0.033618718273831), FRAC_CONST(0.028686351835407)}, {FRAC_CONST(0.033442069265093), FRAC_CONST(0.028892092400321)}, + {FRAC_CONST(0.033264161181349), FRAC_CONST(0.029096745194286)}, {FRAC_CONST(0.033085000720737), FRAC_CONST(0.029300302512241)}, {FRAC_CONST(0.032904594628548), FRAC_CONST(0.029502756690366)}, + {FRAC_CONST(0.032722949696969), FRAC_CONST(0.029704100106376)}, {FRAC_CONST(0.032540072764829), FRAC_CONST(0.029904325179807)}, {FRAC_CONST(0.032355970717341), FRAC_CONST(0.030103424372297)}, + {FRAC_CONST(0.032170650485843), FRAC_CONST(0.030301390187873)}, {FRAC_CONST(0.031984119047537), FRAC_CONST(0.030498215173235)}, {FRAC_CONST(0.031796383425227), FRAC_CONST(0.030693891918034)}, + {FRAC_CONST(0.031607450687052), FRAC_CONST(0.030888413055150)}, {FRAC_CONST(0.031417327946223), FRAC_CONST(0.031081771260973)}, {FRAC_CONST(0.031226022360754), FRAC_CONST(0.031273959255676)}, + {FRAC_CONST(0.031033541133193), FRAC_CONST(0.031464969803488)}, {FRAC_CONST(0.030839891510348), FRAC_CONST(0.031654795712972)}, {FRAC_CONST(0.030645080783018), FRAC_CONST(0.031843429837288)}, + {FRAC_CONST(0.030449116285718), FRAC_CONST(0.032030865074469)}, {FRAC_CONST(0.030252005396399), FRAC_CONST(0.032217094367684)}, {FRAC_CONST(0.030053755536176), FRAC_CONST(0.032402110705505)}, + {FRAC_CONST(0.029854374169043), FRAC_CONST(0.032585907122172)}, {FRAC_CONST(0.029653868801596), FRAC_CONST(0.032768476697853)}, {FRAC_CONST(0.029452246982750), FRAC_CONST(0.032949812558907)}, + {FRAC_CONST(0.029249516303451), FRAC_CONST(0.033129907878142)}, {FRAC_CONST(0.029045684396395), FRAC_CONST(0.033308755875070)}, {FRAC_CONST(0.028840758935738), FRAC_CONST(0.033486349816166)}, + {FRAC_CONST(0.028634747636808), FRAC_CONST(0.033662683015118)}, {FRAC_CONST(0.028427658255815), FRAC_CONST(0.033837748833080)}, {FRAC_CONST(0.028219498589555), FRAC_CONST(0.034011540678924)}, + {FRAC_CONST(0.028010276475123), FRAC_CONST(0.034184052009485)}, {FRAC_CONST(0.027799999789613), FRAC_CONST(0.034355276329809)}, {FRAC_CONST(0.027588676449824), FRAC_CONST(0.034525207193396)}, + {FRAC_CONST(0.027376314411959), FRAC_CONST(0.034693838202447)}, {FRAC_CONST(0.027162921671330), FRAC_CONST(0.034861163008098)}, {FRAC_CONST(0.026948506262053), FRAC_CONST(0.035027175310665)}, + {FRAC_CONST(0.026733076256746), FRAC_CONST(0.035191868859880)}, {FRAC_CONST(0.026516639766228), FRAC_CONST(0.035355237455122)}, {FRAC_CONST(0.026299204939210), FRAC_CONST(0.035517274945657)}, + {FRAC_CONST(0.026080779961991), FRAC_CONST(0.035677975230865)}, {FRAC_CONST(0.025861373058146), FRAC_CONST(0.035837332260471)}, {FRAC_CONST(0.025640992488223), FRAC_CONST(0.035995340034772)}, + {FRAC_CONST(0.025419646549425), FRAC_CONST(0.036151992604866)}, {FRAC_CONST(0.025197343575302), FRAC_CONST(0.036307284072871)}, {FRAC_CONST(0.024974091935435), FRAC_CONST(0.036461208592152)}, + {FRAC_CONST(0.024749900035122), FRAC_CONST(0.036613760367538)}, {FRAC_CONST(0.024524776315061), FRAC_CONST(0.036764933655540)}, {FRAC_CONST(0.024298729251033), FRAC_CONST(0.036914722764569)}, + {FRAC_CONST(0.024071767353583), FRAC_CONST(0.037063122055150)}, {FRAC_CONST(0.023843899167697), FRAC_CONST(0.037210125940135)}, {FRAC_CONST(0.023615133272485), FRAC_CONST(0.037355728884908)}, + {FRAC_CONST(0.023385478280852), FRAC_CONST(0.037499925407603)}, {FRAC_CONST(0.023154942839179), FRAC_CONST(0.037642710079302)}, {FRAC_CONST(0.022923535626995), FRAC_CONST(0.037784077524241)}, + {FRAC_CONST(0.022691265356652), FRAC_CONST(0.037924022420018)}, {FRAC_CONST(0.022458140772993), FRAC_CONST(0.038062539497785)}, {FRAC_CONST(0.022224170653027), FRAC_CONST(0.038199623542453)}, + {FRAC_CONST(0.021989363805598), FRAC_CONST(0.038335269392885)}, {FRAC_CONST(0.021753729071049), FRAC_CONST(0.038469471942092)}, {FRAC_CONST(0.021517275320897), FRAC_CONST(0.038602226137423)}, + {FRAC_CONST(0.021280011457490), FRAC_CONST(0.038733526980758)}, {FRAC_CONST(0.021041946413679), FRAC_CONST(0.038863369528695)}, {FRAC_CONST(0.020803089152479), FRAC_CONST(0.038991748892734)}, + {FRAC_CONST(0.020563448666730), FRAC_CONST(0.039118660239466)}, {FRAC_CONST(0.020323033978761), FRAC_CONST(0.039244098790750)}, {FRAC_CONST(0.020081854140050), FRAC_CONST(0.039368059823895)}, + {FRAC_CONST(0.019839918230880), FRAC_CONST(0.039490538671839)}, {FRAC_CONST(0.019597235360003), FRAC_CONST(0.039611530723322)}, {FRAC_CONST(0.019353814664291), FRAC_CONST(0.039731031423061)}, + {FRAC_CONST(0.019109665308395), FRAC_CONST(0.039849036271924)}, {FRAC_CONST(0.018864796484402), FRAC_CONST(0.039965540827094)}, {FRAC_CONST(0.018619217411483), FRAC_CONST(0.040080540702240)}, + {FRAC_CONST(0.018372937335552), FRAC_CONST(0.040194031567683)}, {FRAC_CONST(0.018125965528915), FRAC_CONST(0.040306009150554)}, {FRAC_CONST(0.017878311289921), FRAC_CONST(0.040416469234963)}, + {FRAC_CONST(0.017629983942612), FRAC_CONST(0.040525407662148)}, {FRAC_CONST(0.017380992836371), FRAC_CONST(0.040632820330639)}, {FRAC_CONST(0.017131347345575), FRAC_CONST(0.040738703196411)}, + {FRAC_CONST(0.016881056869233), FRAC_CONST(0.040843052273033)}, {FRAC_CONST(0.016630130830641), FRAC_CONST(0.040945863631822)}, {FRAC_CONST(0.016378578677023), FRAC_CONST(0.041047133401988)}, + {FRAC_CONST(0.016126409879175), FRAC_CONST(0.041146857770781)}, {FRAC_CONST(0.015873633931110), FRAC_CONST(0.041245032983635)}, {FRAC_CONST(0.015620260349699), FRAC_CONST(0.041341655344309)}, + {FRAC_CONST(0.015366298674314), FRAC_CONST(0.041436721215026)}, {FRAC_CONST(0.015111758466470), FRAC_CONST(0.041530227016609)}, {FRAC_CONST(0.014856649309460), FRAC_CONST(0.041622169228618)}, + {FRAC_CONST(0.014600980808001), FRAC_CONST(0.041712544389481)}, {FRAC_CONST(0.014344762587867), FRAC_CONST(0.041801349096623)}, {FRAC_CONST(0.014088004295529), FRAC_CONST(0.041888580006598)}, + {FRAC_CONST(0.013830715597792), FRAC_CONST(0.041974233835211)}, {FRAC_CONST(0.013572906181430), FRAC_CONST(0.042058307357645)}, {FRAC_CONST(0.013314585752822), FRAC_CONST(0.042140797408577)}, + {FRAC_CONST(0.013055764037585), FRAC_CONST(0.042221700882306)}, {FRAC_CONST(0.012796450780212), FRAC_CONST(0.042301014732860)}, {FRAC_CONST(0.012536655743699), FRAC_CONST(0.042378735974118)}, + {FRAC_CONST(0.012276388709183), FRAC_CONST(0.042454861679919)}, {FRAC_CONST(0.012015659475571), FRAC_CONST(0.042529388984173)}, {FRAC_CONST(0.011754477859172), FRAC_CONST(0.042602315080970)}, + {FRAC_CONST(0.011492853693324), FRAC_CONST(0.042673637224683)}, {FRAC_CONST(0.011230796828031), FRAC_CONST(0.042743352730074)}, {FRAC_CONST(0.010968317129584), FRAC_CONST(0.042811458972393)}, + {FRAC_CONST(0.010705424480197), FRAC_CONST(0.042877953387479)}, {FRAC_CONST(0.010442128777629), FRAC_CONST(0.042942833471854)}, {FRAC_CONST(0.010178439934815), FRAC_CONST(0.043006096782821)}, + {FRAC_CONST(0.009914367879490), FRAC_CONST(0.043067740938551)}, {FRAC_CONST(0.009649922553818), FRAC_CONST(0.043127763618177)}, {FRAC_CONST(0.009385113914016), FRAC_CONST(0.043186162561878)}, + {FRAC_CONST(0.009119951929979), FRAC_CONST(0.043242935570968)}, {FRAC_CONST(0.008854446584907), FRAC_CONST(0.043298080507974)}, {FRAC_CONST(0.008588607874926), FRAC_CONST(0.043351595296722)}, + {FRAC_CONST(0.008322445808712), FRAC_CONST(0.043403477922409)}, {FRAC_CONST(0.008055970407118), FRAC_CONST(0.043453726431684)}, {FRAC_CONST(0.007789191702791), FRAC_CONST(0.043502338932719)}, + {FRAC_CONST(0.007522119739798), FRAC_CONST(0.043549313595281)}, {FRAC_CONST(0.007254764573250), FRAC_CONST(0.043594648650800)}, {FRAC_CONST(0.006987136268915), FRAC_CONST(0.043638342392438)}, + {FRAC_CONST(0.006719244902849), FRAC_CONST(0.043680393175148)}, {FRAC_CONST(0.006451100561010), FRAC_CONST(0.043720799415744)}, {FRAC_CONST(0.006182713338881), FRAC_CONST(0.043759559592953)}, + {FRAC_CONST(0.005914093341090), FRAC_CONST(0.043796672247476)}, {FRAC_CONST(0.005645250681027), FRAC_CONST(0.043832135982044)}, {FRAC_CONST(0.005376195480466), FRAC_CONST(0.043865949461465)}, + {FRAC_CONST(0.005106937869184), FRAC_CONST(0.043898111412683)}, {FRAC_CONST(0.004837487984578), FRAC_CONST(0.043928620624817)}, {FRAC_CONST(0.004567855971284), FRAC_CONST(0.043957475949213)}, + {FRAC_CONST(0.004298051980793), FRAC_CONST(0.043984676299484)}, {FRAC_CONST(0.004028086171076), FRAC_CONST(0.044010220651553)}, {FRAC_CONST(0.003757968706190), FRAC_CONST(0.044034108043689)}, + {FRAC_CONST(0.003487709755907), FRAC_CONST(0.044056337576546)}, {FRAC_CONST(0.003217319495322), FRAC_CONST(0.044076908413193)}, {FRAC_CONST(0.002946808104477), FRAC_CONST(0.044095819779151)}, + {FRAC_CONST(0.002676185767973), FRAC_CONST(0.044113070962418)}, {FRAC_CONST(0.002405462674586), FRAC_CONST(0.044128661313495)}, {FRAC_CONST(0.002134649016890), FRAC_CONST(0.044142590245416)}, + {FRAC_CONST(0.001863754990865), FRAC_CONST(0.044154857233763)}, {FRAC_CONST(0.001592790795518), FRAC_CONST(0.044165461816692)}, {FRAC_CONST(0.001321766632497), FRAC_CONST(0.044174403594946)}, + {FRAC_CONST(0.001050692705710), FRAC_CONST(0.044181682231873)}, {FRAC_CONST(0.000779579220936), FRAC_CONST(0.044187297453434)}, {FRAC_CONST(0.000508436385446), FRAC_CONST(0.044191249048222)}, + {FRAC_CONST(0.000237274407613), FRAC_CONST(0.044193536867459)}}; + #endif // LD_DEC + #ifdef ALLOW_SMALL_FRAMELENGTH +/* 480 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_1920[] = { + {FRAC_CONST(0.032274858518097), FRAC_CONST(0.000013202404176)}, {FRAC_CONST(0.032274642494505), FRAC_CONST(0.000118821372483)}, {FRAC_CONST(0.032274080835421), FRAC_CONST(0.000224439068308)}, + {FRAC_CONST(0.032273173546860), FRAC_CONST(0.000330054360572)}, {FRAC_CONST(0.032271920638538), FRAC_CONST(0.000435666118218)}, {FRAC_CONST(0.032270322123873), FRAC_CONST(0.000541273210231)}, + {FRAC_CONST(0.032268378019984), FRAC_CONST(0.000646874505642)}, {FRAC_CONST(0.032266088347691), FRAC_CONST(0.000752468873546)}, {FRAC_CONST(0.032263453131514), FRAC_CONST(0.000858055183114)}, + {FRAC_CONST(0.032260472399674), FRAC_CONST(0.000963632303600)}, {FRAC_CONST(0.032257146184092), FRAC_CONST(0.001069199104358)}, {FRAC_CONST(0.032253474520390), FRAC_CONST(0.001174754454853)}, + {FRAC_CONST(0.032249457447888), FRAC_CONST(0.001280297224671)}, {FRAC_CONST(0.032245095009606), FRAC_CONST(0.001385826283535)}, {FRAC_CONST(0.032240387252262), FRAC_CONST(0.001491340501313)}, + {FRAC_CONST(0.032235334226272), FRAC_CONST(0.001596838748031)}, {FRAC_CONST(0.032229935985750), FRAC_CONST(0.001702319893890)}, {FRAC_CONST(0.032224192588507), FRAC_CONST(0.001807782809271)}, + {FRAC_CONST(0.032218104096050), FRAC_CONST(0.001913226364749)}, {FRAC_CONST(0.032211670573582), FRAC_CONST(0.002018649431111)}, {FRAC_CONST(0.032204892090000), FRAC_CONST(0.002124050879359)}, + {FRAC_CONST(0.032197768717898), FRAC_CONST(0.002229429580728)}, {FRAC_CONST(0.032190300533560), FRAC_CONST(0.002334784406698)}, {FRAC_CONST(0.032182487616965), FRAC_CONST(0.002440114229003)}, + {FRAC_CONST(0.032174330051782), FRAC_CONST(0.002545417919644)}, {FRAC_CONST(0.032165827925374), FRAC_CONST(0.002650694350905)}, {FRAC_CONST(0.032156981328790), FRAC_CONST(0.002755942395358)}, + {FRAC_CONST(0.032147790356771), FRAC_CONST(0.002861160925883)}, {FRAC_CONST(0.032138255107744), FRAC_CONST(0.002966348815672)}, {FRAC_CONST(0.032128375683825), FRAC_CONST(0.003071504938250)}, + {FRAC_CONST(0.032118152190814), FRAC_CONST(0.003176628167476)}, {FRAC_CONST(0.032107584738196), FRAC_CONST(0.003281717377568)}, {FRAC_CONST(0.032096673439141), FRAC_CONST(0.003386771443102)}, + {FRAC_CONST(0.032085418410500), FRAC_CONST(0.003491789239036)}, {FRAC_CONST(0.032073819772804), FRAC_CONST(0.003596769640711)}, {FRAC_CONST(0.032061877650267), FRAC_CONST(0.003701711523874)}, + {FRAC_CONST(0.032049592170778), FRAC_CONST(0.003806613764680)}, {FRAC_CONST(0.032036963465906), FRAC_CONST(0.003911475239711)}, {FRAC_CONST(0.032023991670893), FRAC_CONST(0.004016294825985)}, + {FRAC_CONST(0.032010676924657), FRAC_CONST(0.004121071400967)}, {FRAC_CONST(0.031997019369789), FRAC_CONST(0.004225803842586)}, {FRAC_CONST(0.031983019152549), FRAC_CONST(0.004330491029241)}, + {FRAC_CONST(0.031968676422869), FRAC_CONST(0.004435131839816)}, {FRAC_CONST(0.031953991334348), FRAC_CONST(0.004539725153692)}, {FRAC_CONST(0.031938964044252), FRAC_CONST(0.004644269850758)}, + {FRAC_CONST(0.031923594713510), FRAC_CONST(0.004748764811426)}, {FRAC_CONST(0.031907883506716), FRAC_CONST(0.004853208916638)}, {FRAC_CONST(0.031891830592124), FRAC_CONST(0.004957601047881)}, + {FRAC_CONST(0.031875436141648), FRAC_CONST(0.005061940087200)}, {FRAC_CONST(0.031858700330859), FRAC_CONST(0.005166224917208)}, {FRAC_CONST(0.031841623338985), FRAC_CONST(0.005270454421097)}, + {FRAC_CONST(0.031824205348907), FRAC_CONST(0.005374627482653)}, {FRAC_CONST(0.031806446547156), FRAC_CONST(0.005478742986267)}, {FRAC_CONST(0.031788347123916), FRAC_CONST(0.005582799816945)}, + {FRAC_CONST(0.031769907273017), FRAC_CONST(0.005686796860323)}, {FRAC_CONST(0.031751127191935), FRAC_CONST(0.005790733002674)}, {FRAC_CONST(0.031732007081789), FRAC_CONST(0.005894607130928)}, + {FRAC_CONST(0.031712547147340), FRAC_CONST(0.005998418132675)}, {FRAC_CONST(0.031692747596989), FRAC_CONST(0.006102164896182)}, {FRAC_CONST(0.031672608642773), FRAC_CONST(0.006205846310406)}, + {FRAC_CONST(0.031652130500364), FRAC_CONST(0.006309461265002)}, {FRAC_CONST(0.031631313389067), FRAC_CONST(0.006413008650337)}, {FRAC_CONST(0.031610157531816), FRAC_CONST(0.006516487357501)}, + {FRAC_CONST(0.031588663155172), FRAC_CONST(0.006619896278321)}, {FRAC_CONST(0.031566830489325), FRAC_CONST(0.006723234305370)}, {FRAC_CONST(0.031544659768083), FRAC_CONST(0.006826500331981)}, + {FRAC_CONST(0.031522151228878), FRAC_CONST(0.006929693252258)}, {FRAC_CONST(0.031499305112758), FRAC_CONST(0.007032811961088)}, {FRAC_CONST(0.031476121664387), FRAC_CONST(0.007135855354151)}, + {FRAC_CONST(0.031452601132040), FRAC_CONST(0.007238822327937)}, {FRAC_CONST(0.031428743767604), FRAC_CONST(0.007341711779751)}, {FRAC_CONST(0.031404549826572), FRAC_CONST(0.007444522607730)}, + {FRAC_CONST(0.031380019568042), FRAC_CONST(0.007547253710853)}, {FRAC_CONST(0.031355153254712), FRAC_CONST(0.007649903988952)}, {FRAC_CONST(0.031329951152882), FRAC_CONST(0.007752472342725)}, + {FRAC_CONST(0.031304413532445), FRAC_CONST(0.007854957673748)}, {FRAC_CONST(0.031278540666888), FRAC_CONST(0.007957358884484)}, {FRAC_CONST(0.031252332833290), FRAC_CONST(0.008059674878300)}, + {FRAC_CONST(0.031225790312316), FRAC_CONST(0.008161904559473)}, {FRAC_CONST(0.031198913388214), FRAC_CONST(0.008264046833205)}, {FRAC_CONST(0.031171702348814), FRAC_CONST(0.008366100605636)}, + {FRAC_CONST(0.031144157485525), FRAC_CONST(0.008468064783849)}, {FRAC_CONST(0.031116279093331), FRAC_CONST(0.008569938275893)}, {FRAC_CONST(0.031088067470786), FRAC_CONST(0.008671719990782)}, + {FRAC_CONST(0.031059522920014), FRAC_CONST(0.008773408838517)}, {FRAC_CONST(0.031030645746705), FRAC_CONST(0.008875003730092)}, {FRAC_CONST(0.031001436260110), FRAC_CONST(0.008976503577507)}, + {FRAC_CONST(0.030971894773039), FRAC_CONST(0.009077907293780)}, {FRAC_CONST(0.030942021601857), FRAC_CONST(0.009179213792959)}, {FRAC_CONST(0.030911817066483), FRAC_CONST(0.009280421990133)}, + {FRAC_CONST(0.030881281490382), FRAC_CONST(0.009381530801444)}, {FRAC_CONST(0.030850415200566), FRAC_CONST(0.009482539144097)}, {FRAC_CONST(0.030819218527589), FRAC_CONST(0.009583445936373)}, + {FRAC_CONST(0.030787691805541), FRAC_CONST(0.009684250097643)}, {FRAC_CONST(0.030755835372048), FRAC_CONST(0.009784950548375)}, {FRAC_CONST(0.030723649568268), FRAC_CONST(0.009885546210147)}, + {FRAC_CONST(0.030691134738883), FRAC_CONST(0.009986036005661)}, {FRAC_CONST(0.030658291232103), FRAC_CONST(0.010086418858753)}, {FRAC_CONST(0.030625119399655), FRAC_CONST(0.010186693694402)}, + {FRAC_CONST(0.030591619596781), FRAC_CONST(0.010286859438745)}, {FRAC_CONST(0.030557792182239), FRAC_CONST(0.010386915019088)}, {FRAC_CONST(0.030523637518292), FRAC_CONST(0.010486859363916)}, + {FRAC_CONST(0.030489155970710), FRAC_CONST(0.010586691402906)}, {FRAC_CONST(0.030454347908763), FRAC_CONST(0.010686410066936)}, {FRAC_CONST(0.030419213705216), FRAC_CONST(0.010786014288099)}, + {FRAC_CONST(0.030383753736329), FRAC_CONST(0.010885502999714)}, {FRAC_CONST(0.030347968381849), FRAC_CONST(0.010984875136338)}, {FRAC_CONST(0.030311858025010), FRAC_CONST(0.011084129633775)}, + {FRAC_CONST(0.030275423052523), FRAC_CONST(0.011183265429088)}, {FRAC_CONST(0.030238663854579), FRAC_CONST(0.011282281460612)}, {FRAC_CONST(0.030201580824838), FRAC_CONST(0.011381176667967)}, + {FRAC_CONST(0.030164174360430), FRAC_CONST(0.011479949992062)}, {FRAC_CONST(0.030126444861948), FRAC_CONST(0.011578600375117)}, {FRAC_CONST(0.030088392733446), FRAC_CONST(0.011677126760663)}, + {FRAC_CONST(0.030050018382430), FRAC_CONST(0.011775528093563)}, {FRAC_CONST(0.030011322219859), FRAC_CONST(0.011873803320018)}, {FRAC_CONST(0.029972304660138), FRAC_CONST(0.011971951387578)}, + {FRAC_CONST(0.029932966121114), FRAC_CONST(0.012069971245157)}, {FRAC_CONST(0.029893307024070), FRAC_CONST(0.012167861843041)}, {FRAC_CONST(0.029853327793724), FRAC_CONST(0.012265622132901)}, + {FRAC_CONST(0.029813028858222), FRAC_CONST(0.012363251067801)}, {FRAC_CONST(0.029772410649132), FRAC_CONST(0.012460747602215)}, {FRAC_CONST(0.029731473601443), FRAC_CONST(0.012558110692033)}, + {FRAC_CONST(0.029690218153558), FRAC_CONST(0.012655339294575)}, {FRAC_CONST(0.029648644747289), FRAC_CONST(0.012752432368600)}, {FRAC_CONST(0.029606753827855), FRAC_CONST(0.012849388874320)}, + {FRAC_CONST(0.029564545843872), FRAC_CONST(0.012946207773407)}, {FRAC_CONST(0.029522021247356), FRAC_CONST(0.013042888029011)}, {FRAC_CONST(0.029479180493710), FRAC_CONST(0.013139428605762)}, + {FRAC_CONST(0.029436024041725), FRAC_CONST(0.013235828469789)}, {FRAC_CONST(0.029392552353570), FRAC_CONST(0.013332086588727)}, {FRAC_CONST(0.029348765894794), FRAC_CONST(0.013428201931728)}, + {FRAC_CONST(0.029304665134313), FRAC_CONST(0.013524173469475)}, {FRAC_CONST(0.029260250544412), FRAC_CONST(0.013620000174189)}, {FRAC_CONST(0.029215522600735), FRAC_CONST(0.013715681019643)}, + {FRAC_CONST(0.029170481782283), FRAC_CONST(0.013811214981173)}, {FRAC_CONST(0.029125128571406), FRAC_CONST(0.013906601035686)}, {FRAC_CONST(0.029079463453801), FRAC_CONST(0.014001838161674)}, + {FRAC_CONST(0.029033486918505), FRAC_CONST(0.014096925339225)}, {FRAC_CONST(0.028987199457889), FRAC_CONST(0.014191861550031)}, {FRAC_CONST(0.028940601567655), FRAC_CONST(0.014286645777401)}, + {FRAC_CONST(0.028893693746829), FRAC_CONST(0.014381277006273)}, {FRAC_CONST(0.028846476497755), FRAC_CONST(0.014475754223221)}, {FRAC_CONST(0.028798950326094), FRAC_CONST(0.014570076416472)}, + {FRAC_CONST(0.028751115740811), FRAC_CONST(0.014664242575910)}, {FRAC_CONST(0.028702973254178), FRAC_CONST(0.014758251693091)}, {FRAC_CONST(0.028654523381760), FRAC_CONST(0.014852102761253)}, + {FRAC_CONST(0.028605766642418), FRAC_CONST(0.014945794775326)}, {FRAC_CONST(0.028556703558297), FRAC_CONST(0.015039326731945)}, {FRAC_CONST(0.028507334654823), FRAC_CONST(0.015132697629457)}, + {FRAC_CONST(0.028457660460698), FRAC_CONST(0.015225906467935)}, {FRAC_CONST(0.028407681507891), FRAC_CONST(0.015318952249187)}, {FRAC_CONST(0.028357398331639), FRAC_CONST(0.015411833976768)}, + {FRAC_CONST(0.028306811470432), FRAC_CONST(0.015504550655988)}, {FRAC_CONST(0.028255921466016), FRAC_CONST(0.015597101293927)}, {FRAC_CONST(0.028204728863381), FRAC_CONST(0.015689484899442)}, + {FRAC_CONST(0.028153234210760), FRAC_CONST(0.015781700483179)}, {FRAC_CONST(0.028101438059619), FRAC_CONST(0.015873747057582)}, {FRAC_CONST(0.028049340964652), FRAC_CONST(0.015965623636907)}, + {FRAC_CONST(0.027996943483779), FRAC_CONST(0.016057329237229)}, {FRAC_CONST(0.027944246178133), FRAC_CONST(0.016148862876456)}, {FRAC_CONST(0.027891249612061), FRAC_CONST(0.016240223574335)}, + {FRAC_CONST(0.027837954353113), FRAC_CONST(0.016331410352467)}, {FRAC_CONST(0.027784360972039), FRAC_CONST(0.016422422234315)}, {FRAC_CONST(0.027730470042780), FRAC_CONST(0.016513258245214)}, + {FRAC_CONST(0.027676282142466), FRAC_CONST(0.016603917412384)}, {FRAC_CONST(0.027621797851405), FRAC_CONST(0.016694398764938)}, {FRAC_CONST(0.027567017753080), FRAC_CONST(0.016784701333894)}, + {FRAC_CONST(0.027511942434143), FRAC_CONST(0.016874824152183)}, {FRAC_CONST(0.027456572484404), FRAC_CONST(0.016964766254662)}, {FRAC_CONST(0.027400908496833), FRAC_CONST(0.017054526678124)}, + {FRAC_CONST(0.027344951067546), FRAC_CONST(0.017144104461307)}, {FRAC_CONST(0.027288700795801), FRAC_CONST(0.017233498644904)}, {FRAC_CONST(0.027232158283994), FRAC_CONST(0.017322708271577)}, + {FRAC_CONST(0.027175324137651), FRAC_CONST(0.017411732385960)}, {FRAC_CONST(0.027118198965418), FRAC_CONST(0.017500570034678)}, {FRAC_CONST(0.027060783379060), FRAC_CONST(0.017589220266351)}, + {FRAC_CONST(0.027003077993454), FRAC_CONST(0.017677682131607)}, {FRAC_CONST(0.026945083426576), FRAC_CONST(0.017765954683088)}, {FRAC_CONST(0.026886800299502), FRAC_CONST(0.017854036975468)}, + {FRAC_CONST(0.026828229236397), FRAC_CONST(0.017941928065456)}, {FRAC_CONST(0.026769370864511), FRAC_CONST(0.018029627011808)}, {FRAC_CONST(0.026710225814170), FRAC_CONST(0.018117132875340)}, + {FRAC_CONST(0.026650794718768), FRAC_CONST(0.018204444718934)}, {FRAC_CONST(0.026591078214767), FRAC_CONST(0.018291561607551)}, {FRAC_CONST(0.026531076941680), FRAC_CONST(0.018378482608238)}, + {FRAC_CONST(0.026470791542075), FRAC_CONST(0.018465206790142)}, {FRAC_CONST(0.026410222661558), FRAC_CONST(0.018551733224515)}, {FRAC_CONST(0.026349370948775), FRAC_CONST(0.018638060984730)}, + {FRAC_CONST(0.026288237055398), FRAC_CONST(0.018724189146286)}, {FRAC_CONST(0.026226821636121), FRAC_CONST(0.018810116786819)}, {FRAC_CONST(0.026165125348656), FRAC_CONST(0.018895842986112)}, + {FRAC_CONST(0.026103148853718), FRAC_CONST(0.018981366826109)}, {FRAC_CONST(0.026040892815028), FRAC_CONST(0.019066687390916)}, {FRAC_CONST(0.025978357899296), FRAC_CONST(0.019151803766819)}, + {FRAC_CONST(0.025915544776223), FRAC_CONST(0.019236715042290)}, {FRAC_CONST(0.025852454118485), FRAC_CONST(0.019321420307998)}, {FRAC_CONST(0.025789086601733), FRAC_CONST(0.019405918656817)}, + {FRAC_CONST(0.025725442904582), FRAC_CONST(0.019490209183837)}, {FRAC_CONST(0.025661523708606), FRAC_CONST(0.019574290986376)}, {FRAC_CONST(0.025597329698327), FRAC_CONST(0.019658163163984)}, + {FRAC_CONST(0.025532861561211), FRAC_CONST(0.019741824818458)}, {FRAC_CONST(0.025468119987662), FRAC_CONST(0.019825275053848)}, {FRAC_CONST(0.025403105671008), FRAC_CONST(0.019908512976470)}, + {FRAC_CONST(0.025337819307501), FRAC_CONST(0.019991537694913)}, {FRAC_CONST(0.025272261596305), FRAC_CONST(0.020074348320047)}, {FRAC_CONST(0.025206433239491), FRAC_CONST(0.020156943965039)}, + {FRAC_CONST(0.025140334942028), FRAC_CONST(0.020239323745355)}, {FRAC_CONST(0.025073967411776), FRAC_CONST(0.020321486778774)}, {FRAC_CONST(0.025007331359476), FRAC_CONST(0.020403432185395)}, + {FRAC_CONST(0.024940427498748), FRAC_CONST(0.020485159087650)}, {FRAC_CONST(0.024873256546079), FRAC_CONST(0.020566666610309)}, {FRAC_CONST(0.024805819220816), FRAC_CONST(0.020647953880491)}, + {FRAC_CONST(0.024738116245157), FRAC_CONST(0.020729020027676)}, {FRAC_CONST(0.024670148344147), FRAC_CONST(0.020809864183709)}, {FRAC_CONST(0.024601916245669), FRAC_CONST(0.020890485482816)}, + {FRAC_CONST(0.024533420680433), FRAC_CONST(0.020970883061607)}, {FRAC_CONST(0.024464662381971), FRAC_CONST(0.021051056059087)}, {FRAC_CONST(0.024395642086630), FRAC_CONST(0.021131003616670)}, + {FRAC_CONST(0.024326360533561), FRAC_CONST(0.021210724878181)}, {FRAC_CONST(0.024256818464715), FRAC_CONST(0.021290218989868)}, {FRAC_CONST(0.024187016624830), FRAC_CONST(0.021369485100415)}, + {FRAC_CONST(0.024116955761430), FRAC_CONST(0.021448522360944)}, {FRAC_CONST(0.024046636624808), FRAC_CONST(0.021527329925030)}, {FRAC_CONST(0.023976059968027), FRAC_CONST(0.021605906948708)}, + {FRAC_CONST(0.023905226546906), FRAC_CONST(0.021684252590480)}, {FRAC_CONST(0.023834137120014), FRAC_CONST(0.021762366011328)}, {FRAC_CONST(0.023762792448662), FRAC_CONST(0.021840246374720)}, + {FRAC_CONST(0.023691193296893), FRAC_CONST(0.021917892846620)}, {FRAC_CONST(0.023619340431478), FRAC_CONST(0.021995304595495)}, {FRAC_CONST(0.023547234621902), FRAC_CONST(0.022072480792330)}, + {FRAC_CONST(0.023474876640361), FRAC_CONST(0.022149420610628)}, {FRAC_CONST(0.023402267261751), FRAC_CONST(0.022226123226426)}, {FRAC_CONST(0.023329407263659), FRAC_CONST(0.022302587818300)}, + {FRAC_CONST(0.023256297426359), FRAC_CONST(0.022378813567377)}, {FRAC_CONST(0.023182938532797), FRAC_CONST(0.022454799657339)}, {FRAC_CONST(0.023109331368588), FRAC_CONST(0.022530545274437)}, + {FRAC_CONST(0.023035476722006), FRAC_CONST(0.022606049607496)}, {FRAC_CONST(0.022961375383975), FRAC_CONST(0.022681311847926)}, {FRAC_CONST(0.022887028148061), FRAC_CONST(0.022756331189727)}, + {FRAC_CONST(0.022812435810462), FRAC_CONST(0.022831106829504)}, {FRAC_CONST(0.022737599170003), FRAC_CONST(0.022905637966469)}, {FRAC_CONST(0.022662519028125), FRAC_CONST(0.022979923802453)}, + {FRAC_CONST(0.022587196188874), FRAC_CONST(0.023053963541915)}, {FRAC_CONST(0.022511631458899), FRAC_CONST(0.023127756391950)}, {FRAC_CONST(0.022435825647437), FRAC_CONST(0.023201301562294)}, + {FRAC_CONST(0.022359779566306), FRAC_CONST(0.023274598265338)}, {FRAC_CONST(0.022283494029900), FRAC_CONST(0.023347645716133)}, {FRAC_CONST(0.022206969855176), FRAC_CONST(0.023420443132400)}, + {FRAC_CONST(0.022130207861645), FRAC_CONST(0.023492989734537)}, {FRAC_CONST(0.022053208871367), FRAC_CONST(0.023565284745628)}, {FRAC_CONST(0.021975973708940), FRAC_CONST(0.023637327391451)}, + {FRAC_CONST(0.021898503201489), FRAC_CONST(0.023709116900488)}, {FRAC_CONST(0.021820798178663), FRAC_CONST(0.023780652503931)}, {FRAC_CONST(0.021742859472618), FRAC_CONST(0.023851933435691)}, + {FRAC_CONST(0.021664687918017), FRAC_CONST(0.023922958932406)}, {FRAC_CONST(0.021586284352013), FRAC_CONST(0.023993728233451)}, {FRAC_CONST(0.021507649614247), FRAC_CONST(0.024064240580942)}, + {FRAC_CONST(0.021428784546832), FRAC_CONST(0.024134495219750)}, {FRAC_CONST(0.021349689994350), FRAC_CONST(0.024204491397504)}, {FRAC_CONST(0.021270366803840), FRAC_CONST(0.024274228364600)}, + {FRAC_CONST(0.021190815824791), FRAC_CONST(0.024343705374213)}, {FRAC_CONST(0.021111037909128), FRAC_CONST(0.024412921682298)}, {FRAC_CONST(0.021031033911210), FRAC_CONST(0.024481876547605)}, + {FRAC_CONST(0.020950804687815), FRAC_CONST(0.024550569231683)}, {FRAC_CONST(0.020870351098134), FRAC_CONST(0.024618998998889)}, {FRAC_CONST(0.020789674003759), FRAC_CONST(0.024687165116394)}, + {FRAC_CONST(0.020708774268678), FRAC_CONST(0.024755066854194)}, {FRAC_CONST(0.020627652759262), FRAC_CONST(0.024822703485116)}, {FRAC_CONST(0.020546310344257), FRAC_CONST(0.024890074284826)}, + {FRAC_CONST(0.020464747894775), FRAC_CONST(0.024957178531837)}, {FRAC_CONST(0.020382966284284), FRAC_CONST(0.025024015507516)}, {FRAC_CONST(0.020300966388600), FRAC_CONST(0.025090584496093)}, + {FRAC_CONST(0.020218749085876), FRAC_CONST(0.025156884784668)}, {FRAC_CONST(0.020136315256592), FRAC_CONST(0.025222915663218)}, {FRAC_CONST(0.020053665783549), FRAC_CONST(0.025288676424605)}, + {FRAC_CONST(0.019970801551857), FRAC_CONST(0.025354166364584)}, {FRAC_CONST(0.019887723448925), FRAC_CONST(0.025419384781811)}, {FRAC_CONST(0.019804432364452), FRAC_CONST(0.025484330977848)}, + {FRAC_CONST(0.019720929190419), FRAC_CONST(0.025549004257175)}, {FRAC_CONST(0.019637214821078), FRAC_CONST(0.025613403927192)}, {FRAC_CONST(0.019553290152943), FRAC_CONST(0.025677529298230)}, + {FRAC_CONST(0.019469156084779), FRAC_CONST(0.025741379683559)}, {FRAC_CONST(0.019384813517595), FRAC_CONST(0.025804954399392)}, {FRAC_CONST(0.019300263354632), FRAC_CONST(0.025868252764895)}, + {FRAC_CONST(0.019215506501354), FRAC_CONST(0.025931274102193)}, {FRAC_CONST(0.019130543865439), FRAC_CONST(0.025994017736379)}, {FRAC_CONST(0.019045376356769), FRAC_CONST(0.026056482995518)}, + {FRAC_CONST(0.018960004887419), FRAC_CONST(0.026118669210657)}, {FRAC_CONST(0.018874430371648), FRAC_CONST(0.026180575715833)}, {FRAC_CONST(0.018788653725892), FRAC_CONST(0.026242201848076)}, + {FRAC_CONST(0.018702675868750), FRAC_CONST(0.026303546947421)}, {FRAC_CONST(0.018616497720974), FRAC_CONST(0.026364610356909)}, {FRAC_CONST(0.018530120205464), FRAC_CONST(0.026425391422602)}, + {FRAC_CONST(0.018443544247254), FRAC_CONST(0.026485889493583)}, {FRAC_CONST(0.018356770773502), FRAC_CONST(0.026546103921965)}, {FRAC_CONST(0.018269800713483), FRAC_CONST(0.026606034062902)}, + {FRAC_CONST(0.018182634998576), FRAC_CONST(0.026665679274589)}, {FRAC_CONST(0.018095274562256), FRAC_CONST(0.026725038918274)}, {FRAC_CONST(0.018007720340083), FRAC_CONST(0.026784112358263)}, + {FRAC_CONST(0.017919973269692), FRAC_CONST(0.026842898961926)}, {FRAC_CONST(0.017832034290785), FRAC_CONST(0.026901398099707)}, {FRAC_CONST(0.017743904345116), FRAC_CONST(0.026959609145127)}, + {FRAC_CONST(0.017655584376488), FRAC_CONST(0.027017531474792)}, {FRAC_CONST(0.017567075330734), FRAC_CONST(0.027075164468401)}, {FRAC_CONST(0.017478378155718), FRAC_CONST(0.027132507508750)}, + {FRAC_CONST(0.017389493801313), FRAC_CONST(0.027189559981742)}, {FRAC_CONST(0.017300423219401), FRAC_CONST(0.027246321276391)}, {FRAC_CONST(0.017211167363854), FRAC_CONST(0.027302790784828)}, + {FRAC_CONST(0.017121727190533), FRAC_CONST(0.027358967902310)}, {FRAC_CONST(0.017032103657269), FRAC_CONST(0.027414852027226)}, {FRAC_CONST(0.016942297723858), FRAC_CONST(0.027470442561102)}, + {FRAC_CONST(0.016852310352050), FRAC_CONST(0.027525738908608)}, {FRAC_CONST(0.016762142505537), FRAC_CONST(0.027580740477564)}, {FRAC_CONST(0.016671795149944), FRAC_CONST(0.027635446678948)}, + {FRAC_CONST(0.016581269252819), FRAC_CONST(0.027689856926900)}, {FRAC_CONST(0.016490565783622), FRAC_CONST(0.027743970638730)}, {FRAC_CONST(0.016399685713714), FRAC_CONST(0.027797787234924)}, + {FRAC_CONST(0.016308630016347), FRAC_CONST(0.027851306139149)}, {FRAC_CONST(0.016217399666655), FRAC_CONST(0.027904526778260)}, {FRAC_CONST(0.016125995641641), FRAC_CONST(0.027957448582309)}, + {FRAC_CONST(0.016034418920170), FRAC_CONST(0.028010070984544)}, {FRAC_CONST(0.015942670482954), FRAC_CONST(0.028062393421421)}, {FRAC_CONST(0.015850751312545), FRAC_CONST(0.028114415332610)}, + {FRAC_CONST(0.015758662393324), FRAC_CONST(0.028166136160998)}, {FRAC_CONST(0.015666404711489), FRAC_CONST(0.028217555352697)}, {FRAC_CONST(0.015573979255046), FRAC_CONST(0.028268672357047)}, + {FRAC_CONST(0.015481387013797), FRAC_CONST(0.028319486626627)}, {FRAC_CONST(0.015388628979331), FRAC_CONST(0.028369997617257)}, {FRAC_CONST(0.015295706145012), FRAC_CONST(0.028420204788004)}, + {FRAC_CONST(0.015202619505968), FRAC_CONST(0.028470107601191)}, {FRAC_CONST(0.015109370059084), FRAC_CONST(0.028519705522399)}, {FRAC_CONST(0.015015958802984), FRAC_CONST(0.028568998020472)}, + {FRAC_CONST(0.014922386738030), FRAC_CONST(0.028617984567529)}, {FRAC_CONST(0.014828654866302), FRAC_CONST(0.028666664638963)}, {FRAC_CONST(0.014734764191593), FRAC_CONST(0.028715037713449)}, + {FRAC_CONST(0.014640715719398), FRAC_CONST(0.028763103272951)}, {FRAC_CONST(0.014546510456900), FRAC_CONST(0.028810860802724)}, {FRAC_CONST(0.014452149412962), FRAC_CONST(0.028858309791325)}, + {FRAC_CONST(0.014357633598114), FRAC_CONST(0.028905449730613)}, {FRAC_CONST(0.014262964024545), FRAC_CONST(0.028952280115756)}, {FRAC_CONST(0.014168141706090), FRAC_CONST(0.028998800445240)}, + {FRAC_CONST(0.014073167658220), FRAC_CONST(0.029045010220868)}, {FRAC_CONST(0.013978042898030), FRAC_CONST(0.029090908947771)}, {FRAC_CONST(0.013882768444231), FRAC_CONST(0.029136496134411)}, + {FRAC_CONST(0.013787345317136), FRAC_CONST(0.029181771292585)}, {FRAC_CONST(0.013691774538648), FRAC_CONST(0.029226733937433)}, {FRAC_CONST(0.013596057132255), FRAC_CONST(0.029271383587441)}, + {FRAC_CONST(0.013500194123014), FRAC_CONST(0.029315719764447)}, {FRAC_CONST(0.013404186537539), FRAC_CONST(0.029359741993647)}, {FRAC_CONST(0.013308035403995), FRAC_CONST(0.029403449803598)}, + {FRAC_CONST(0.013211741752084), FRAC_CONST(0.029446842726223)}, {FRAC_CONST(0.013115306613032), FRAC_CONST(0.029489920296820)}, {FRAC_CONST(0.013018731019584), FRAC_CONST(0.029532682054063)}, + {FRAC_CONST(0.012922016005985), FRAC_CONST(0.029575127540008)}, {FRAC_CONST(0.012825162607977), FRAC_CONST(0.029617256300097)}, {FRAC_CONST(0.012728171862781), FRAC_CONST(0.029659067883165)}, + {FRAC_CONST(0.012631044809089), FRAC_CONST(0.029700561841444)}, {FRAC_CONST(0.012533782487056), FRAC_CONST(0.029741737730567)}, {FRAC_CONST(0.012436385938281), FRAC_CONST(0.029782595109573)}, + {FRAC_CONST(0.012338856205805), FRAC_CONST(0.029823133540913)}, {FRAC_CONST(0.012241194334091), FRAC_CONST(0.029863352590452)}, {FRAC_CONST(0.012143401369021), FRAC_CONST(0.029903251827477)}, + {FRAC_CONST(0.012045478357878), FRAC_CONST(0.029942830824699)}, {FRAC_CONST(0.011947426349339), FRAC_CONST(0.029982089158259)}, {FRAC_CONST(0.011849246393462), FRAC_CONST(0.030021026407731)}, + {FRAC_CONST(0.011750939541676), FRAC_CONST(0.030059642156129)}, {FRAC_CONST(0.011652506846768), FRAC_CONST(0.030097935989909)}, {FRAC_CONST(0.011553949362874), FRAC_CONST(0.030135907498976)}, + {FRAC_CONST(0.011455268145464), FRAC_CONST(0.030173556276684)}, {FRAC_CONST(0.011356464251335), FRAC_CONST(0.030210881919845)}, {FRAC_CONST(0.011257538738598), FRAC_CONST(0.030247884028732)}, + {FRAC_CONST(0.011158492666665), FRAC_CONST(0.030284562207083)}, {FRAC_CONST(0.011059327096240), FRAC_CONST(0.030320916062102)}, {FRAC_CONST(0.010960043089307), FRAC_CONST(0.030356945204470)}, + {FRAC_CONST(0.010860641709118), FRAC_CONST(0.030392649248343)}, {FRAC_CONST(0.010761124020182), FRAC_CONST(0.030428027811361)}, {FRAC_CONST(0.010661491088253), FRAC_CONST(0.030463080514646)}, + {FRAC_CONST(0.010561743980319), FRAC_CONST(0.030497806982812)}, {FRAC_CONST(0.010461883764593), FRAC_CONST(0.030532206843968)}, {FRAC_CONST(0.010361911510496), FRAC_CONST(0.030566279729717)}, + {FRAC_CONST(0.010261828288652), FRAC_CONST(0.030600025275167)}, {FRAC_CONST(0.010161635170872), FRAC_CONST(0.030633443118931)}, {FRAC_CONST(0.010061333230142), FRAC_CONST(0.030666532903129)}, + {FRAC_CONST(0.009960923540617), FRAC_CONST(0.030699294273397)}, {FRAC_CONST(0.009860407177603), FRAC_CONST(0.030731726878888)}, {FRAC_CONST(0.009759785217550), FRAC_CONST(0.030763830372273)}, + {FRAC_CONST(0.009659058738038), FRAC_CONST(0.030795604409750)}, {FRAC_CONST(0.009558228817767), FRAC_CONST(0.030827048651045)}, {FRAC_CONST(0.009457296536545), FRAC_CONST(0.030858162759415)}, + {FRAC_CONST(0.009356262975275), FRAC_CONST(0.030888946401653)}, {FRAC_CONST(0.009255129215945), FRAC_CONST(0.030919399248091)}, {FRAC_CONST(0.009153896341616), FRAC_CONST(0.030949520972603)}, + {FRAC_CONST(0.009052565436412), FRAC_CONST(0.030979311252611)}, {FRAC_CONST(0.008951137585505), FRAC_CONST(0.031008769769084)}, {FRAC_CONST(0.008849613875105), FRAC_CONST(0.031037896206544)}, + {FRAC_CONST(0.008747995392451), FRAC_CONST(0.031066690253072)}, {FRAC_CONST(0.008646283225794), FRAC_CONST(0.031095151600306)}, {FRAC_CONST(0.008544478464390), FRAC_CONST(0.031123279943448)}, + {FRAC_CONST(0.008442582198486), FRAC_CONST(0.031151074981266)}, {FRAC_CONST(0.008340595519310), FRAC_CONST(0.031178536416098)}, {FRAC_CONST(0.008238519519057), FRAC_CONST(0.031205663953853)}, + {FRAC_CONST(0.008136355290878), FRAC_CONST(0.031232457304017)}, {FRAC_CONST(0.008034103928871), FRAC_CONST(0.031258916179656)}, {FRAC_CONST(0.007931766528065), FRAC_CONST(0.031285040297416)}, + {FRAC_CONST(0.007829344184412), FRAC_CONST(0.031310829377528)}, {FRAC_CONST(0.007726837994772), FRAC_CONST(0.031336283143813)}, {FRAC_CONST(0.007624249056906), FRAC_CONST(0.031361401323680)}, + {FRAC_CONST(0.007521578469457), FRAC_CONST(0.031386183648135)}, {FRAC_CONST(0.007418827331946), FRAC_CONST(0.031410629851778)}, {FRAC_CONST(0.007315996744755), FRAC_CONST(0.031434739672811)}, + {FRAC_CONST(0.007213087809115), FRAC_CONST(0.031458512853036)}, {FRAC_CONST(0.007110101627101), FRAC_CONST(0.031481949137863)}, {FRAC_CONST(0.007007039301610), FRAC_CONST(0.031505048276306)}, + {FRAC_CONST(0.006903901936357), FRAC_CONST(0.031527810020993)}, {FRAC_CONST(0.006800690635862), FRAC_CONST(0.031550234128164)}, {FRAC_CONST(0.006697406505433), FRAC_CONST(0.031572320357675)}, + {FRAC_CONST(0.006594050651161), FRAC_CONST(0.031594068473000)}, {FRAC_CONST(0.006490624179905), FRAC_CONST(0.031615478241233)}, {FRAC_CONST(0.006387128199278), FRAC_CONST(0.031636549433095)}, + {FRAC_CONST(0.006283563817639), FRAC_CONST(0.031657281822929)}, {FRAC_CONST(0.006179932144080), FRAC_CONST(0.031677675188707)}, {FRAC_CONST(0.006076234288412), FRAC_CONST(0.031697729312034)}, + {FRAC_CONST(0.005972471361157), FRAC_CONST(0.031717443978146)}, {FRAC_CONST(0.005868644473532), FRAC_CONST(0.031736818975914)}, {FRAC_CONST(0.005764754737440), FRAC_CONST(0.031755854097848)}, + {FRAC_CONST(0.005660803265456), FRAC_CONST(0.031774549140098)}, {FRAC_CONST(0.005556791170816), FRAC_CONST(0.031792903902453)}, {FRAC_CONST(0.005452719567407), FRAC_CONST(0.031810918188350)}, + {FRAC_CONST(0.005348589569753), FRAC_CONST(0.031828591804869)}, {FRAC_CONST(0.005244402293001), FRAC_CONST(0.031845924562742)}, {FRAC_CONST(0.005140158852914), FRAC_CONST(0.031862916276347)}, + {FRAC_CONST(0.005035860365855), FRAC_CONST(0.031879566763717)}, {FRAC_CONST(0.004931507948778), FRAC_CONST(0.031895875846539)}, {FRAC_CONST(0.004827102719212), FRAC_CONST(0.031911843350155)}, + {FRAC_CONST(0.004722645795254), FRAC_CONST(0.031927469103567)}, {FRAC_CONST(0.004618138295554), FRAC_CONST(0.031942752939435)}, {FRAC_CONST(0.004513581339303), FRAC_CONST(0.031957694694082)}, + {FRAC_CONST(0.004408976046222), FRAC_CONST(0.031972294207493)}, {FRAC_CONST(0.004304323536549), FRAC_CONST(0.031986551323320)}, {FRAC_CONST(0.004199624931030), FRAC_CONST(0.032000465888879)}, + {FRAC_CONST(0.004094881350902), FRAC_CONST(0.032014037755158)}, {FRAC_CONST(0.003990093917884), FRAC_CONST(0.032027266776813)}, {FRAC_CONST(0.003885263754166), FRAC_CONST(0.032040152812170)}, + {FRAC_CONST(0.003780391982394), FRAC_CONST(0.032052695723232)}, {FRAC_CONST(0.003675479725661), FRAC_CONST(0.032064895375674)}, {FRAC_CONST(0.003570528107494), FRAC_CONST(0.032076751638847)}, + {FRAC_CONST(0.003465538251839), FRAC_CONST(0.032088264385780)}, {FRAC_CONST(0.003360511283053), FRAC_CONST(0.032099433493181)}, {FRAC_CONST(0.003255448325892), FRAC_CONST(0.032110258841438)}, + {FRAC_CONST(0.003150350505494), FRAC_CONST(0.032120740314619)}, {FRAC_CONST(0.003045218947373), FRAC_CONST(0.032130877800478)}, {FRAC_CONST(0.002940054777404), FRAC_CONST(0.032140671190449)}, + {FRAC_CONST(0.002834859121810), FRAC_CONST(0.032150120379653)}, {FRAC_CONST(0.002729633107153), FRAC_CONST(0.032159225266897)}, {FRAC_CONST(0.002624377860318), FRAC_CONST(0.032167985754674)}, + {FRAC_CONST(0.002519094508504), FRAC_CONST(0.032176401749168)}, {FRAC_CONST(0.002413784179212), FRAC_CONST(0.032184473160250)}, {FRAC_CONST(0.002308448000231), FRAC_CONST(0.032192199901481)}, + {FRAC_CONST(0.002203087099626), FRAC_CONST(0.032199581890114)}, {FRAC_CONST(0.002097702605728), FRAC_CONST(0.032206619047093)}, {FRAC_CONST(0.001992295647121), FRAC_CONST(0.032213311297057)}, + {FRAC_CONST(0.001886867352628), FRAC_CONST(0.032219658568338)}, {FRAC_CONST(0.001781418851302), FRAC_CONST(0.032225660792960)}, {FRAC_CONST(0.001675951272410), FRAC_CONST(0.032231317906644)}, + {FRAC_CONST(0.001570465745428), FRAC_CONST(0.032236629848809)}, {FRAC_CONST(0.001464963400018), FRAC_CONST(0.032241596562566)}, {FRAC_CONST(0.001359445366028), FRAC_CONST(0.032246217994727)}, + {FRAC_CONST(0.001253912773470), FRAC_CONST(0.032250494095799)}, {FRAC_CONST(0.001148366752513), FRAC_CONST(0.032254424819990)}, {FRAC_CONST(0.001042808433471), FRAC_CONST(0.032258010125204)}, + {FRAC_CONST(0.000937238946789), FRAC_CONST(0.032261249973045)}, {FRAC_CONST(0.000831659423030), FRAC_CONST(0.032264144328817)}, {FRAC_CONST(0.000726070992868), FRAC_CONST(0.032266693161525)}, + {FRAC_CONST(0.000620474787068), FRAC_CONST(0.032268896443871)}, {FRAC_CONST(0.000514871936481), FRAC_CONST(0.032270754152261)}, {FRAC_CONST(0.000409263572030), FRAC_CONST(0.032272266266801)}, + {FRAC_CONST(0.000303650824695), FRAC_CONST(0.032273432771295)}, {FRAC_CONST(0.000198034825504), FRAC_CONST(0.032274253653254)}, {FRAC_CONST(0.000092416705518), FRAC_CONST(0.032274728903884)}}; + #ifdef LD_DEC +/* 240 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_960[] = { + {FRAC_CONST(0.045643531183573), FRAC_CONST(0.000037342034959)}, {FRAC_CONST(0.045642309173789), FRAC_CONST(0.000336075315362)}, {FRAC_CONST(0.045639131999390), FRAC_CONST(0.000634794199417)}, + {FRAC_CONST(0.045633999796474), FRAC_CONST(0.000933485891002)}, {FRAC_CONST(0.045626912784890), FRAC_CONST(0.001232137595157)}, {FRAC_CONST(0.045617871268219), FRAC_CONST(0.001530736518639)}, + {FRAC_CONST(0.045606875633772), FRAC_CONST(0.001829269870464)}, {FRAC_CONST(0.045593926352564), FRAC_CONST(0.002127724862455)}, {FRAC_CONST(0.045579023979299), FRAC_CONST(0.002426088709795)}, + {FRAC_CONST(0.045562169152346), FRAC_CONST(0.002724348631569)}, {FRAC_CONST(0.045543362593709), FRAC_CONST(0.003022491851315)}, {FRAC_CONST(0.045522605108999), FRAC_CONST(0.003320505597570)}, + {FRAC_CONST(0.045499897587396), FRAC_CONST(0.003618377104416)}, {FRAC_CONST(0.045475241001617), FRAC_CONST(0.003916093612031)}, {FRAC_CONST(0.045448636407866), FRAC_CONST(0.004213642367228)}, + {FRAC_CONST(0.045420084945797), FRAC_CONST(0.004511010624011)}, {FRAC_CONST(0.045389587838458), FRAC_CONST(0.004808185644112)}, {FRAC_CONST(0.045357146392244), FRAC_CONST(0.005105154697544)}, + {FRAC_CONST(0.045322761996840), FRAC_CONST(0.005401905063139)}, {FRAC_CONST(0.045286436125157), FRAC_CONST(0.005698424029100)}, {FRAC_CONST(0.045248170333275), FRAC_CONST(0.005994698893542)}, + {FRAC_CONST(0.045207966260374), FRAC_CONST(0.006290716965035)}, {FRAC_CONST(0.045165825628663), FRAC_CONST(0.006586465563151)}, {FRAC_CONST(0.045121750243305), FRAC_CONST(0.006881932019003)}, + {FRAC_CONST(0.045075741992343), FRAC_CONST(0.007177103675792)}, {FRAC_CONST(0.045027802846618), FRAC_CONST(0.007471967889347)}, {FRAC_CONST(0.044977934859683), FRAC_CONST(0.007766512028667)}, + {FRAC_CONST(0.044926140167717), FRAC_CONST(0.008060723476460)}, {FRAC_CONST(0.044872420989432), FRAC_CONST(0.008354589629687)}, {FRAC_CONST(0.044816779625979), FRAC_CONST(0.008648097900101)}, + {FRAC_CONST(0.044759218460849), FRAC_CONST(0.008941235714784)}, {FRAC_CONST(0.044699739959770), FRAC_CONST(0.009233990516688)}, {FRAC_CONST(0.044638346670603), FRAC_CONST(0.009526349765171)}, + {FRAC_CONST(0.044575041223233), FRAC_CONST(0.009818300936537)}, {FRAC_CONST(0.044509826329454), FRAC_CONST(0.010109831524568)}, {FRAC_CONST(0.044442704782856), FRAC_CONST(0.010400929041064)}, + {FRAC_CONST(0.044373679458701), FRAC_CONST(0.010691581016378)}, {FRAC_CONST(0.044302753313806), FRAC_CONST(0.010981774999945)}, {FRAC_CONST(0.044229929386409), FRAC_CONST(0.011271498560822)}, + {FRAC_CONST(0.044155210796046), FRAC_CONST(0.011560739288214)}, {FRAC_CONST(0.044078600743413), FRAC_CONST(0.011849484792012)}, {FRAC_CONST(0.044000102510229), FRAC_CONST(0.012137722703321)}, + {FRAC_CONST(0.043919719459097), FRAC_CONST(0.012425440674986)}, {FRAC_CONST(0.043837455033359), FRAC_CONST(0.012712626382127)}, {FRAC_CONST(0.043753312756950), FRAC_CONST(0.012999267522665)}, + {FRAC_CONST(0.043667296234245), FRAC_CONST(0.013285351817848)}, {FRAC_CONST(0.043579409149906), FRAC_CONST(0.013570867012776)}, {FRAC_CONST(0.043489655268722), FRAC_CONST(0.013855800876928)}, + {FRAC_CONST(0.043398038435451), FRAC_CONST(0.014140141204686)}, {FRAC_CONST(0.043304562574653), FRAC_CONST(0.014423875815857)}, {FRAC_CONST(0.043209231690524), FRAC_CONST(0.014706992556195)}, + {FRAC_CONST(0.043112049866720), FRAC_CONST(0.014989479297920)}, {FRAC_CONST(0.043013021266188), FRAC_CONST(0.015271323940241)}, {FRAC_CONST(0.042912150130984), FRAC_CONST(0.015552514409871)}, + {FRAC_CONST(0.042809440782090), FRAC_CONST(0.015833038661547)}, {FRAC_CONST(0.042704897619235), FRAC_CONST(0.016112884678543)}, {FRAC_CONST(0.042598525120698), FRAC_CONST(0.016392040473187)}, + {FRAC_CONST(0.042490327843124), FRAC_CONST(0.016670494087374)}, {FRAC_CONST(0.042380310421324), FRAC_CONST(0.016948233593079)}, {FRAC_CONST(0.042268477568078), FRAC_CONST(0.017225247092864)}, + {FRAC_CONST(0.042154834073934), FRAC_CONST(0.017501522720393)}, {FRAC_CONST(0.042039384807000), FRAC_CONST(0.017777048640940)}, {FRAC_CONST(0.041922134712739), FRAC_CONST(0.018051813051888)}, + {FRAC_CONST(0.041803088813754), FRAC_CONST(0.018325804183247)}, {FRAC_CONST(0.041682252209576), FRAC_CONST(0.018599010298148)}, {FRAC_CONST(0.041559630076443), FRAC_CONST(0.018871419693350)}, + {FRAC_CONST(0.041435227667079), FRAC_CONST(0.019143020699741)}, {FRAC_CONST(0.041309050310468), FRAC_CONST(0.019413801682838)}, {FRAC_CONST(0.041181103411629), FRAC_CONST(0.019683751043285)}, + {FRAC_CONST(0.041051392451382), FRAC_CONST(0.019952857217350)}, {FRAC_CONST(0.040919922986111), FRAC_CONST(0.020221108677421)}, {FRAC_CONST(0.040786700647532), FRAC_CONST(0.020488493932496)}, + {FRAC_CONST(0.040651731142446), FRAC_CONST(0.020755001528683)}, {FRAC_CONST(0.040515020252497), FRAC_CONST(0.021020620049682)}, {FRAC_CONST(0.040376573833925), FRAC_CONST(0.021285338117280)}, + {FRAC_CONST(0.040236397817314), FRAC_CONST(0.021549144391836)}, {FRAC_CONST(0.040094498207337), FRAC_CONST(0.021812027572768)}, {FRAC_CONST(0.039950881082502), FRAC_CONST(0.022073976399034)}, + {FRAC_CONST(0.039805552594888), FRAC_CONST(0.022334979649620)}, {FRAC_CONST(0.039658518969884), FRAC_CONST(0.022595026144014)}, {FRAC_CONST(0.039509786505922), FRAC_CONST(0.022854104742690)}, + {FRAC_CONST(0.039359361574204), FRAC_CONST(0.023112204347583)}, {FRAC_CONST(0.039207250618434), FRAC_CONST(0.023369313902565)}, {FRAC_CONST(0.039053460154540), FRAC_CONST(0.023625422393919)}, + {FRAC_CONST(0.038897996770393), FRAC_CONST(0.023880518850809)}, {FRAC_CONST(0.038740867125527), FRAC_CONST(0.024134592345752)}, {FRAC_CONST(0.038582077950852), FRAC_CONST(0.024387631995085)}, + {FRAC_CONST(0.038421636048370), FRAC_CONST(0.024639626959432)}, {FRAC_CONST(0.038259548290876), FRAC_CONST(0.024890566444167)}, {FRAC_CONST(0.038095821621671), FRAC_CONST(0.025140439699877)}, + {FRAC_CONST(0.037930463054261), FRAC_CONST(0.025389236022825)}, {FRAC_CONST(0.037763479672055), FRAC_CONST(0.025636944755403)}, {FRAC_CONST(0.037594878628068), FRAC_CONST(0.025883555286595)}, + {FRAC_CONST(0.037424667144605), FRAC_CONST(0.026129057052425)}, {FRAC_CONST(0.037252852512960), FRAC_CONST(0.026373439536415)}, {FRAC_CONST(0.037079442093102), FRAC_CONST(0.026616692270033)}, + {FRAC_CONST(0.036904443313354), FRAC_CONST(0.026858804833142)}, {FRAC_CONST(0.036727863670081), FRAC_CONST(0.027099766854444)}, {FRAC_CONST(0.036549710727369), FRAC_CONST(0.027339568011930)}, + {FRAC_CONST(0.036369992116697), FRAC_CONST(0.027578198033315)}, {FRAC_CONST(0.036188715536611), FRAC_CONST(0.027815646696484)}, {FRAC_CONST(0.036005888752396), FRAC_CONST(0.028051903829926)}, + {FRAC_CONST(0.035821519595745), FRAC_CONST(0.028286959313171)}, {FRAC_CONST(0.035635615964417), FRAC_CONST(0.028520803077226)}, {FRAC_CONST(0.035448185821906), FRAC_CONST(0.028753425105002)}, + {FRAC_CONST(0.035259237197095), FRAC_CONST(0.028984815431745)}, {FRAC_CONST(0.035068778183914), FRAC_CONST(0.029214964145465)}, {FRAC_CONST(0.034876816940994), FRAC_CONST(0.029443861387355)}, + {FRAC_CONST(0.034683361691315), FRAC_CONST(0.029671497352220)}, {FRAC_CONST(0.034488420721856), FRAC_CONST(0.029897862288892)}, {FRAC_CONST(0.034292002383240), FRAC_CONST(0.030122946500652)}, + {FRAC_CONST(0.034094115089375), FRAC_CONST(0.030346740345641)}, {FRAC_CONST(0.033894767317093), FRAC_CONST(0.030569234237276)}, {FRAC_CONST(0.033693967605790), FRAC_CONST(0.030790418644658)}, + {FRAC_CONST(0.033491724557057), FRAC_CONST(0.031010284092984)}, {FRAC_CONST(0.033288046834313), FRAC_CONST(0.031228821163949)}, {FRAC_CONST(0.033082943162434), FRAC_CONST(0.031446020496153)}, + {FRAC_CONST(0.032876422327378), FRAC_CONST(0.031661872785500)}, {FRAC_CONST(0.032668493175811), FRAC_CONST(0.031876368785596)}, {FRAC_CONST(0.032459164614726), FRAC_CONST(0.032089499308145)}, + {FRAC_CONST(0.032248445611061), FRAC_CONST(0.032301255223347)}, {FRAC_CONST(0.032036345191317), FRAC_CONST(0.032511627460281)}, {FRAC_CONST(0.031822872441171), FRAC_CONST(0.032720607007302)}, + {FRAC_CONST(0.031608036505083), FRAC_CONST(0.032928184912422)}, {FRAC_CONST(0.031391846585912), FRAC_CONST(0.033134352283693)}, {FRAC_CONST(0.031174311944513), FRAC_CONST(0.033339100289593)}, + {FRAC_CONST(0.030955441899347), FRAC_CONST(0.033542420159397)}, {FRAC_CONST(0.030735245826077), FRAC_CONST(0.033744303183559)}, {FRAC_CONST(0.030513733157171), FRAC_CONST(0.033944740714083)}, + {FRAC_CONST(0.030290913381494), FRAC_CONST(0.034143724164891)}, {FRAC_CONST(0.030066796043904), FRAC_CONST(0.034341245012195)}, {FRAC_CONST(0.029841390744841), FRAC_CONST(0.034537294794860)}, + {FRAC_CONST(0.029614707139919), FRAC_CONST(0.034731865114764)}, {FRAC_CONST(0.029386754939508), FRAC_CONST(0.034924947637164)}, {FRAC_CONST(0.029157543908322), FRAC_CONST(0.035116534091046)}, + {FRAC_CONST(0.028927083864999), FRAC_CONST(0.035306616269485)}, {FRAC_CONST(0.028695384681680), FRAC_CONST(0.035495186029992)}, {FRAC_CONST(0.028462456283587), FRAC_CONST(0.035682235294866)}, + {FRAC_CONST(0.028228308648598), FRAC_CONST(0.035867756051541)}, {FRAC_CONST(0.027992951806817), FRAC_CONST(0.036051740352923)}, {FRAC_CONST(0.027756395840148), FRAC_CONST(0.036234180317738)}, + {FRAC_CONST(0.027518650881862), FRAC_CONST(0.036415068130865)}, {FRAC_CONST(0.027279727116161), FRAC_CONST(0.036594396043672)}, {FRAC_CONST(0.027039634777745), FRAC_CONST(0.036772156374348)}, + {FRAC_CONST(0.026798384151369), FRAC_CONST(0.036948341508233)}, {FRAC_CONST(0.026555985571409), FRAC_CONST(0.037122943898140)}, {FRAC_CONST(0.026312449421412), FRAC_CONST(0.037295956064686)}, + {FRAC_CONST(0.026067786133656), FRAC_CONST(0.037467370596605)}, {FRAC_CONST(0.025822006188702), FRAC_CONST(0.037637180151068)}, {FRAC_CONST(0.025575120114946), FRAC_CONST(0.037805377454000)}, + {FRAC_CONST(0.025327138488165), FRAC_CONST(0.037971955300388)}, {FRAC_CONST(0.025078071931066), FRAC_CONST(0.038136906554591)}, {FRAC_CONST(0.024827931112832), FRAC_CONST(0.038300224150647)}, + {FRAC_CONST(0.024576726748663), FRAC_CONST(0.038461901092573)}, {FRAC_CONST(0.024324469599317), FRAC_CONST(0.038621930454668)}, {FRAC_CONST(0.024071170470652), FRAC_CONST(0.038780305381806)}, + {FRAC_CONST(0.023816840213160), FRAC_CONST(0.038937019089732)}, {FRAC_CONST(0.023561489721501), FRAC_CONST(0.039092064865353)}, {FRAC_CONST(0.023305129934041), FRAC_CONST(0.039245436067023)}, + {FRAC_CONST(0.023047771832380), FRAC_CONST(0.039397126124832)}, {FRAC_CONST(0.022789426440883), FRAC_CONST(0.039547128540881)}, {FRAC_CONST(0.022530104826206), FRAC_CONST(0.039695436889566)}, + {FRAC_CONST(0.022269818096825), FRAC_CONST(0.039842044817851)}, {FRAC_CONST(0.022008577402555), FRAC_CONST(0.039986946045542)}, {FRAC_CONST(0.021746393934081), FRAC_CONST(0.040130134365550)}, + {FRAC_CONST(0.021483278922467), FRAC_CONST(0.040271603644166)}, {FRAC_CONST(0.021219243638687), FRAC_CONST(0.040411347821316)}, {FRAC_CONST(0.020954299393132), FRAC_CONST(0.040549360910825)}, + {FRAC_CONST(0.020688457535133), FRAC_CONST(0.040685637000671)}, {FRAC_CONST(0.020421729452469), FRAC_CONST(0.040820170253240)}, {FRAC_CONST(0.020154126570884), FRAC_CONST(0.040952954905576)}, + {FRAC_CONST(0.019885660353596), FRAC_CONST(0.041083985269625)}, {FRAC_CONST(0.019616342300802), FRAC_CONST(0.041213255732484)}, {FRAC_CONST(0.019346183949192), FRAC_CONST(0.041340760756635)}, + {FRAC_CONST(0.019075196871451), FRAC_CONST(0.041466494880189)}, {FRAC_CONST(0.018803392675763), FRAC_CONST(0.041590452717113)}, {FRAC_CONST(0.018530783005316), FRAC_CONST(0.041712628957466)}, + {FRAC_CONST(0.018257379537800), FRAC_CONST(0.041833018367625)}, {FRAC_CONST(0.017983193984910), FRAC_CONST(0.041951615790509)}, {FRAC_CONST(0.017708238091842), FRAC_CONST(0.042068416145797)}, + {FRAC_CONST(0.017432523636792), FRAC_CONST(0.042183414430153)}, {FRAC_CONST(0.017156062430449), FRAC_CONST(0.042296605717432)}, {FRAC_CONST(0.016878866315491), FRAC_CONST(0.042407985158896)}, + {FRAC_CONST(0.016600947166078), FRAC_CONST(0.042517547983420)}, {FRAC_CONST(0.016322316887341), FRAC_CONST(0.042625289497698)}, {FRAC_CONST(0.016042987414872), FRAC_CONST(0.042731205086442)}, + {FRAC_CONST(0.015762970714219), FRAC_CONST(0.042835290212581)}, {FRAC_CONST(0.015482278780363), FRAC_CONST(0.042937540417454)}, {FRAC_CONST(0.015200923637213), FRAC_CONST(0.043037951321002)}, + {FRAC_CONST(0.014918917337087), FRAC_CONST(0.043136518621958)}, {FRAC_CONST(0.014636271960196), FRAC_CONST(0.043233238098025)}, {FRAC_CONST(0.014352999614128), FRAC_CONST(0.043328105606063)}, + {FRAC_CONST(0.014069112433327), FRAC_CONST(0.043421117082265)}, {FRAC_CONST(0.013784622578575), FRAC_CONST(0.043512268542327)}, {FRAC_CONST(0.013499542236471), FRAC_CONST(0.043601556081625)}, + {FRAC_CONST(0.013213883618907), FRAC_CONST(0.043688975875378)}, {FRAC_CONST(0.012927658962548), FRAC_CONST(0.043774524178812)}, {FRAC_CONST(0.012640880528305), FRAC_CONST(0.043858197327323)}, + {FRAC_CONST(0.012353560600813), FRAC_CONST(0.043939991736633)}, {FRAC_CONST(0.012065711487901), FRAC_CONST(0.044019903902940)}, {FRAC_CONST(0.011777345520066), FRAC_CONST(0.044097930403073)}, + {FRAC_CONST(0.011488475049948), FRAC_CONST(0.044174067894638)}, {FRAC_CONST(0.011199112451794), FRAC_CONST(0.044248313116156)}, {FRAC_CONST(0.010909270120937), FRAC_CONST(0.044320662887211)}, + {FRAC_CONST(0.010618960473257), FRAC_CONST(0.044391114108577)}, {FRAC_CONST(0.010328195944653), FRAC_CONST(0.044459663762361)}, {FRAC_CONST(0.010036988990509), FRAC_CONST(0.044526308912122)}, + {FRAC_CONST(0.009745352085163), FRAC_CONST(0.044591046703005)}, {FRAC_CONST(0.009453297721368), FRAC_CONST(0.044653874361857)}, {FRAC_CONST(0.009160838409762), FRAC_CONST(0.044714789197351)}, + {FRAC_CONST(0.008867986678328), FRAC_CONST(0.044773788600099)}, {FRAC_CONST(0.008574755071860), FRAC_CONST(0.044830870042761)}, {FRAC_CONST(0.008281156151424), FRAC_CONST(0.044886031080160)}, + {FRAC_CONST(0.007987202493820), FRAC_CONST(0.044939269349379)}, {FRAC_CONST(0.007692906691044), FRAC_CONST(0.044990582569869)}, {FRAC_CONST(0.007398281349750), FRAC_CONST(0.045039968543542)}, + {FRAC_CONST(0.007103339090706), FRAC_CONST(0.045087425154868)}, {FRAC_CONST(0.006808092548258), FRAC_CONST(0.045132950370962)}, {FRAC_CONST(0.006512554369783), FRAC_CONST(0.045176542241676)}, + {FRAC_CONST(0.006216737215155), FRAC_CONST(0.045218198899680)}, {FRAC_CONST(0.005920653756196), FRAC_CONST(0.045257918560541)}, {FRAC_CONST(0.005624316676135), FRAC_CONST(0.045295699522801)}, + {FRAC_CONST(0.005327738669067), FRAC_CONST(0.045331540168049)}, {FRAC_CONST(0.005030932439406), FRAC_CONST(0.045365438960992)}, {FRAC_CONST(0.004733910701344), FRAC_CONST(0.045397394449517)}, + {FRAC_CONST(0.004436686178303), FRAC_CONST(0.045427405264758)}, {FRAC_CONST(0.004139271602393), FRAC_CONST(0.045455470121152)}, {FRAC_CONST(0.003841679713863), FRAC_CONST(0.045481587816494)}, + {FRAC_CONST(0.003543923260561), FRAC_CONST(0.045505757231988)}, {FRAC_CONST(0.003246014997382), FRAC_CONST(0.045527977332297)}, {FRAC_CONST(0.002947967685724), FRAC_CONST(0.045548247165585)}, + {FRAC_CONST(0.002649794092941), FRAC_CONST(0.045566565863562)}, {FRAC_CONST(0.002351506991799), FRAC_CONST(0.045582932641515)}, {FRAC_CONST(0.002053119159924), FRAC_CONST(0.045597346798344)}, + {FRAC_CONST(0.001754643379257), FRAC_CONST(0.045609807716597)}, {FRAC_CONST(0.001456092435508), FRAC_CONST(0.045620314862489)}, {FRAC_CONST(0.001157479117605), FRAC_CONST(0.045628867785927)}, + {FRAC_CONST(0.000858816217149), FRAC_CONST(0.045635466120535)}, {FRAC_CONST(0.000560116527865), FRAC_CONST(0.045640109583661)}, {FRAC_CONST(0.000261392845053), FRAC_CONST(0.045642797976394)}}; + #endif // LD_DEC +/* 60 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_240[] = { + {FRAC_CONST(0.091286604111815), FRAC_CONST(0.000298735779793)}, {FRAC_CONST(0.091247502481454), FRAC_CONST(0.002688238127538)}, {FRAC_CONST(0.091145864370807), FRAC_CONST(0.005075898091152)}, + {FRAC_CONST(0.090981759437558), FRAC_CONST(0.007460079287760)}, {FRAC_CONST(0.090755300151030), FRAC_CONST(0.009839147718664)}, {FRAC_CONST(0.090466641715108), FRAC_CONST(0.012211472889198)}, + {FRAC_CONST(0.090115981961863), FRAC_CONST(0.014575428926191)}, {FRAC_CONST(0.089703561215976), FRAC_CONST(0.016929395692256)}, {FRAC_CONST(0.089229662130024), FRAC_CONST(0.019271759896156)}, + {FRAC_CONST(0.088694609490769), FRAC_CONST(0.021600916198470)}, {FRAC_CONST(0.088098769996564), FRAC_CONST(0.023915268311810)}, {FRAC_CONST(0.087442552006035), FRAC_CONST(0.026213230094844)}, + {FRAC_CONST(0.086726405258214), FRAC_CONST(0.028493226639351)}, {FRAC_CONST(0.085950820564309), FRAC_CONST(0.030753695349588)}, {FRAC_CONST(0.085116329471329), FRAC_CONST(0.032993087013213)}, + {FRAC_CONST(0.084223503897785), FRAC_CONST(0.035209866863042)}, {FRAC_CONST(0.083272955741727), FRAC_CONST(0.037402515628894)}, {FRAC_CONST(0.082265336461381), FRAC_CONST(0.039569530578832)}, + {FRAC_CONST(0.081201336628670), FRAC_CONST(0.041709426549053)}, {FRAC_CONST(0.080081685455930), FRAC_CONST(0.043820736961749)}, {FRAC_CONST(0.078907150296148), FRAC_CONST(0.045902014830227)}, + {FRAC_CONST(0.077678536117054), FRAC_CONST(0.047951833750597)}, {FRAC_CONST(0.076396684949434), FRAC_CONST(0.049968788879362)}, {FRAC_CONST(0.075062475310050), FRAC_CONST(0.051951497896226)}, + {FRAC_CONST(0.073676821599542), FRAC_CONST(0.053898601951466)}, {FRAC_CONST(0.072240673475749), FRAC_CONST(0.055808766597225)}, {FRAC_CONST(0.070755015202858), FRAC_CONST(0.057680682702068)}, + {FRAC_CONST(0.069220864976840), FRAC_CONST(0.059513067348201)}, {FRAC_CONST(0.067639274227625), FRAC_CONST(0.061304664710718)}, {FRAC_CONST(0.066011326898512), FRAC_CONST(0.063054246918278)}, + {FRAC_CONST(0.064338138703282), FRAC_CONST(0.064760614894630)}, {FRAC_CONST(0.062620856361546), FRAC_CONST(0.066422599180399)}, {FRAC_CONST(0.060860656812842), FRAC_CONST(0.068039060734572)}, + {FRAC_CONST(0.059058746410016), FRAC_CONST(0.069608891715145)}, {FRAC_CONST(0.057216360092450), FRAC_CONST(0.071131016238378)}, {FRAC_CONST(0.055334760539699), FRAC_CONST(0.072604391116154)}, + {FRAC_CONST(0.053415237306106), FRAC_CONST(0.074028006570930)}, {FRAC_CONST(0.051459105937014), FRAC_CONST(0.075400886927784)}, {FRAC_CONST(0.049467707067153), FRAC_CONST(0.076722091283096)}, + {FRAC_CONST(0.047442405501835), FRAC_CONST(0.077990714149396)}, {FRAC_CONST(0.045384589281588), FRAC_CONST(0.079205886075941)}, {FRAC_CONST(0.043295668730857), FRAC_CONST(0.080366774244592)}, + {FRAC_CONST(0.041177075491445), FRAC_CONST(0.081472583040586)}, {FRAC_CONST(0.039030261541332), FRAC_CONST(0.082522554597810)}, {FRAC_CONST(0.036856698199564), FRAC_CONST(0.083515969318206)}, + {FRAC_CONST(0.034657875117883), FRAC_CONST(0.084452146364948)}, {FRAC_CONST(0.032435299259796), FRAC_CONST(0.085330444129049)}, {FRAC_CONST(0.030190493867775), FRAC_CONST(0.086150260669096)}, + {FRAC_CONST(0.027924997419306), FRAC_CONST(0.086911034123781)}, {FRAC_CONST(0.025640362572491), FRAC_CONST(0.087612243096981)}, {FRAC_CONST(0.023338155101933), FRAC_CONST(0.088253407015092)}, + {FRAC_CONST(0.021019952825636), FRAC_CONST(0.088834086456390)}, {FRAC_CONST(0.018687344523641), FRAC_CONST(0.089353883452193)}, {FRAC_CONST(0.016341928849164), FRAC_CONST(0.089812441759604)}, + {FRAC_CONST(0.013985313232951), FRAC_CONST(0.090209447105664)}, {FRAC_CONST(0.011619112781631), FRAC_CONST(0.090544627402740)}, {FRAC_CONST(0.009244949170797), FRAC_CONST(0.090817752935000)}, + {FRAC_CONST(0.006864449533597), FRAC_CONST(0.091028636515846)}, {FRAC_CONST(0.004479245345574), FRAC_CONST(0.091177133616206)}, {FRAC_CONST(0.002090971306534), FRAC_CONST(0.091263142463585)}}; + #endif // ALLOW_SMALL_FRAMELENGTH + #ifdef SSR_DEC +/* 128 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_512[] = { + {FRAC_CONST(0.062499926465731), FRAC_CONST(0.000095873761643)}, {FRAC_CONST(0.062494043817678), FRAC_CONST(0.000862836783004)}, {FRAC_CONST(0.062478749796497), FRAC_CONST(0.001629669864319)}, + {FRAC_CONST(0.062454046705412), FRAC_CONST(0.002396257523347)}, {FRAC_CONST(0.062419938264617), FRAC_CONST(0.003162484314806)}, {FRAC_CONST(0.062376429610718), FRAC_CONST(0.003928234847760)}, + {FRAC_CONST(0.062323527295958), FRAC_CONST(0.004693393802995)}, {FRAC_CONST(0.062261239287231), FRAC_CONST(0.005457845950387)}, {FRAC_CONST(0.062189574964882), FRAC_CONST(0.006221476166254)}, + {FRAC_CONST(0.062108545121295), FRAC_CONST(0.006984169450695)}, {FRAC_CONST(0.062018161959266), FRAC_CONST(0.007745810944907)}, {FRAC_CONST(0.061918439090167), FRAC_CONST(0.008506285948482)}, + {FRAC_CONST(0.061809391531894), FRAC_CONST(0.009265479936681)}, {FRAC_CONST(0.061691035706609), FRAC_CONST(0.010023278577683)}, {FRAC_CONST(0.061563389438265), FRAC_CONST(0.010779567749800)}, + {FRAC_CONST(0.061426471949919), FRAC_CONST(0.011534233558664)}, {FRAC_CONST(0.061280303860842), FRAC_CONST(0.012287162354380)}, {FRAC_CONST(0.061124907183410), FRAC_CONST(0.013038240748641)}, + {FRAC_CONST(0.060960305319791), FRAC_CONST(0.013787355631805)}, {FRAC_CONST(0.060786523058421), FRAC_CONST(0.014534394189923)}, {FRAC_CONST(0.060603586570268), FRAC_CONST(0.015279243921739)}, + {FRAC_CONST(0.060411523404896), FRAC_CONST(0.016021792655621)}, {FRAC_CONST(0.060210362486310), FRAC_CONST(0.016761928566463)}, {FRAC_CONST(0.060000134108604), FRAC_CONST(0.017499540192517)}, + {FRAC_CONST(0.059780869931400), FRAC_CONST(0.018234516452187)}, {FRAC_CONST(0.059552602975075), FRAC_CONST(0.018966746660751)}, {FRAC_CONST(0.059315367615794), FRAC_CONST(0.019696120547033)}, + {FRAC_CONST(0.059069199580329), FRAC_CONST(0.020422528270008)}, {FRAC_CONST(0.058814135940681), FRAC_CONST(0.021145860435346)}, {FRAC_CONST(0.058550215108495), FRAC_CONST(0.021866008111883)}, + {FRAC_CONST(0.058277476829279), FRAC_CONST(0.022582862848028)}, {FRAC_CONST(0.057995962176414), FRAC_CONST(0.023296316688095)}, {FRAC_CONST(0.057705713544970), FRAC_CONST(0.024006262188558)}, + {FRAC_CONST(0.057406774645326), FRAC_CONST(0.024712592434239)}, {FRAC_CONST(0.057099190496578), FRAC_CONST(0.025415201054398)}, {FRAC_CONST(0.056783007419769), FRAC_CONST(0.026113982238763)}, + {FRAC_CONST(0.056458273030907), FRAC_CONST(0.026808830753458)}, {FRAC_CONST(0.056125036233796), FRAC_CONST(0.027499641956852)}, {FRAC_CONST(0.055783347212673), FRAC_CONST(0.028186311815319)}, + {FRAC_CONST(0.055433257424646), FRAC_CONST(0.028868736918904)}, {FRAC_CONST(0.055074819591951), FRAC_CONST(0.029546814496896)}, {FRAC_CONST(0.054708087694007), FRAC_CONST(0.030220442433307)}, + {FRAC_CONST(0.054333116959288), FRAC_CONST(0.030889519282247)}, {FRAC_CONST(0.053949963857008), FRAC_CONST(0.031553944283204)}, {FRAC_CONST(0.053558686088614), FRAC_CONST(0.032213617376216)}, + {FRAC_CONST(0.053159342579100), FRAC_CONST(0.032868439216943)}, {FRAC_CONST(0.052751993468129), FRAC_CONST(0.033518311191623)}, {FRAC_CONST(0.052336700100979), FRAC_CONST(0.034163135431927)}, + {FRAC_CONST(0.051913525019303), FRAC_CONST(0.034802814829698)}, {FRAC_CONST(0.051482531951712), FRAC_CONST(0.035437253051569)}, {FRAC_CONST(0.051043785804177), FRAC_CONST(0.036066354553480)}, + {FRAC_CONST(0.050597352650253), FRAC_CONST(0.036690024595057)}, {FRAC_CONST(0.050143299721132), FRAC_CONST(0.037308169253887)}, {FRAC_CONST(0.049681695395515), FRAC_CONST(0.037920695439658)}, + {FRAC_CONST(0.049212609189314), FRAC_CONST(0.038527510908178)}, {FRAC_CONST(0.048736111745188), FRAC_CONST(0.039128524275271)}, {FRAC_CONST(0.048252274821899), FRAC_CONST(0.039723645030535)}, + {FRAC_CONST(0.047761171283507), FRAC_CONST(0.040312783550971)}, {FRAC_CONST(0.047262875088400), FRAC_CONST(0.040895851114488)}, {FRAC_CONST(0.046757461278150), FRAC_CONST(0.041472759913252)}, + {FRAC_CONST(0.046245005966220), FRAC_CONST(0.042043423066923)}, {FRAC_CONST(0.045725586326493), FRAC_CONST(0.042607754635728)}, {FRAC_CONST(0.045199280581658), FRAC_CONST(0.043165669633408)}, + {FRAC_CONST(0.044666167991423), FRAC_CONST(0.043717084040018)}, {FRAC_CONST(0.044126328840584), FRAC_CONST(0.044261914814575)}, {FRAC_CONST(0.043579844426930), FRAC_CONST(0.044800079907569)}, + {FRAC_CONST(0.043026797049006), FRAC_CONST(0.045331498273316)}, {FRAC_CONST(0.042467269993710), FRAC_CONST(0.045856089882166)}, {FRAC_CONST(0.041901347523761), FRAC_CONST(0.046373775732552)}, + {FRAC_CONST(0.041329114865000), FRAC_CONST(0.046884477862888)}, {FRAC_CONST(0.040750658193560), FRAC_CONST(0.047388119363313)}, {FRAC_CONST(0.040166064622889), FRAC_CONST(0.047884624387270)}, + {FRAC_CONST(0.039575422190629), FRAC_CONST(0.048373918162926)}, {FRAC_CONST(0.038978819845356), FRAC_CONST(0.048855927004441)}, {FRAC_CONST(0.038376347433190), FRAC_CONST(0.049330578323055)}, + {FRAC_CONST(0.037768095684260), FRAC_CONST(0.049797800638026)}, {FRAC_CONST(0.037154156199042), FRAC_CONST(0.050257523587392)}, {FRAC_CONST(0.036534621434563), FRAC_CONST(0.050709677938566)}, + {FRAC_CONST(0.035909584690482), FRAC_CONST(0.051154195598769)}, {FRAC_CONST(0.035279140095032), FRAC_CONST(0.051591009625274)}, {FRAC_CONST(0.034643382590851), FRAC_CONST(0.052020054235496)}, + {FRAC_CONST(0.034002407920680), FRAC_CONST(0.052441264816895)}, {FRAC_CONST(0.033356312612947), FRAC_CONST(0.052854577936706)}, {FRAC_CONST(0.032705193967229), FRAC_CONST(0.053259931351495)}, + {FRAC_CONST(0.032049150039598), FRAC_CONST(0.053657264016528)}, {FRAC_CONST(0.031388279627857), FRAC_CONST(0.054046516094966)}, {FRAC_CONST(0.030722682256659), FRAC_CONST(0.054427628966880)}, + {FRAC_CONST(0.030052458162521), FRAC_CONST(0.054800545238072)}, {FRAC_CONST(0.029377708278725), FRAC_CONST(0.055165208748723)}, {FRAC_CONST(0.028698534220122), FRAC_CONST(0.055521564581850)}, + {FRAC_CONST(0.028015038267826), FRAC_CONST(0.055869559071575)}, {FRAC_CONST(0.027327323353815), FRAC_CONST(0.056209139811209)}, {FRAC_CONST(0.026635493045425), FRAC_CONST(0.056540255661140)}, + {FRAC_CONST(0.025939651529755), FRAC_CONST(0.056862856756541)}, {FRAC_CONST(0.025239903597978), FRAC_CONST(0.057176894514872)}, {FRAC_CONST(0.024536354629559), FRAC_CONST(0.057482321643202)}, + {FRAC_CONST(0.023829110576385), FRAC_CONST(0.057779092145329)}, {FRAC_CONST(0.023118277946808), FRAC_CONST(0.058067161328707)}, {FRAC_CONST(0.022403963789609), FRAC_CONST(0.058346485811177)}, + {FRAC_CONST(0.021686275677870), FRAC_CONST(0.058617023527499)}, {FRAC_CONST(0.020965321692783), FRAC_CONST(0.058878733735689)}, {FRAC_CONST(0.020241210407366), FRAC_CONST(0.059131577023150)}, + {FRAC_CONST(0.019514050870114), FRAC_CONST(0.059375515312615)}, {FRAC_CONST(0.018783952588580), FRAC_CONST(0.059610511867874)}, {FRAC_CONST(0.018051025512878), FRAC_CONST(0.059836531299311)}, + {FRAC_CONST(0.017315380019131), FRAC_CONST(0.060053539569230)}, {FRAC_CONST(0.016577126892844), FRAC_CONST(0.060261503996984)}, {FRAC_CONST(0.015836377312223), FRAC_CONST(0.060460393263896)}, + {FRAC_CONST(0.015093242831429), FRAC_CONST(0.060650177417972)}, {FRAC_CONST(0.014347835363782), FRAC_CONST(0.060830827878419)}, {FRAC_CONST(0.013600267164905), FRAC_CONST(0.061002317439940)}, + {FRAC_CONST(0.012850650815819), FRAC_CONST(0.061164620276839)}, {FRAC_CONST(0.012099099205988), FRAC_CONST(0.061317711946905)}, {FRAC_CONST(0.011345725516320), FRAC_CONST(0.061461569395097)}, + {FRAC_CONST(0.010590643202123), FRAC_CONST(0.061596170957011)}, {FRAC_CONST(0.009833965976015), FRAC_CONST(0.061721496362147)}, {FRAC_CONST(0.009075807790803), FRAC_CONST(0.061837526736961)}, + {FRAC_CONST(0.008316282822321), FRAC_CONST(0.061944244607705)}, {FRAC_CONST(0.007555505452236), FRAC_CONST(0.062041633903059)}, {FRAC_CONST(0.006793590250821), FRAC_CONST(0.062129679956555)}, + {FRAC_CONST(0.006030651959703), FRAC_CONST(0.062208369508780)}, {FRAC_CONST(0.005266805474583), FRAC_CONST(0.062277690709378)}, {FRAC_CONST(0.004502165827931), FRAC_CONST(0.062337633118830)}, + {FRAC_CONST(0.003736848171665), FRAC_CONST(0.062388187710030)}, {FRAC_CONST(0.002970967759810), FRAC_CONST(0.062429346869643)}, {FRAC_CONST(0.002204639931138), FRAC_CONST(0.062461104399250)}, + {FRAC_CONST(0.001437980091802), FRAC_CONST(0.062483455516285)}, {FRAC_CONST(0.000671103697954), FRAC_CONST(0.062496396854751)}}; +/* 16 (N/4) complex twiddle factors */ +static const complex_t mdct_tab_64[] = { + {FRAC_CONST(0.176763384336599), FRAC_CONST(0.002169321984356)}, {FRAC_CONST(0.175699589589310), FRAC_CONST(0.019484717553714)}, {FRAC_CONST(0.172943711747111), FRAC_CONST(0.036612464641599)}, + {FRAC_CONST(0.168522291420137), FRAC_CONST(0.053387613680577)}, {FRAC_CONST(0.162477909303132), FRAC_CONST(0.069648610815172)}, {FRAC_CONST(0.154868776100077), FRAC_CONST(0.085238853753814)}, + {FRAC_CONST(0.145768171923295), FRAC_CONST(0.100008199934509)}, {FRAC_CONST(0.135263740565902), FRAC_CONST(0.113814412479792)}, {FRAC_CONST(0.123456645444178), FRAC_CONST(0.126524530015608)}, + {FRAC_CONST(0.110460595338559), FRAC_CONST(0.138016147162030)}, {FRAC_CONST(0.096400749315926), FRAC_CONST(0.148178593363981)}, {FRAC_CONST(0.081412511379371), FRAC_CONST(0.156913998709178)}, + {FRAC_CONST(0.065640226453626), FRAC_CONST(0.164138236468888)}, {FRAC_CONST(0.049235790264535), FRAC_CONST(0.169781733284316)}, {FRAC_CONST(0.032357186500177), FRAC_CONST(0.173790139196080)}, + {FRAC_CONST(0.015166965341583), FRAC_CONST(0.176124851064031)}}; + #endif // SSR_DEC +#endif // FIXED_POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t kbd_long_1024[] = { + FRAC_CONST(0.00029256153896361), FRAC_CONST(0.00042998567353047), FRAC_CONST(0.00054674074589540), FRAC_CONST(0.00065482304299792), FRAC_CONST(0.00075870195068747), + FRAC_CONST(0.00086059331713336), FRAC_CONST(0.00096177541439010), FRAC_CONST(0.0010630609410878), FRAC_CONST(0.0011650036308132), FRAC_CONST(0.0012680012194148), + FRAC_CONST(0.0013723517232956), FRAC_CONST(0.0014782864109136), FRAC_CONST(0.0015859901976719), FRAC_CONST(0.0016956148252373), FRAC_CONST(0.0018072876903517), + FRAC_CONST(0.0019211179405514), FRAC_CONST(0.0020372007924215), FRAC_CONST(0.0021556206591754), FRAC_CONST(0.0022764534599614), FRAC_CONST(0.0023997683540995), + FRAC_CONST(0.0025256290631156), FRAC_CONST(0.0026540948920831), FRAC_CONST(0.0027852215281403), FRAC_CONST(0.0029190616715331), FRAC_CONST(0.0030556655443223), + FRAC_CONST(0.0031950812943391), FRAC_CONST(0.0033373553240392), FRAC_CONST(0.0034825325586930), FRAC_CONST(0.0036306566699199), FRAC_CONST(0.0037817702604646), + FRAC_CONST(0.0039359150179719), FRAC_CONST(0.0040931318437260), FRAC_CONST(0.0042534609610026), FRAC_CONST(0.0044169420066964), FRAC_CONST(0.0045836141091341), + FRAC_CONST(0.0047535159544086), FRAC_CONST(0.0049266858431214), FRAC_CONST(0.0051031617390698), FRAC_CONST(0.0052829813111335), FRAC_CONST(0.0054661819693975), + FRAC_CONST(0.0056528008963682), FRAC_CONST(0.0058428750739943), FRAC_CONST(0.0060364413070882), FRAC_CONST(0.0062335362436492), FRAC_CONST(0.0064341963925079), + FRAC_CONST(0.0066384581386503), FRAC_CONST(0.0068463577565218), FRAC_CONST(0.0070579314215715), FRAC_CONST(0.0072732152202559), FRAC_CONST(0.0074922451586909), + FRAC_CONST(0.0077150571701162), FRAC_CONST(0.0079416871213115), FRAC_CONST(0.0081721708180857), FRAC_CONST(0.0084065440099458), FRAC_CONST(0.0086448423940363), + FRAC_CONST(0.0088871016184291), FRAC_CONST(0.0091333572848345), FRAC_CONST(0.0093836449507939), FRAC_CONST(0.0096380001314086), FRAC_CONST(0.0098964583006517), + FRAC_CONST(0.010159054892306), FRAC_CONST(0.010425825300561), FRAC_CONST(0.010696804880310), FRAC_CONST(0.010972028947167), FRAC_CONST(0.011251532777236), + FRAC_CONST(0.011535351606646), FRAC_CONST(0.011823520630897), FRAC_CONST(0.012116075003993), FRAC_CONST(0.012413049837429), FRAC_CONST(0.012714480198999), + FRAC_CONST(0.013020401111478), FRAC_CONST(0.013330847551161), FRAC_CONST(0.013645854446288), FRAC_CONST(0.013965456675352), FRAC_CONST(0.014289689065314), + FRAC_CONST(0.014618586389712), FRAC_CONST(0.014952183366697), FRAC_CONST(0.015290514656976), FRAC_CONST(0.015633614861688), FRAC_CONST(0.015981518520214), + FRAC_CONST(0.016334260107915), FRAC_CONST(0.016691874033817), FRAC_CONST(0.017054394638241), FRAC_CONST(0.017421856190380), FRAC_CONST(0.017794292885832), + FRAC_CONST(0.018171738844085), FRAC_CONST(0.018554228105962), FRAC_CONST(0.018941794631032), FRAC_CONST(0.019334472294980), FRAC_CONST(0.019732294886947), + FRAC_CONST(0.020135296106839), FRAC_CONST(0.020543509562604), FRAC_CONST(0.020956968767488), FRAC_CONST(0.021375707137257), FRAC_CONST(0.021799757987407), + FRAC_CONST(0.022229154530343), FRAC_CONST(0.022663929872540), FRAC_CONST(0.023104117011689), FRAC_CONST(0.023549748833816), FRAC_CONST(0.024000858110398), + FRAC_CONST(0.024457477495451), FRAC_CONST(0.024919639522613), FRAC_CONST(0.025387376602207), FRAC_CONST(0.025860721018295), FRAC_CONST(0.026339704925726), + FRAC_CONST(0.026824360347160), FRAC_CONST(0.027314719170100), FRAC_CONST(0.027810813143900), FRAC_CONST(0.028312673876775), FRAC_CONST(0.028820332832801), + FRAC_CONST(0.029333821328905), FRAC_CONST(0.029853170531859), FRAC_CONST(0.030378411455255), FRAC_CONST(0.030909574956490), FRAC_CONST(0.031446691733739), + FRAC_CONST(0.031989792322926), FRAC_CONST(0.032538907094693), FRAC_CONST(0.033094066251369), FRAC_CONST(0.033655299823935), FRAC_CONST(0.034222637668991), + FRAC_CONST(0.034796109465717), FRAC_CONST(0.035375744712844), FRAC_CONST(0.035961572725616), FRAC_CONST(0.036553622632758), FRAC_CONST(0.037151923373446), + FRAC_CONST(0.037756503694277), FRAC_CONST(0.038367392146243), FRAC_CONST(0.038984617081711), FRAC_CONST(0.039608206651398), FRAC_CONST(0.040238188801359), + FRAC_CONST(0.040874591269976), FRAC_CONST(0.041517441584950), FRAC_CONST(0.042166767060301), FRAC_CONST(0.042822594793376), FRAC_CONST(0.043484951661852), + FRAC_CONST(0.044153864320760), FRAC_CONST(0.044829359199509), FRAC_CONST(0.045511462498913), FRAC_CONST(0.046200200188234), FRAC_CONST(0.046895598002228), + FRAC_CONST(0.047597681438201), FRAC_CONST(0.048306475753074), FRAC_CONST(0.049022005960455), FRAC_CONST(0.049744296827725), FRAC_CONST(0.050473372873129), + FRAC_CONST(0.051209258362879), FRAC_CONST(0.051951977308273), FRAC_CONST(0.052701553462813), FRAC_CONST(0.053458010319350), FRAC_CONST(0.054221371107223), + FRAC_CONST(0.054991658789428), FRAC_CONST(0.055768896059787), FRAC_CONST(0.056553105340134), FRAC_CONST(0.057344308777513), FRAC_CONST(0.058142528241393), + FRAC_CONST(0.058947785320893), FRAC_CONST(0.059760101322019), FRAC_CONST(0.060579497264926), FRAC_CONST(0.061405993881180), FRAC_CONST(0.062239611611049), + FRAC_CONST(0.063080370600799), FRAC_CONST(0.063928290700012), FRAC_CONST(0.064783391458919), FRAC_CONST(0.065645692125747), FRAC_CONST(0.066515211644086), + FRAC_CONST(0.067391968650269), FRAC_CONST(0.068275981470777), FRAC_CONST(0.069167268119652), FRAC_CONST(0.070065846295935), FRAC_CONST(0.070971733381121), + FRAC_CONST(0.071884946436630), FRAC_CONST(0.072805502201299), FRAC_CONST(0.073733417088896), FRAC_CONST(0.074668707185649), FRAC_CONST(0.075611388247794), + FRAC_CONST(0.076561475699152), FRAC_CONST(0.077518984628715), FRAC_CONST(0.078483929788261), FRAC_CONST(0.079456325589986), FRAC_CONST(0.080436186104162), + FRAC_CONST(0.081423525056808), FRAC_CONST(0.082418355827392), FRAC_CONST(0.083420691446553), FRAC_CONST(0.084430544593841), FRAC_CONST(0.085447927595483), + FRAC_CONST(0.086472852422178), FRAC_CONST(0.087505330686900), FRAC_CONST(0.088545373642744), FRAC_CONST(0.089592992180780), FRAC_CONST(0.090648196827937), + FRAC_CONST(0.091710997744919), FRAC_CONST(0.092781404724131), FRAC_CONST(0.093859427187640), FRAC_CONST(0.094945074185163), FRAC_CONST(0.096038354392069), + FRAC_CONST(0.097139276107423), FRAC_CONST(0.098247847252041), FRAC_CONST(0.099364075366580), FRAC_CONST(0.10048796760965), FRAC_CONST(0.10161953075597), + FRAC_CONST(0.10275877119451), FRAC_CONST(0.10390569492671), FRAC_CONST(0.10506030756469), FRAC_CONST(0.10622261432949), FRAC_CONST(0.10739262004941), + FRAC_CONST(0.10857032915821), FRAC_CONST(0.10975574569357), FRAC_CONST(0.11094887329534), FRAC_CONST(0.11214971520402), FRAC_CONST(0.11335827425914), + FRAC_CONST(0.11457455289772), FRAC_CONST(0.11579855315274), FRAC_CONST(0.11703027665170), FRAC_CONST(0.11826972461510), FRAC_CONST(0.11951689785504), + FRAC_CONST(0.12077179677383), FRAC_CONST(0.12203442136263), FRAC_CONST(0.12330477120008), FRAC_CONST(0.12458284545102), FRAC_CONST(0.12586864286523), + FRAC_CONST(0.12716216177615), FRAC_CONST(0.12846340009971), FRAC_CONST(0.12977235533312), FRAC_CONST(0.13108902455375), FRAC_CONST(0.13241340441801), + FRAC_CONST(0.13374549116025), FRAC_CONST(0.13508528059173), FRAC_CONST(0.13643276809961), FRAC_CONST(0.13778794864595), FRAC_CONST(0.13915081676677), + FRAC_CONST(0.14052136657114), FRAC_CONST(0.14189959174027), FRAC_CONST(0.14328548552671), FRAC_CONST(0.14467904075349), FRAC_CONST(0.14608024981336), + FRAC_CONST(0.14748910466804), FRAC_CONST(0.14890559684750), FRAC_CONST(0.15032971744929), FRAC_CONST(0.15176145713790), FRAC_CONST(0.15320080614414), + FRAC_CONST(0.15464775426459), FRAC_CONST(0.15610229086100), FRAC_CONST(0.15756440485987), FRAC_CONST(0.15903408475193), FRAC_CONST(0.16051131859170), + FRAC_CONST(0.16199609399712), FRAC_CONST(0.16348839814917), FRAC_CONST(0.16498821779156), FRAC_CONST(0.16649553923042), FRAC_CONST(0.16801034833404), + FRAC_CONST(0.16953263053270), FRAC_CONST(0.17106237081842), FRAC_CONST(0.17259955374484), FRAC_CONST(0.17414416342714), FRAC_CONST(0.17569618354193), + FRAC_CONST(0.17725559732720), FRAC_CONST(0.17882238758238), FRAC_CONST(0.18039653666830), FRAC_CONST(0.18197802650733), FRAC_CONST(0.18356683858343), + FRAC_CONST(0.18516295394233), FRAC_CONST(0.18676635319174), FRAC_CONST(0.18837701650148), FRAC_CONST(0.18999492360384), FRAC_CONST(0.19162005379380), + FRAC_CONST(0.19325238592940), FRAC_CONST(0.19489189843209), FRAC_CONST(0.19653856928714), FRAC_CONST(0.19819237604409), FRAC_CONST(0.19985329581721), + FRAC_CONST(0.20152130528605), FRAC_CONST(0.20319638069594), FRAC_CONST(0.20487849785865), FRAC_CONST(0.20656763215298), FRAC_CONST(0.20826375852540), + FRAC_CONST(0.20996685149083), FRAC_CONST(0.21167688513330), FRAC_CONST(0.21339383310678), FRAC_CONST(0.21511766863598), FRAC_CONST(0.21684836451719), + FRAC_CONST(0.21858589311922), FRAC_CONST(0.22033022638425), FRAC_CONST(0.22208133582887), FRAC_CONST(0.22383919254503), FRAC_CONST(0.22560376720111), + FRAC_CONST(0.22737503004300), FRAC_CONST(0.22915295089517), FRAC_CONST(0.23093749916189), FRAC_CONST(0.23272864382838), FRAC_CONST(0.23452635346201), + FRAC_CONST(0.23633059621364), FRAC_CONST(0.23814133981883), FRAC_CONST(0.23995855159925), FRAC_CONST(0.24178219846403), FRAC_CONST(0.24361224691114), + FRAC_CONST(0.24544866302890), FRAC_CONST(0.24729141249740), FRAC_CONST(0.24914046059007), FRAC_CONST(0.25099577217522), FRAC_CONST(0.25285731171763), + FRAC_CONST(0.25472504328019), FRAC_CONST(0.25659893052556), FRAC_CONST(0.25847893671788), FRAC_CONST(0.26036502472451), FRAC_CONST(0.26225715701781), + FRAC_CONST(0.26415529567692), FRAC_CONST(0.26605940238966), FRAC_CONST(0.26796943845439), FRAC_CONST(0.26988536478190), FRAC_CONST(0.27180714189742), + FRAC_CONST(0.27373472994256), FRAC_CONST(0.27566808867736), FRAC_CONST(0.27760717748238), FRAC_CONST(0.27955195536071), FRAC_CONST(0.28150238094021), + FRAC_CONST(0.28345841247557), FRAC_CONST(0.28542000785059), FRAC_CONST(0.28738712458038), FRAC_CONST(0.28935971981364), FRAC_CONST(0.29133775033492), + FRAC_CONST(0.29332117256704), FRAC_CONST(0.29530994257338), FRAC_CONST(0.29730401606034), FRAC_CONST(0.29930334837974), FRAC_CONST(0.30130789453132), + FRAC_CONST(0.30331760916521), FRAC_CONST(0.30533244658452), FRAC_CONST(0.30735236074785), FRAC_CONST(0.30937730527195), FRAC_CONST(0.31140723343430), + FRAC_CONST(0.31344209817583), FRAC_CONST(0.31548185210356), FRAC_CONST(0.31752644749341), FRAC_CONST(0.31957583629288), FRAC_CONST(0.32162997012390), + FRAC_CONST(0.32368880028565), FRAC_CONST(0.32575227775738), FRAC_CONST(0.32782035320134), FRAC_CONST(0.32989297696566), FRAC_CONST(0.33197009908736), + FRAC_CONST(0.33405166929523), FRAC_CONST(0.33613763701295), FRAC_CONST(0.33822795136203), FRAC_CONST(0.34032256116495), FRAC_CONST(0.34242141494820), + FRAC_CONST(0.34452446094547), FRAC_CONST(0.34663164710072), FRAC_CONST(0.34874292107143), FRAC_CONST(0.35085823023181), FRAC_CONST(0.35297752167598), + FRAC_CONST(0.35510074222129), FRAC_CONST(0.35722783841160), FRAC_CONST(0.35935875652060), FRAC_CONST(0.36149344255514), FRAC_CONST(0.36363184225864), + FRAC_CONST(0.36577390111444), FRAC_CONST(0.36791956434930), FRAC_CONST(0.37006877693676), FRAC_CONST(0.37222148360070), FRAC_CONST(0.37437762881878), + FRAC_CONST(0.37653715682603), FRAC_CONST(0.37870001161834), FRAC_CONST(0.38086613695607), FRAC_CONST(0.38303547636766), FRAC_CONST(0.38520797315322), + FRAC_CONST(0.38738357038821), FRAC_CONST(0.38956221092708), FRAC_CONST(0.39174383740701), FRAC_CONST(0.39392839225157), FRAC_CONST(0.39611581767449), + FRAC_CONST(0.39830605568342), FRAC_CONST(0.40049904808370), FRAC_CONST(0.40269473648218), FRAC_CONST(0.40489306229101), FRAC_CONST(0.40709396673153), + FRAC_CONST(0.40929739083810), FRAC_CONST(0.41150327546197), FRAC_CONST(0.41371156127524), FRAC_CONST(0.41592218877472), FRAC_CONST(0.41813509828594), + FRAC_CONST(0.42035022996702), FRAC_CONST(0.42256752381274), FRAC_CONST(0.42478691965848), FRAC_CONST(0.42700835718423), FRAC_CONST(0.42923177591866), + FRAC_CONST(0.43145711524314), FRAC_CONST(0.43368431439580), FRAC_CONST(0.43591331247564), FRAC_CONST(0.43814404844658), FRAC_CONST(0.44037646114161), + FRAC_CONST(0.44261048926688), FRAC_CONST(0.44484607140589), FRAC_CONST(0.44708314602359), FRAC_CONST(0.44932165147057), FRAC_CONST(0.45156152598727), + FRAC_CONST(0.45380270770813), FRAC_CONST(0.45604513466581), FRAC_CONST(0.45828874479543), FRAC_CONST(0.46053347593880), FRAC_CONST(0.46277926584861), + FRAC_CONST(0.46502605219277), FRAC_CONST(0.46727377255861), FRAC_CONST(0.46952236445718), FRAC_CONST(0.47177176532752), FRAC_CONST(0.47402191254100), + FRAC_CONST(0.47627274340557), FRAC_CONST(0.47852419517009), FRAC_CONST(0.48077620502869), FRAC_CONST(0.48302871012505), FRAC_CONST(0.48528164755674), + FRAC_CONST(0.48753495437962), FRAC_CONST(0.48978856761212), FRAC_CONST(0.49204242423966), FRAC_CONST(0.49429646121898), FRAC_CONST(0.49655061548250), + FRAC_CONST(0.49880482394273), FRAC_CONST(0.50105902349665), FRAC_CONST(0.50331315103004), FRAC_CONST(0.50556714342194), FRAC_CONST(0.50782093754901), + FRAC_CONST(0.51007447028990), FRAC_CONST(0.51232767852971), FRAC_CONST(0.51458049916433), FRAC_CONST(0.51683286910489), FRAC_CONST(0.51908472528213), + FRAC_CONST(0.52133600465083), FRAC_CONST(0.52358664419420), FRAC_CONST(0.52583658092832), FRAC_CONST(0.52808575190648), FRAC_CONST(0.53033409422367), + FRAC_CONST(0.53258154502092), FRAC_CONST(0.53482804148974), FRAC_CONST(0.53707352087652), FRAC_CONST(0.53931792048690), FRAC_CONST(0.54156117769021), + FRAC_CONST(0.54380322992385), FRAC_CONST(0.54604401469766), FRAC_CONST(0.54828346959835), FRAC_CONST(0.55052153229384), FRAC_CONST(0.55275814053768), + FRAC_CONST(0.55499323217338), FRAC_CONST(0.55722674513883), FRAC_CONST(0.55945861747062), FRAC_CONST(0.56168878730842), FRAC_CONST(0.56391719289930), + FRAC_CONST(0.56614377260214), FRAC_CONST(0.56836846489188), FRAC_CONST(0.57059120836390), FRAC_CONST(0.57281194173835), FRAC_CONST(0.57503060386439), + FRAC_CONST(0.57724713372458), FRAC_CONST(0.57946147043912), FRAC_CONST(0.58167355327012), FRAC_CONST(0.58388332162591), FRAC_CONST(0.58609071506528), + FRAC_CONST(0.58829567330173), FRAC_CONST(0.59049813620770), FRAC_CONST(0.59269804381879), FRAC_CONST(0.59489533633802), FRAC_CONST(0.59708995413996), + FRAC_CONST(0.59928183777495), FRAC_CONST(0.60147092797329), FRAC_CONST(0.60365716564937), FRAC_CONST(0.60584049190582), FRAC_CONST(0.60802084803764), + FRAC_CONST(0.61019817553632), FRAC_CONST(0.61237241609393), FRAC_CONST(0.61454351160718), FRAC_CONST(0.61671140418155), FRAC_CONST(0.61887603613527), + FRAC_CONST(0.62103735000336), FRAC_CONST(0.62319528854167), FRAC_CONST(0.62534979473088), FRAC_CONST(0.62750081178042), FRAC_CONST(0.62964828313250), + FRAC_CONST(0.63179215246597), FRAC_CONST(0.63393236370030), FRAC_CONST(0.63606886099946), FRAC_CONST(0.63820158877577), FRAC_CONST(0.64033049169379), + FRAC_CONST(0.64245551467413), FRAC_CONST(0.64457660289729), FRAC_CONST(0.64669370180740), FRAC_CONST(0.64880675711607), FRAC_CONST(0.65091571480603), + FRAC_CONST(0.65302052113494), FRAC_CONST(0.65512112263906), FRAC_CONST(0.65721746613689), FRAC_CONST(0.65930949873289), FRAC_CONST(0.66139716782102), + FRAC_CONST(0.66348042108842), FRAC_CONST(0.66555920651892), FRAC_CONST(0.66763347239664), FRAC_CONST(0.66970316730947), FRAC_CONST(0.67176824015260), + FRAC_CONST(0.67382864013196), FRAC_CONST(0.67588431676768), FRAC_CONST(0.67793521989751), FRAC_CONST(0.67998129968017), FRAC_CONST(0.68202250659876), + FRAC_CONST(0.68405879146403), FRAC_CONST(0.68609010541774), FRAC_CONST(0.68811639993588), FRAC_CONST(0.69013762683195), FRAC_CONST(0.69215373826012), + FRAC_CONST(0.69416468671849), FRAC_CONST(0.69617042505214), FRAC_CONST(0.69817090645634), FRAC_CONST(0.70016608447958), FRAC_CONST(0.70215591302664), + FRAC_CONST(0.70414034636163), FRAC_CONST(0.70611933911096), FRAC_CONST(0.70809284626630), FRAC_CONST(0.71006082318751), FRAC_CONST(0.71202322560554), + FRAC_CONST(0.71398000962530), FRAC_CONST(0.71593113172842), FRAC_CONST(0.71787654877613), FRAC_CONST(0.71981621801195), FRAC_CONST(0.72175009706445), + FRAC_CONST(0.72367814394990), FRAC_CONST(0.72560031707496), FRAC_CONST(0.72751657523927), FRAC_CONST(0.72942687763803), FRAC_CONST(0.73133118386457), + FRAC_CONST(0.73322945391280), FRAC_CONST(0.73512164817975), FRAC_CONST(0.73700772746796), FRAC_CONST(0.73888765298787), FRAC_CONST(0.74076138636020), + FRAC_CONST(0.74262888961827), FRAC_CONST(0.74449012521027), FRAC_CONST(0.74634505600152), FRAC_CONST(0.74819364527663), FRAC_CONST(0.75003585674175), + FRAC_CONST(0.75187165452661), FRAC_CONST(0.75370100318668), FRAC_CONST(0.75552386770515), FRAC_CONST(0.75734021349500), FRAC_CONST(0.75915000640095), + FRAC_CONST(0.76095321270137), FRAC_CONST(0.76274979911019), FRAC_CONST(0.76453973277875), FRAC_CONST(0.76632298129757), FRAC_CONST(0.76809951269819), + FRAC_CONST(0.76986929545481), FRAC_CONST(0.77163229848604), FRAC_CONST(0.77338849115651), FRAC_CONST(0.77513784327849), FRAC_CONST(0.77688032511340), + FRAC_CONST(0.77861590737340), FRAC_CONST(0.78034456122283), FRAC_CONST(0.78206625827961), FRAC_CONST(0.78378097061667), FRAC_CONST(0.78548867076330), + FRAC_CONST(0.78718933170643), FRAC_CONST(0.78888292689189), FRAC_CONST(0.79056943022564), FRAC_CONST(0.79224881607494), FRAC_CONST(0.79392105926949), + FRAC_CONST(0.79558613510249), FRAC_CONST(0.79724401933170), FRAC_CONST(0.79889468818046), FRAC_CONST(0.80053811833858), FRAC_CONST(0.80217428696334), + FRAC_CONST(0.80380317168028), FRAC_CONST(0.80542475058405), FRAC_CONST(0.80703900223920), FRAC_CONST(0.80864590568089), FRAC_CONST(0.81024544041560), + FRAC_CONST(0.81183758642175), FRAC_CONST(0.81342232415032), FRAC_CONST(0.81499963452540), FRAC_CONST(0.81656949894467), FRAC_CONST(0.81813189927991), + FRAC_CONST(0.81968681787738), FRAC_CONST(0.82123423755821), FRAC_CONST(0.82277414161874), FRAC_CONST(0.82430651383076), FRAC_CONST(0.82583133844180), + FRAC_CONST(0.82734860017528), FRAC_CONST(0.82885828423070), FRAC_CONST(0.83036037628369), FRAC_CONST(0.83185486248609), FRAC_CONST(0.83334172946597), + FRAC_CONST(0.83482096432759), FRAC_CONST(0.83629255465130), FRAC_CONST(0.83775648849344), FRAC_CONST(0.83921275438615), FRAC_CONST(0.84066134133716), + FRAC_CONST(0.84210223882952), FRAC_CONST(0.84353543682130), FRAC_CONST(0.84496092574524), FRAC_CONST(0.84637869650833), FRAC_CONST(0.84778874049138), + FRAC_CONST(0.84919104954855), FRAC_CONST(0.85058561600677), FRAC_CONST(0.85197243266520), FRAC_CONST(0.85335149279457), FRAC_CONST(0.85472279013653), + FRAC_CONST(0.85608631890295), FRAC_CONST(0.85744207377513), FRAC_CONST(0.85879004990298), FRAC_CONST(0.86013024290422), FRAC_CONST(0.86146264886346), + FRAC_CONST(0.86278726433124), FRAC_CONST(0.86410408632306), FRAC_CONST(0.86541311231838), FRAC_CONST(0.86671434025950), FRAC_CONST(0.86800776855046), + FRAC_CONST(0.86929339605590), FRAC_CONST(0.87057122209981), FRAC_CONST(0.87184124646433), FRAC_CONST(0.87310346938840), FRAC_CONST(0.87435789156650), + FRAC_CONST(0.87560451414719), FRAC_CONST(0.87684333873173), FRAC_CONST(0.87807436737261), FRAC_CONST(0.87929760257204), FRAC_CONST(0.88051304728038), + FRAC_CONST(0.88172070489456), FRAC_CONST(0.88292057925645), FRAC_CONST(0.88411267465117), FRAC_CONST(0.88529699580537), FRAC_CONST(0.88647354788545), + FRAC_CONST(0.88764233649580), FRAC_CONST(0.88880336767692), FRAC_CONST(0.88995664790351), FRAC_CONST(0.89110218408260), FRAC_CONST(0.89223998355154), + FRAC_CONST(0.89337005407600), FRAC_CONST(0.89449240384793), FRAC_CONST(0.89560704148345), FRAC_CONST(0.89671397602074), FRAC_CONST(0.89781321691786), + FRAC_CONST(0.89890477405053), FRAC_CONST(0.89998865770993), FRAC_CONST(0.90106487860034), FRAC_CONST(0.90213344783689), FRAC_CONST(0.90319437694315), + FRAC_CONST(0.90424767784873), FRAC_CONST(0.90529336288690), FRAC_CONST(0.90633144479201), FRAC_CONST(0.90736193669708), FRAC_CONST(0.90838485213119), + FRAC_CONST(0.90940020501694), FRAC_CONST(0.91040800966776), FRAC_CONST(0.91140828078533), FRAC_CONST(0.91240103345685), FRAC_CONST(0.91338628315231), + FRAC_CONST(0.91436404572173), FRAC_CONST(0.91533433739238), FRAC_CONST(0.91629717476594), FRAC_CONST(0.91725257481564), FRAC_CONST(0.91820055488334), + FRAC_CONST(0.91914113267664), FRAC_CONST(0.92007432626589), FRAC_CONST(0.92100015408120), FRAC_CONST(0.92191863490944), FRAC_CONST(0.92282978789113), + FRAC_CONST(0.92373363251740), FRAC_CONST(0.92463018862687), FRAC_CONST(0.92551947640245), FRAC_CONST(0.92640151636824), FRAC_CONST(0.92727632938624), + FRAC_CONST(0.92814393665320), FRAC_CONST(0.92900435969727), FRAC_CONST(0.92985762037477), FRAC_CONST(0.93070374086684), FRAC_CONST(0.93154274367610), + FRAC_CONST(0.93237465162328), FRAC_CONST(0.93319948784382), FRAC_CONST(0.93401727578443), FRAC_CONST(0.93482803919967), FRAC_CONST(0.93563180214841), + FRAC_CONST(0.93642858899043), FRAC_CONST(0.93721842438279), FRAC_CONST(0.93800133327637), FRAC_CONST(0.93877734091223), FRAC_CONST(0.93954647281807), + FRAC_CONST(0.94030875480458), FRAC_CONST(0.94106421296182), FRAC_CONST(0.94181287365556), FRAC_CONST(0.94255476352362), FRAC_CONST(0.94328990947213), + FRAC_CONST(0.94401833867184), FRAC_CONST(0.94474007855439), FRAC_CONST(0.94545515680855), FRAC_CONST(0.94616360137644), FRAC_CONST(0.94686544044975), + FRAC_CONST(0.94756070246592), FRAC_CONST(0.94824941610434), FRAC_CONST(0.94893161028248), FRAC_CONST(0.94960731415209), FRAC_CONST(0.95027655709525), + FRAC_CONST(0.95093936872056), FRAC_CONST(0.95159577885924), FRAC_CONST(0.95224581756115), FRAC_CONST(0.95288951509097), FRAC_CONST(0.95352690192417), + FRAC_CONST(0.95415800874314), FRAC_CONST(0.95478286643320), FRAC_CONST(0.95540150607863), FRAC_CONST(0.95601395895871), FRAC_CONST(0.95662025654373), + FRAC_CONST(0.95722043049100), FRAC_CONST(0.95781451264084), FRAC_CONST(0.95840253501260), FRAC_CONST(0.95898452980058), FRAC_CONST(0.95956052937008), + FRAC_CONST(0.96013056625336), FRAC_CONST(0.96069467314557), FRAC_CONST(0.96125288290073), FRAC_CONST(0.96180522852773), FRAC_CONST(0.96235174318622), + FRAC_CONST(0.96289246018262), FRAC_CONST(0.96342741296604), FRAC_CONST(0.96395663512424), FRAC_CONST(0.96448016037959), FRAC_CONST(0.96499802258499), + FRAC_CONST(0.96551025571985), FRAC_CONST(0.96601689388602), FRAC_CONST(0.96651797130376), FRAC_CONST(0.96701352230768), FRAC_CONST(0.96750358134269), + FRAC_CONST(0.96798818295998), FRAC_CONST(0.96846736181297), FRAC_CONST(0.96894115265327), FRAC_CONST(0.96940959032667), FRAC_CONST(0.96987270976912), + FRAC_CONST(0.97033054600270), FRAC_CONST(0.97078313413161), FRAC_CONST(0.97123050933818), FRAC_CONST(0.97167270687887), FRAC_CONST(0.97210976208030), + FRAC_CONST(0.97254171033525), FRAC_CONST(0.97296858709871), FRAC_CONST(0.97339042788392), FRAC_CONST(0.97380726825843), FRAC_CONST(0.97421914384017), + FRAC_CONST(0.97462609029350), FRAC_CONST(0.97502814332534), FRAC_CONST(0.97542533868127), FRAC_CONST(0.97581771214160), FRAC_CONST(0.97620529951759), + FRAC_CONST(0.97658813664749), FRAC_CONST(0.97696625939282), FRAC_CONST(0.97733970363445), FRAC_CONST(0.97770850526884), FRAC_CONST(0.97807270020427), + FRAC_CONST(0.97843232435704), FRAC_CONST(0.97878741364771), FRAC_CONST(0.97913800399743), FRAC_CONST(0.97948413132414), FRAC_CONST(0.97982583153895), + FRAC_CONST(0.98016314054243), FRAC_CONST(0.98049609422096), FRAC_CONST(0.98082472844313), FRAC_CONST(0.98114907905608), FRAC_CONST(0.98146918188197), + FRAC_CONST(0.98178507271438), FRAC_CONST(0.98209678731477), FRAC_CONST(0.98240436140902), FRAC_CONST(0.98270783068385), FRAC_CONST(0.98300723078342), + FRAC_CONST(0.98330259730589), FRAC_CONST(0.98359396579995), FRAC_CONST(0.98388137176152), FRAC_CONST(0.98416485063031), FRAC_CONST(0.98444443778651), + FRAC_CONST(0.98472016854752), FRAC_CONST(0.98499207816463), FRAC_CONST(0.98526020181980), FRAC_CONST(0.98552457462240), FRAC_CONST(0.98578523160609), + FRAC_CONST(0.98604220772560), FRAC_CONST(0.98629553785362), FRAC_CONST(0.98654525677772), FRAC_CONST(0.98679139919726), FRAC_CONST(0.98703399972035), + FRAC_CONST(0.98727309286089), FRAC_CONST(0.98750871303556), FRAC_CONST(0.98774089456089), FRAC_CONST(0.98796967165036), FRAC_CONST(0.98819507841154), + FRAC_CONST(0.98841714884323), FRAC_CONST(0.98863591683269), FRAC_CONST(0.98885141615285), FRAC_CONST(0.98906368045957), FRAC_CONST(0.98927274328896), + FRAC_CONST(0.98947863805473), FRAC_CONST(0.98968139804554), FRAC_CONST(0.98988105642241), FRAC_CONST(0.99007764621618), FRAC_CONST(0.99027120032501), + FRAC_CONST(0.99046175151186), FRAC_CONST(0.99064933240208), FRAC_CONST(0.99083397548099), FRAC_CONST(0.99101571309153), FRAC_CONST(0.99119457743191), + FRAC_CONST(0.99137060055337), FRAC_CONST(0.99154381435784), FRAC_CONST(0.99171425059582), FRAC_CONST(0.99188194086414), FRAC_CONST(0.99204691660388), + FRAC_CONST(0.99220920909823), FRAC_CONST(0.99236884947045), FRAC_CONST(0.99252586868186), FRAC_CONST(0.99268029752989), FRAC_CONST(0.99283216664606), + FRAC_CONST(0.99298150649419), FRAC_CONST(0.99312834736847), FRAC_CONST(0.99327271939167), FRAC_CONST(0.99341465251338), FRAC_CONST(0.99355417650825), + FRAC_CONST(0.99369132097430), FRAC_CONST(0.99382611533130), FRAC_CONST(0.99395858881910), FRAC_CONST(0.99408877049612), FRAC_CONST(0.99421668923778), + FRAC_CONST(0.99434237373503), FRAC_CONST(0.99446585249289), FRAC_CONST(0.99458715382906), FRAC_CONST(0.99470630587254), FRAC_CONST(0.99482333656229), + FRAC_CONST(0.99493827364600), FRAC_CONST(0.99505114467878), FRAC_CONST(0.99516197702200), FRAC_CONST(0.99527079784214), FRAC_CONST(0.99537763410962), + FRAC_CONST(0.99548251259777), FRAC_CONST(0.99558545988178), FRAC_CONST(0.99568650233767), FRAC_CONST(0.99578566614138), FRAC_CONST(0.99588297726783), + FRAC_CONST(0.99597846149005), FRAC_CONST(0.99607214437834), FRAC_CONST(0.99616405129947), FRAC_CONST(0.99625420741595), FRAC_CONST(0.99634263768527), + FRAC_CONST(0.99642936685928), FRAC_CONST(0.99651441948352), FRAC_CONST(0.99659781989663), FRAC_CONST(0.99667959222978), FRAC_CONST(0.99675976040620), + FRAC_CONST(0.99683834814063), FRAC_CONST(0.99691537893895), FRAC_CONST(0.99699087609774), FRAC_CONST(0.99706486270391), FRAC_CONST(0.99713736163442), + FRAC_CONST(0.99720839555593), FRAC_CONST(0.99727798692461), FRAC_CONST(0.99734615798589), FRAC_CONST(0.99741293077431), FRAC_CONST(0.99747832711337), + FRAC_CONST(0.99754236861541), FRAC_CONST(0.99760507668158), FRAC_CONST(0.99766647250181), FRAC_CONST(0.99772657705478), FRAC_CONST(0.99778541110799), + FRAC_CONST(0.99784299521785), FRAC_CONST(0.99789934972976), FRAC_CONST(0.99795449477828), FRAC_CONST(0.99800845028730), FRAC_CONST(0.99806123597027), + FRAC_CONST(0.99811287133042), FRAC_CONST(0.99816337566108), FRAC_CONST(0.99821276804596), FRAC_CONST(0.99826106735952), FRAC_CONST(0.99830829226732), + FRAC_CONST(0.99835446122649), FRAC_CONST(0.99839959248609), FRAC_CONST(0.99844370408765), FRAC_CONST(0.99848681386566), FRAC_CONST(0.99852893944805), + FRAC_CONST(0.99857009825685), FRAC_CONST(0.99861030750869), FRAC_CONST(0.99864958421549), FRAC_CONST(0.99868794518504), FRAC_CONST(0.99872540702178), + FRAC_CONST(0.99876198612738), FRAC_CONST(0.99879769870160), FRAC_CONST(0.99883256074295), FRAC_CONST(0.99886658804953), FRAC_CONST(0.99889979621983), + FRAC_CONST(0.99893220065356), FRAC_CONST(0.99896381655254), FRAC_CONST(0.99899465892154), FRAC_CONST(0.99902474256924), FRAC_CONST(0.99905408210916), + FRAC_CONST(0.99908269196056), FRAC_CONST(0.99911058634952), FRAC_CONST(0.99913777930986), FRAC_CONST(0.99916428468421), FRAC_CONST(0.99919011612505), + FRAC_CONST(0.99921528709576), FRAC_CONST(0.99923981087174), FRAC_CONST(0.99926370054150), FRAC_CONST(0.99928696900779), FRAC_CONST(0.99930962898876), + FRAC_CONST(0.99933169301910), FRAC_CONST(0.99935317345126), FRAC_CONST(0.99937408245662), FRAC_CONST(0.99939443202674), FRAC_CONST(0.99941423397457), + FRAC_CONST(0.99943349993572), FRAC_CONST(0.99945224136972), FRAC_CONST(0.99947046956130), FRAC_CONST(0.99948819562171), FRAC_CONST(0.99950543049000), + FRAC_CONST(0.99952218493439), FRAC_CONST(0.99953846955355), FRAC_CONST(0.99955429477803), FRAC_CONST(0.99956967087154), FRAC_CONST(0.99958460793242), + FRAC_CONST(0.99959911589494), FRAC_CONST(0.99961320453077), FRAC_CONST(0.99962688345035), FRAC_CONST(0.99964016210433), FRAC_CONST(0.99965304978499), + FRAC_CONST(0.99966555562769), FRAC_CONST(0.99967768861231), FRAC_CONST(0.99968945756473), FRAC_CONST(0.99970087115825), FRAC_CONST(0.99971193791510), + FRAC_CONST(0.99972266620792), FRAC_CONST(0.99973306426121), FRAC_CONST(0.99974314015288), FRAC_CONST(0.99975290181568), FRAC_CONST(0.99976235703876), + FRAC_CONST(0.99977151346914), FRAC_CONST(0.99978037861326), FRAC_CONST(0.99978895983845), FRAC_CONST(0.99979726437448), FRAC_CONST(0.99980529931507), + FRAC_CONST(0.99981307161943), FRAC_CONST(0.99982058811377), FRAC_CONST(0.99982785549283), FRAC_CONST(0.99983488032144), FRAC_CONST(0.99984166903600), + FRAC_CONST(0.99984822794606), FRAC_CONST(0.99985456323584), FRAC_CONST(0.99986068096572), FRAC_CONST(0.99986658707386), FRAC_CONST(0.99987228737764), + FRAC_CONST(0.99987778757524), FRAC_CONST(0.99988309324717), FRAC_CONST(0.99988820985777), FRAC_CONST(0.99989314275675), FRAC_CONST(0.99989789718072), + FRAC_CONST(0.99990247825468), FRAC_CONST(0.99990689099357), FRAC_CONST(0.99991114030376), FRAC_CONST(0.99991523098456), FRAC_CONST(0.99991916772971), + FRAC_CONST(0.99992295512891), FRAC_CONST(0.99992659766930), FRAC_CONST(0.99993009973692), FRAC_CONST(0.99993346561824), FRAC_CONST(0.99993669950161), + FRAC_CONST(0.99993980547870), FRAC_CONST(0.99994278754604), FRAC_CONST(0.99994564960642), FRAC_CONST(0.99994839547033), FRAC_CONST(0.99995102885747), + FRAC_CONST(0.99995355339809), FRAC_CONST(0.99995597263451), FRAC_CONST(0.99995829002249), FRAC_CONST(0.99996050893264), FRAC_CONST(0.99996263265183), + FRAC_CONST(0.99996466438460), FRAC_CONST(0.99996660725452), FRAC_CONST(0.99996846430558), FRAC_CONST(0.99997023850356), FRAC_CONST(0.99997193273736), + FRAC_CONST(0.99997354982037), FRAC_CONST(0.99997509249183), FRAC_CONST(0.99997656341810), FRAC_CONST(0.99997796519400), FRAC_CONST(0.99997930034415), + FRAC_CONST(0.99998057132421), FRAC_CONST(0.99998178052220), FRAC_CONST(0.99998293025975), FRAC_CONST(0.99998402279338), FRAC_CONST(0.99998506031574), + FRAC_CONST(0.99998604495686), FRAC_CONST(0.99998697878536), FRAC_CONST(0.99998786380966), FRAC_CONST(0.99998870197921), FRAC_CONST(0.99998949518567), + FRAC_CONST(0.99999024526408), FRAC_CONST(0.99999095399401), FRAC_CONST(0.99999162310077), FRAC_CONST(0.99999225425649), FRAC_CONST(0.99999284908128), + FRAC_CONST(0.99999340914435), FRAC_CONST(0.99999393596510), FRAC_CONST(0.99999443101421), FRAC_CONST(0.99999489571473), FRAC_CONST(0.99999533144314), + FRAC_CONST(0.99999573953040), FRAC_CONST(0.99999612126300), FRAC_CONST(0.99999647788395), FRAC_CONST(0.99999681059383), FRAC_CONST(0.99999712055178), + FRAC_CONST(0.99999740887647), FRAC_CONST(0.99999767664709), FRAC_CONST(0.99999792490431), FRAC_CONST(0.99999815465123), FRAC_CONST(0.99999836685427), + FRAC_CONST(0.99999856244415), FRAC_CONST(0.99999874231676), FRAC_CONST(0.99999890733405), FRAC_CONST(0.99999905832493), FRAC_CONST(0.99999919608613), + FRAC_CONST(0.99999932138304), FRAC_CONST(0.99999943495056), FRAC_CONST(0.99999953749392), FRAC_CONST(0.99999962968950), FRAC_CONST(0.99999971218563), + FRAC_CONST(0.99999978560337), FRAC_CONST(0.99999985053727), FRAC_CONST(0.99999990755616), FRAC_CONST(0.99999995720387)}; +#ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t kbd_long_960[] = { + FRAC_CONST(0.0003021562530949), FRAC_CONST(0.0004452267024786), FRAC_CONST(0.0005674947527496), FRAC_CONST(0.0006812465553466), FRAC_CONST(0.0007910496776387), FRAC_CONST(0.0008991655033895), + FRAC_CONST(0.0010068978259384), FRAC_CONST(0.0011150758515751), FRAC_CONST(0.0012242653193642), FRAC_CONST(0.0013348735658205), FRAC_CONST(0.0014472068670273), FRAC_CONST(0.0015615039850448), + FRAC_CONST(0.0016779568885263), FRAC_CONST(0.0017967241232412), FRAC_CONST(0.0019179397560955), FRAC_CONST(0.0020417195415393), FRAC_CONST(0.0021681652836642), FRAC_CONST(0.0022973679910599), + FRAC_CONST(0.0024294102029937), FRAC_CONST(0.0025643677339078), FRAC_CONST(0.0027023110014772), FRAC_CONST(0.0028433060512612), FRAC_CONST(0.0029874153568025), FRAC_CONST(0.0031346984511728), + FRAC_CONST(0.0032852124303662), FRAC_CONST(0.0034390123581190), FRAC_CONST(0.0035961515940931), FRAC_CONST(0.0037566820618961), FRAC_CONST(0.0039206544694386), FRAC_CONST(0.0040881184912194), + FRAC_CONST(0.0042591229199617), FRAC_CONST(0.0044337157933972), FRAC_CONST(0.0046119445007641), FRAC_CONST(0.0047938558726415), FRAC_CONST(0.0049794962570131), FRAC_CONST(0.0051689115838900), + FRAC_CONST(0.0053621474203763), FRAC_CONST(0.0055592490177131), FRAC_CONST(0.0057602613515573), FRAC_CONST(0.0059652291565289), FRAC_CONST(0.0061741969558843), FRAC_CONST(0.0063872090870253), + FRAC_CONST(0.0066043097234387), FRAC_CONST(0.0068255428935640), FRAC_CONST(0.0070509524970088), FRAC_CONST(0.0072805823184660), FRAC_CONST(0.0075144760396340), FRAC_CONST(0.0077526772493942), + FRAC_CONST(0.0079952294524673), FRAC_CONST(0.0082421760767325), FRAC_CONST(0.0084935604793733), FRAC_CONST(0.0087494259519870), FRAC_CONST(0.0090098157247792), FRAC_CONST(0.0092747729699467), + FRAC_CONST(0.0095443408043399), FRAC_CONST(0.0098185622914832), FRAC_CONST(0.0100974804430226), FRAC_CONST(0.0103811382196612), FRAC_CONST(0.0106695785316351), FRAC_CONST(0.0109628442387771), + FRAC_CONST(0.0112609781502091), FRAC_CONST(0.0115640230236993), FRAC_CONST(0.0118720215647169), FRAC_CONST(0.0121850164252137), FRAC_CONST(0.0125030502021561), FRAC_CONST(0.0128261654358321), + FRAC_CONST(0.0131544046079532), FRAC_CONST(0.0134878101395681), FRAC_CONST(0.0138264243888068), FRAC_CONST(0.0141702896484671), FRAC_CONST(0.0145194481434592), FRAC_CONST(0.0148739420281182), + FRAC_CONST(0.0152338133833959), FRAC_CONST(0.0155991042139432), FRAC_CONST(0.0159698564450882), FRAC_CONST(0.0163461119197227), FRAC_CONST(0.0167279123950996), FRAC_CONST(0.0171152995395520), + FRAC_CONST(0.0175083149291368), FRAC_CONST(0.0179070000442104), FRAC_CONST(0.0183113962659409), FRAC_CONST(0.0187215448727609), FRAC_CONST(0.0191374870367659), FRAC_CONST(0.0195592638200623), + FRAC_CONST(0.0199869161710679), FRAC_CONST(0.0204204849207691), FRAC_CONST(0.0208600107789370), FRAC_CONST(0.0213055343303066), FRAC_CONST(0.0217570960307201), FRAC_CONST(0.0222147362032386), + FRAC_CONST(0.0226784950342228), FRAC_CONST(0.0231484125693867), FRAC_CONST(0.0236245287098244), FRAC_CONST(0.0241068832080138), FRAC_CONST(0.0245955156637973), FRAC_CONST(0.0250904655203431), + FRAC_CONST(0.0255917720600868), FRAC_CONST(0.0260994744006559), FRAC_CONST(0.0266136114907790), FRAC_CONST(0.0271342221061795), FRAC_CONST(0.0276613448454576), FRAC_CONST(0.0281950181259587), + FRAC_CONST(0.0287352801796329), FRAC_CONST(0.0292821690488833), FRAC_CONST(0.0298357225824074), FRAC_CONST(0.0303959784310299), FRAC_CONST(0.0309629740435296), FRAC_CONST(0.0315367466624615), + FRAC_CONST(0.0321173333199732), FRAC_CONST(0.0327047708336193), FRAC_CONST(0.0332990958021720), FRAC_CONST(0.0339003446014307), FRAC_CONST(0.0345085533800302), FRAC_CONST(0.0351237580552491), + FRAC_CONST(0.0357459943088193), FRAC_CONST(0.0363752975827358), FRAC_CONST(0.0370117030750704), FRAC_CONST(0.0376552457357870), FRAC_CONST(0.0383059602625614), FRAC_CONST(0.0389638810966056), + FRAC_CONST(0.0396290424184964), FRAC_CONST(0.0403014781440112), FRAC_CONST(0.0409812219199691), FRAC_CONST(0.0416683071200799), FRAC_CONST(0.0423627668408009), FRAC_CONST(0.0430646338972016), + FRAC_CONST(0.0437739408188385), FRAC_CONST(0.0444907198456388), FRAC_CONST(0.0452150029237951), FRAC_CONST(0.0459468217016708), FRAC_CONST(0.0466862075257170), FRAC_CONST(0.0474331914364021), + FRAC_CONST(0.0481878041641539), FRAC_CONST(0.0489500761253148), FRAC_CONST(0.0497200374181119), FRAC_CONST(0.0504977178186404), FRAC_CONST(0.0512831467768636), FRAC_CONST(0.0520763534126273), + FRAC_CONST(0.0528773665116913), FRAC_CONST(0.0536862145217772), FRAC_CONST(0.0545029255486345), FRAC_CONST(0.0553275273521232), FRAC_CONST(0.0561600473423164), FRAC_CONST(0.0570005125756209), + FRAC_CONST(0.0578489497509179), FRAC_CONST(0.0587053852057233), FRAC_CONST(0.0595698449123695), FRAC_CONST(0.0604423544742077), FRAC_CONST(0.0613229391218317), FRAC_CONST(0.0622116237093247), + FRAC_CONST(0.0631084327105284), FRAC_CONST(0.0640133902153352), FRAC_CONST(0.0649265199260043), FRAC_CONST(0.0658478451535027), FRAC_CONST(0.0667773888138695), FRAC_CONST(0.0677151734246072), + FRAC_CONST(0.0686612211010977), FRAC_CONST(0.0696155535530446), FRAC_CONST(0.0705781920809429), FRAC_CONST(0.0715491575725758), FRAC_CONST(0.0725284704995383), FRAC_CONST(0.0735161509137906), + FRAC_CONST(0.0745122184442388), FRAC_CONST(0.0755166922933461), FRAC_CONST(0.0765295912337720), FRAC_CONST(0.0775509336050437), FRAC_CONST(0.0785807373102561), FRAC_CONST(0.0796190198128044), + FRAC_CONST(0.0806657981331473), FRAC_CONST(0.0817210888456026), FRAC_CONST(0.0827849080751753), FRAC_CONST(0.0838572714944183), FRAC_CONST(0.0849381943203265), FRAC_CONST(0.0860276913112652), + FRAC_CONST(0.0871257767639319), FRAC_CONST(0.0882324645103534), FRAC_CONST(0.0893477679149177), FRAC_CONST(0.0904716998714418), FRAC_CONST(0.0916042728002747), FRAC_CONST(0.0927454986454381), + FRAC_CONST(0.0938953888718020), FRAC_CONST(0.0950539544622996), FRAC_CONST(0.0962212059151784), FRAC_CONST(0.0973971532412897), FRAC_CONST(0.0985818059614169), FRAC_CONST(0.0997751731036425), + FRAC_CONST(0.1009772632007537), FRAC_CONST(0.1021880842876888), FRAC_CONST(0.1034076438990227), FRAC_CONST(0.1046359490664932), FRAC_CONST(0.1058730063165681), FRAC_CONST(0.1071188216680533), + FRAC_CONST(0.1083734006297428), FRAC_CONST(0.1096367481981100), FRAC_CONST(0.1109088688550422), FRAC_CONST(0.1121897665656167), FRAC_CONST(0.1134794447759207), FRAC_CONST(0.1147779064109143), + FRAC_CONST(0.1160851538723372), FRAC_CONST(0.1174011890366591), FRAC_CONST(0.1187260132530751), FRAC_CONST(0.1200596273415457), FRAC_CONST(0.1214020315908810), FRAC_CONST(0.1227532257568719), + FRAC_CONST(0.1241132090604651), FRAC_CONST(0.1254819801859856), FRAC_CONST(0.1268595372794049), FRAC_CONST(0.1282458779466558), FRAC_CONST(0.1296409992519942), FRAC_CONST(0.1310448977164081), + FRAC_CONST(0.1324575693160745), FRAC_CONST(0.1338790094808633), FRAC_CONST(0.1353092130928902), FRAC_CONST(0.1367481744851168), FRAC_CONST(0.1381958874400010), FRAC_CONST(0.1396523451881945), + FRAC_CONST(0.1411175404072910), FRAC_CONST(0.1425914652206223), FRAC_CONST(0.1440741111961058), FRAC_CONST(0.1455654693451402), FRAC_CONST(0.1470655301215526), FRAC_CONST(0.1485742834205956), + FRAC_CONST(0.1500917185779945), FRAC_CONST(0.1516178243690463), FRAC_CONST(0.1531525890077689), FRAC_CONST(0.1546960001461024), FRAC_CONST(0.1562480448731608), FRAC_CONST(0.1578087097145364), + FRAC_CONST(0.1593779806316558), FRAC_CONST(0.1609558430211876), FRAC_CONST(0.1625422817145027), FRAC_CONST(0.1641372809771871), FRAC_CONST(0.1657408245086070), FRAC_CONST(0.1673528954415270), + FRAC_CONST(0.1689734763417811), FRAC_CONST(0.1706025492079969), FRAC_CONST(0.1722400954713725), FRAC_CONST(0.1738860959955082), FRAC_CONST(0.1755405310762898), FRAC_CONST(0.1772033804418275), + FRAC_CONST(0.1788746232524467), FRAC_CONST(0.1805542381007349), FRAC_CONST(0.1822422030116404), FRAC_CONST(0.1839384954426268), FRAC_CONST(0.1856430922838810), FRAC_CONST(0.1873559698585756), + FRAC_CONST(0.1890771039231862), FRAC_CONST(0.1908064696678625), FRAC_CONST(0.1925440417168546), FRAC_CONST(0.1942897941289937), FRAC_CONST(0.1960437003982277), FRAC_CONST(0.1978057334542116), + FRAC_CONST(0.1995758656629525), FRAC_CONST(0.2013540688275098), FRAC_CONST(0.2031403141887507), FRAC_CONST(0.2049345724261595), FRAC_CONST(0.2067368136587033), FRAC_CONST(0.2085470074457521), + FRAC_CONST(0.2103651227880538), FRAC_CONST(0.2121911281287646), FRAC_CONST(0.2140249913545346), FRAC_CONST(0.2158666797966480), FRAC_CONST(0.2177161602322188), FRAC_CONST(0.2195733988854414), + FRAC_CONST(0.2214383614288963), FRAC_CONST(0.2233110129849106), FRAC_CONST(0.2251913181269740), FRAC_CONST(0.2270792408812093), FRAC_CONST(0.2289747447278976), FRAC_CONST(0.2308777926030592), + FRAC_CONST(0.2327883469000885), FRAC_CONST(0.2347063694714437), FRAC_CONST(0.2366318216303919), FRAC_CONST(0.2385646641528076), FRAC_CONST(0.2405048572790267), FRAC_CONST(0.2424523607157545), + FRAC_CONST(0.2444071336380283), FRAC_CONST(0.2463691346912334), FRAC_CONST(0.2483383219931741), FRAC_CONST(0.2503146531361985), FRAC_CONST(0.2522980851893767), FRAC_CONST(0.2542885747007335), + FRAC_CONST(0.2562860776995335), FRAC_CONST(0.2582905496986215), FRAC_CONST(0.2603019456968142), FRAC_CONST(0.2623202201813464), FRAC_CONST(0.2643453271303700), FRAC_CONST(0.2663772200155053), + FRAC_CONST(0.2684158518044454), FRAC_CONST(0.2704611749636135), FRAC_CONST(0.2725131414608710), FRAC_CONST(0.2745717027682799), FRAC_CONST(0.2766368098649151), FRAC_CONST(0.2787084132397296), + FRAC_CONST(0.2807864628944707), FRAC_CONST(0.2828709083466482), FRAC_CONST(0.2849616986325523), FRAC_CONST(0.2870587823103237), FRAC_CONST(0.2891621074630737), FRAC_CONST(0.2912716217020546), + FRAC_CONST(0.2933872721698803), FRAC_CONST(0.2955090055437973), FRAC_CONST(0.2976367680390041), FRAC_CONST(0.2997705054120213), FRAC_CONST(0.3019101629641097), FRAC_CONST(0.3040556855447379), + FRAC_CONST(0.3062070175550981), FRAC_CONST(0.3083641029516701), FRAC_CONST(0.3105268852498334), FRAC_CONST(0.3126953075275265), FRAC_CONST(0.3148693124289546), FRAC_CONST(0.3170488421683428), + FRAC_CONST(0.3192338385337370), FRAC_CONST(0.3214242428908514), FRAC_CONST(0.3236199961869606), FRAC_CONST(0.3258210389548392), FRAC_CONST(0.3280273113167459), FRAC_CONST(0.3302387529884521), + FRAC_CONST(0.3324553032833160), FRAC_CONST(0.3346769011164010), FRAC_CONST(0.3369034850086373), FRAC_CONST(0.3391349930910280), FRAC_CONST(0.3413713631088974), FRAC_CONST(0.3436125324261830), + FRAC_CONST(0.3458584380297697), FRAC_CONST(0.3481090165338656), FRAC_CONST(0.3503642041844199), FRAC_CONST(0.3526239368635820), FRAC_CONST(0.3548881500942010), FRAC_CONST(0.3571567790443668), + FRAC_CONST(0.3594297585319891), FRAC_CONST(0.3617070230294185), FRAC_CONST(0.3639885066681048), FRAC_CONST(0.3662741432432950), FRAC_CONST(0.3685638662187693), FRAC_CONST(0.3708576087316147), + FRAC_CONST(0.3731553035970366), FRAC_CONST(0.3754568833132069), FRAC_CONST(0.3777622800661488), FRAC_CONST(0.3800714257346570), FRAC_CONST(0.3823842518952546), FRAC_CONST(0.3847006898271841), + FRAC_CONST(0.3870206705174334), FRAC_CONST(0.3893441246657958), FRAC_CONST(0.3916709826899639), FRAC_CONST(0.3940011747306560), FRAC_CONST(0.3963346306567764), FRAC_CONST(0.3986712800706062), + FRAC_CONST(0.4010110523130271), FRAC_CONST(0.4033538764687756), FRAC_CONST(0.4056996813717284), FRAC_CONST(0.4080483956102172), FRAC_CONST(0.4103999475323736), FRAC_CONST(0.4127542652515031), + FRAC_CONST(0.4151112766514873), FRAC_CONST(0.4174709093922143), FRAC_CONST(0.4198330909150365), FRAC_CONST(0.4221977484482556), FRAC_CONST(0.4245648090126334), FRAC_CONST(0.4269341994269293), + FRAC_CONST(0.4293058463134616), FRAC_CONST(0.4316796761036958), FRAC_CONST(0.4340556150438547), FRAC_CONST(0.4364335892005536), FRAC_CONST(0.4388135244664580), FRAC_CONST(0.4411953465659639), + FRAC_CONST(0.4435789810609000), FRAC_CONST(0.4459643533562509), FRAC_CONST(0.4483513887059016), FRAC_CONST(0.4507400122184019), FRAC_CONST(0.4531301488627497), FRAC_CONST(0.4555217234741947), + FRAC_CONST(0.4579146607600593), FRAC_CONST(0.4603088853055777), FRAC_CONST(0.4627043215797521), FRAC_CONST(0.4651008939412254), FRAC_CONST(0.4674985266441709), FRAC_CONST(0.4698971438441951), + FRAC_CONST(0.4722966696042580), FRAC_CONST(0.4746970279006055), FRAC_CONST(0.4770981426287164), FRAC_CONST(0.4794999376092619), FRAC_CONST(0.4819023365940778), FRAC_CONST(0.4843052632721476), + FRAC_CONST(0.4867086412755978), FRAC_CONST(0.4891123941857028), FRAC_CONST(0.4915164455388997), FRAC_CONST(0.4939207188328126), FRAC_CONST(0.4963251375322855), FRAC_CONST(0.4987296250754225), + FRAC_CONST(0.5011341048796359), FRAC_CONST(0.5035385003477012), FRAC_CONST(0.5059427348738168), FRAC_CONST(0.5083467318496706), FRAC_CONST(0.5107504146705106), FRAC_CONST(0.5131537067412193), + FRAC_CONST(0.5155565314823923), FRAC_CONST(0.5179588123364193), FRAC_CONST(0.5203604727735667), FRAC_CONST(0.5227614362980630), FRAC_CONST(0.5251616264541841), FRAC_CONST(0.5275609668323384), + FRAC_CONST(0.5299593810751532), FRAC_CONST(0.5323567928835578), FRAC_CONST(0.5347531260228663), FRAC_CONST(0.5371483043288580), FRAC_CONST(0.5395422517138538), FRAC_CONST(0.5419348921727899), + FRAC_CONST(0.5443261497892862), FRAC_CONST(0.5467159487417104), FRAC_CONST(0.5491042133092364), FRAC_CONST(0.5514908678778958), FRAC_CONST(0.5538758369466227), FRAC_CONST(0.5562590451332913), + FRAC_CONST(0.5586404171807443), FRAC_CONST(0.5610198779628133), FRAC_CONST(0.5633973524903286), FRAC_CONST(0.5657727659171199), FRAC_CONST(0.5681460435460047), FRAC_CONST(0.5705171108347663), + FRAC_CONST(0.5728858934021188), FRAC_CONST(0.5752523170336598), FRAC_CONST(0.5776163076878088), FRAC_CONST(0.5799777915017323), FRAC_CONST(0.5823366947972535), FRAC_CONST(0.5846929440867458), + FRAC_CONST(0.5870464660790119), FRAC_CONST(0.5893971876851449), FRAC_CONST(0.5917450360243719), FRAC_CONST(0.5940899384298793), FRAC_CONST(0.5964318224546208), FRAC_CONST(0.5987706158771039), + FRAC_CONST(0.6011062467071583), FRAC_CONST(0.6034386431916822), FRAC_CONST(0.6057677338203681), FRAC_CONST(0.6080934473314057), FRAC_CONST(0.6104157127171639), FRAC_CONST(0.6127344592298474), + FRAC_CONST(0.6150496163871310), FRAC_CONST(0.6173611139777690), FRAC_CONST(0.6196688820671789), FRAC_CONST(0.6219728510029997), FRAC_CONST(0.6242729514206247), FRAC_CONST(0.6265691142487051), + FRAC_CONST(0.6288612707146283), FRAC_CONST(0.6311493523499663), FRAC_CONST(0.6334332909958958), FRAC_CONST(0.6357130188085891), FRAC_CONST(0.6379884682645743), FRAC_CONST(0.6402595721660647), + FRAC_CONST(0.6425262636462578), FRAC_CONST(0.6447884761746012), FRAC_CONST(0.6470461435620266), FRAC_CONST(0.6492991999661505), FRAC_CONST(0.6515475798964411), FRAC_CONST(0.6537912182193508), + FRAC_CONST(0.6560300501634142), FRAC_CONST(0.6582640113243098), FRAC_CONST(0.6604930376698862), FRAC_CONST(0.6627170655451516), FRAC_CONST(0.6649360316772256), FRAC_CONST(0.6671498731802533), + FRAC_CONST(0.6693585275602818), FRAC_CONST(0.6715619327200959), FRAC_CONST(0.6737600269640164), FRAC_CONST(0.6759527490026566), FRAC_CONST(0.6781400379576392), FRAC_CONST(0.6803218333662715), + FRAC_CONST(0.6824980751861787), FRAC_CONST(0.6846687037998949), FRAC_CONST(0.6868336600194123), FRAC_CONST(0.6889928850906855), FRAC_CONST(0.6911463206980928), FRAC_CONST(0.6932939089688525), + FRAC_CONST(0.6954355924773949), FRAC_CONST(0.6975713142496884), FRAC_CONST(0.6997010177675195), FRAC_CONST(0.7018246469727265), FRAC_CONST(0.7039421462713862), FRAC_CONST(0.7060534605379528), + FRAC_CONST(0.7081585351193496), FRAC_CONST(0.7102573158390105), FRAC_CONST(0.7123497490008750), FRAC_CONST(0.7144357813933307), FRAC_CONST(0.7165153602931092), FRAC_CONST(0.7185884334691287), + FRAC_CONST(0.7206549491862871), FRAC_CONST(0.7227148562092042), FRAC_CONST(0.7247681038059106), FRAC_CONST(0.7268146417514855), FRAC_CONST(0.7288544203316418), FRAC_CONST(0.7308873903462577), + FRAC_CONST(0.7329135031128549), FRAC_CONST(0.7349327104700221), FRAC_CONST(0.7369449647807855), FRAC_CONST(0.7389502189359237), FRAC_CONST(0.7409484263572271), FRAC_CONST(0.7429395410007016), + FRAC_CONST(0.7449235173597176), FRAC_CONST(0.7469003104681008), FRAC_CONST(0.7488698759031670), FRAC_CONST(0.7508321697887005), FRAC_CONST(0.7527871487978728), FRAC_CONST(0.7547347701561059), + FRAC_CONST(0.7566749916438754), FRAC_CONST(0.7586077715994560), FRAC_CONST(0.7605330689216074), FRAC_CONST(0.7624508430722016), FRAC_CONST(0.7643610540787891), FRAC_CONST(0.7662636625371070), + FRAC_CONST(0.7681586296135255), FRAC_CONST(0.7700459170474343), FRAC_CONST(0.7719254871535672), FRAC_CONST(0.7737973028242671), FRAC_CONST(0.7756613275316875), FRAC_CONST(0.7775175253299340), + FRAC_CONST(0.7793658608571425), FRAC_CONST(0.7812062993374951), FRAC_CONST(0.7830388065831744), FRAC_CONST(0.7848633489962533), FRAC_CONST(0.7866798935705233), FRAC_CONST(0.7884884078932579), + FRAC_CONST(0.7902888601469138), FRAC_CONST(0.7920812191107668), FRAC_CONST(0.7938654541624850), FRAC_CONST(0.7956415352796368), FRAC_CONST(0.7974094330411343), FRAC_CONST(0.7991691186286133), + FRAC_CONST(0.8009205638277465), FRAC_CONST(0.8026637410294932), FRAC_CONST(0.8043986232312831), FRAC_CONST(0.8061251840381346), FRAC_CONST(0.8078433976637077), FRAC_CONST(0.8095532389312917), + FRAC_CONST(0.8112546832747255), FRAC_CONST(0.8129477067392539), FRAC_CONST(0.8146322859823164), FRAC_CONST(0.8163083982742698), FRAC_CONST(0.8179760214990457), FRAC_CONST(0.8196351341547393), + FRAC_CONST(0.8212857153541345), FRAC_CONST(0.8229277448251595), FRAC_CONST(0.8245612029112778), FRAC_CONST(0.8261860705718113), FRAC_CONST(0.8278023293821971), FRAC_CONST(0.8294099615341773), + FRAC_CONST(0.8310089498359212), FRAC_CONST(0.8325992777120815), FRAC_CONST(0.8341809292037831), FRAC_CONST(0.8357538889685445), FRAC_CONST(0.8373181422801330), FRAC_CONST(0.8388736750283521), + FRAC_CONST(0.8404204737187619), FRAC_CONST(0.8419585254723335), FRAC_CONST(0.8434878180250348), FRAC_CONST(0.8450083397273509), FRAC_CONST(0.8465200795437368), FRAC_CONST(0.8480230270520029), + FRAC_CONST(0.8495171724426350), FRAC_CONST(0.8510025065180464), FRAC_CONST(0.8524790206917633), FRAC_CONST(0.8539467069875448), FRAC_CONST(0.8554055580384357), FRAC_CONST(0.8568555670857525), + FRAC_CONST(0.8582967279780043), FRAC_CONST(0.8597290351697464), FRAC_CONST(0.8611524837203691), FRAC_CONST(0.8625670692928198), FRAC_CONST(0.8639727881522599), FRAC_CONST(0.8653696371646555), + FRAC_CONST(0.8667576137953045), FRAC_CONST(0.8681367161072958), FRAC_CONST(0.8695069427599065), FRAC_CONST(0.8708682930069319), FRAC_CONST(0.8722207666949527), FRAC_CONST(0.8735643642615368), + FRAC_CONST(0.8748990867333771), FRAC_CONST(0.8762249357243662), FRAC_CONST(0.8775419134336067), FRAC_CONST(0.8788500226433579), FRAC_CONST(0.8801492667169208), FRAC_CONST(0.8814396495964587), + FRAC_CONST(0.8827211758007560), FRAC_CONST(0.8839938504229149), FRAC_CONST(0.8852576791279895), FRAC_CONST(0.8865126681505587), FRAC_CONST(0.8877588242922386), FRAC_CONST(0.8889961549191320), + FRAC_CONST(0.8902246679592184), FRAC_CONST(0.8914443718996848), FRAC_CONST(0.8926552757841945), FRAC_CONST(0.8938573892100969), FRAC_CONST(0.8950507223255798), FRAC_CONST(0.8962352858267605), + FRAC_CONST(0.8974110909547198), FRAC_CONST(0.8985781494924783), FRAC_CONST(0.8997364737619142), FRAC_CONST(0.9008860766206249), FRAC_CONST(0.9020269714587307), FRAC_CONST(0.9031591721956235), + FRAC_CONST(0.9042826932766591), FRAC_CONST(0.9053975496697941), FRAC_CONST(0.9065037568621681), FRAC_CONST(0.9076013308566311), FRAC_CONST(0.9086902881682180), FRAC_CONST(0.9097706458205682), + FRAC_CONST(0.9108424213422940), FRAC_CONST(0.9119056327632955), FRAC_CONST(0.9129602986110235), FRAC_CONST(0.9140064379066919), FRAC_CONST(0.9150440701614393), FRAC_CONST(0.9160732153724396), + FRAC_CONST(0.9170938940189634), FRAC_CONST(0.9181061270583908), FRAC_CONST(0.9191099359221748), FRAC_CONST(0.9201053425117579), FRAC_CONST(0.9210923691944400), FRAC_CONST(0.9220710387992010), + FRAC_CONST(0.9230413746124764), FRAC_CONST(0.9240034003738882), FRAC_CONST(0.9249571402719298), FRAC_CONST(0.9259026189396085), FRAC_CONST(0.9268398614500427), FRAC_CONST(0.9277688933120170), + FRAC_CONST(0.9286897404654957), FRAC_CONST(0.9296024292770939), FRAC_CONST(0.9305069865355076), FRAC_CONST(0.9314034394469048), FRAC_CONST(0.9322918156302762), FRAC_CONST(0.9331721431127471), + FRAC_CONST(0.9340444503248519), FRAC_CONST(0.9349087660957711), FRAC_CONST(0.9357651196485313), FRAC_CONST(0.9366135405951697), FRAC_CONST(0.9374540589318637), FRAC_CONST(0.9382867050340261), + FRAC_CONST(0.9391115096513655), FRAC_CONST(0.9399285039029165), FRAC_CONST(0.9407377192720349), FRAC_CONST(0.9415391876013639), FRAC_CONST(0.9423329410877687), FRAC_CONST(0.9431190122772415), + FRAC_CONST(0.9438974340597782), FRAC_CONST(0.9446682396642262), FRAC_CONST(0.9454314626531054), FRAC_CONST(0.9461871369174033), FRAC_CONST(0.9469352966713429), FRAC_CONST(0.9476759764471278), + FRAC_CONST(0.9484092110896616), FRAC_CONST(0.9491350357512457), FRAC_CONST(0.9498534858862532), FRAC_CONST(0.9505645972457831), FRAC_CONST(0.9512684058722927), FRAC_CONST(0.9519649480942105), + FRAC_CONST(0.9526542605205314), FRAC_CONST(0.9533363800353921), FRAC_CONST(0.9540113437926313), FRAC_CONST(0.9546791892103320), FRAC_CONST(0.9553399539653500), FRAC_CONST(0.9559936759878265), + FRAC_CONST(0.9566403934556893), FRAC_CONST(0.9572801447891388), FRAC_CONST(0.9579129686451244), FRAC_CONST(0.9585389039118085), FRAC_CONST(0.9591579897030224), FRAC_CONST(0.9597702653527108), + FRAC_CONST(0.9603757704093711), FRAC_CONST(0.9609745446304828), FRAC_CONST(0.9615666279769324), FRAC_CONST(0.9621520606074324), FRAC_CONST(0.9627308828729358), FRAC_CONST(0.9633031353110477), + FRAC_CONST(0.9638688586404335), FRAC_CONST(0.9644280937552258), FRAC_CONST(0.9649808817194311), FRAC_CONST(0.9655272637613366), FRAC_CONST(0.9660672812679171), FRAC_CONST(0.9666009757792454), + FRAC_CONST(0.9671283889829055), FRAC_CONST(0.9676495627084089), FRAC_CONST(0.9681645389216160), FRAC_CONST(0.9686733597191652), FRAC_CONST(0.9691760673229058), FRAC_CONST(0.9696727040743406), + FRAC_CONST(0.9701633124290767), FRAC_CONST(0.9706479349512860), FRAC_CONST(0.9711266143081750), FRAC_CONST(0.9715993932644684), FRAC_CONST(0.9720663146769026), FRAC_CONST(0.9725274214887337), + FRAC_CONST(0.9729827567242596), FRAC_CONST(0.9734323634833574), FRAC_CONST(0.9738762849360358), FRAC_CONST(0.9743145643170059), FRAC_CONST(0.9747472449202687), FRAC_CONST(0.9751743700937215), + FRAC_CONST(0.9755959832337850), FRAC_CONST(0.9760121277800496), FRAC_CONST(0.9764228472099433), FRAC_CONST(0.9768281850334235), FRAC_CONST(0.9772281847876897), FRAC_CONST(0.9776228900319223), + FRAC_CONST(0.9780123443420448), FRAC_CONST(0.9783965913055132), FRAC_CONST(0.9787756745161313), FRAC_CONST(0.9791496375688939), FRAC_CONST(0.9795185240548578), FRAC_CONST(0.9798823775560431), + FRAC_CONST(0.9802412416403639), FRAC_CONST(0.9805951598565897), FRAC_CONST(0.9809441757293399), FRAC_CONST(0.9812883327541090), FRAC_CONST(0.9816276743923267), FRAC_CONST(0.9819622440664515), + FRAC_CONST(0.9822920851550995), FRAC_CONST(0.9826172409882086), FRAC_CONST(0.9829377548422400), FRAC_CONST(0.9832536699354163), FRAC_CONST(0.9835650294229984), FRAC_CONST(0.9838718763926001), + FRAC_CONST(0.9841742538595437), FRAC_CONST(0.9844722047622547), FRAC_CONST(0.9847657719576983), FRAC_CONST(0.9850549982168574), FRAC_CONST(0.9853399262202529), FRAC_CONST(0.9856205985535073), + FRAC_CONST(0.9858970577029519), FRAC_CONST(0.9861693460512790), FRAC_CONST(0.9864375058732389), FRAC_CONST(0.9867015793313820), FRAC_CONST(0.9869616084718489), FRAC_CONST(0.9872176352202061), + FRAC_CONST(0.9874697013773301), FRAC_CONST(0.9877178486153397), FRAC_CONST(0.9879621184735767), FRAC_CONST(0.9882025523546365), FRAC_CONST(0.9884391915204485), FRAC_CONST(0.9886720770884069), + FRAC_CONST(0.9889012500275530), FRAC_CONST(0.9891267511548089), FRAC_CONST(0.9893486211312621), FRAC_CONST(0.9895669004585049), FRAC_CONST(0.9897816294750255), FRAC_CONST(0.9899928483526520), + FRAC_CONST(0.9902005970930525), FRAC_CONST(0.9904049155242876), FRAC_CONST(0.9906058432974180), FRAC_CONST(0.9908034198831690), FRAC_CONST(0.9909976845686489), FRAC_CONST(0.9911886764541239), + FRAC_CONST(0.9913764344498495), FRAC_CONST(0.9915609972729590), FRAC_CONST(0.9917424034444086), FRAC_CONST(0.9919206912859797), FRAC_CONST(0.9920958989173397), FRAC_CONST(0.9922680642531603), + FRAC_CONST(0.9924372250002933), FRAC_CONST(0.9926034186550070), FRAC_CONST(0.9927666825002789), FRAC_CONST(0.9929270536031491), FRAC_CONST(0.9930845688121325), FRAC_CONST(0.9932392647546895), + FRAC_CONST(0.9933911778347579), FRAC_CONST(0.9935403442303433), FRAC_CONST(0.9936867998911693), FRAC_CONST(0.9938305805363887), FRAC_CONST(0.9939717216523539), FRAC_CONST(0.9941102584904481), + FRAC_CONST(0.9942462260649764), FRAC_CONST(0.9943796591511174), FRAC_CONST(0.9945105922829353), FRAC_CONST(0.9946390597514524), FRAC_CONST(0.9947650956027824), FRAC_CONST(0.9948887336363228), + FRAC_CONST(0.9950100074030103), FRAC_CONST(0.9951289502036336), FRAC_CONST(0.9952455950872091), FRAC_CONST(0.9953599748494155), FRAC_CONST(0.9954721220310890), FRAC_CONST(0.9955820689167787), + FRAC_CONST(0.9956898475333619), FRAC_CONST(0.9957954896487196), FRAC_CONST(0.9958990267704713), FRAC_CONST(0.9960004901447701), FRAC_CONST(0.9960999107551559), FRAC_CONST(0.9961973193214694), + FRAC_CONST(0.9962927462988245), FRAC_CONST(0.9963862218766388), FRAC_CONST(0.9964777759777242), FRAC_CONST(0.9965674382574342), FRAC_CONST(0.9966552381028704), FRAC_CONST(0.9967412046321465), + FRAC_CONST(0.9968253666937095), FRAC_CONST(0.9969077528657186), FRAC_CONST(0.9969883914554805), FRAC_CONST(0.9970673104989413), FRAC_CONST(0.9971445377602348), FRAC_CONST(0.9972201007312871), + FRAC_CONST(0.9972940266314749), FRAC_CONST(0.9973663424073412), FRAC_CONST(0.9974370747323638), FRAC_CONST(0.9975062500067785), FRAC_CONST(0.9975738943574574), FRAC_CONST(0.9976400336378379), + FRAC_CONST(0.9977046934279079), FRAC_CONST(0.9977678990342401), FRAC_CONST(0.9978296754900812), FRAC_CONST(0.9978900475554902), FRAC_CONST(0.9979490397175296), FRAC_CONST(0.9980066761905056), + FRAC_CONST(0.9980629809162593), FRAC_CONST(0.9981179775645063), FRAC_CONST(0.9981716895332257), FRAC_CONST(0.9982241399490979), FRAC_CONST(0.9982753516679893), FRAC_CONST(0.9983253472754841), + FRAC_CONST(0.9983741490874634), FRAC_CONST(0.9984217791507299), FRAC_CONST(0.9984682592436778), FRAC_CONST(0.9985136108770075), FRAC_CONST(0.9985578552944850), FRAC_CONST(0.9986010134737439), + FRAC_CONST(0.9986431061271304), FRAC_CONST(0.9986841537025921), FRAC_CONST(0.9987241763846056), FRAC_CONST(0.9987631940951476), FRAC_CONST(0.9988012264947044), FRAC_CONST(0.9988382929833222), + FRAC_CONST(0.9988744127016956), FRAC_CONST(0.9989096045322947), FRAC_CONST(0.9989438871005292), FRAC_CONST(0.9989772787759494), FRAC_CONST(0.9990097976734847), FRAC_CONST(0.9990414616547146), + FRAC_CONST(0.9990722883291779), FRAC_CONST(0.9991022950557125), FRAC_CONST(0.9991314989438310), FRAC_CONST(0.9991599168551279), FRAC_CONST(0.9991875654047181), FRAC_CONST(0.9992144609627068), + FRAC_CONST(0.9992406196556911), FRAC_CONST(0.9992660573682882), FRAC_CONST(0.9992907897446957), FRAC_CONST(0.9993148321902777), FRAC_CONST(0.9993381998731797), FRAC_CONST(0.9993609077259696), + FRAC_CONST(0.9993829704473038), FRAC_CONST(0.9994044025036201), FRAC_CONST(0.9994252181308537), FRAC_CONST(0.9994454313361775), FRAC_CONST(0.9994650558997651), FRAC_CONST(0.9994841053765757), + FRAC_CONST(0.9995025930981609), FRAC_CONST(0.9995205321744921), FRAC_CONST(0.9995379354958073), FRAC_CONST(0.9995548157344778), FRAC_CONST(0.9995711853468930), FRAC_CONST(0.9995870565753632), + FRAC_CONST(0.9996024414500382), FRAC_CONST(0.9996173517908444), FRAC_CONST(0.9996317992094352), FRAC_CONST(0.9996457951111574), FRAC_CONST(0.9996593506970310), FRAC_CONST(0.9996724769657434), + FRAC_CONST(0.9996851847156547), FRAC_CONST(0.9996974845468164), FRAC_CONST(0.9997093868630000), FRAC_CONST(0.9997209018737374), FRAC_CONST(0.9997320395963699), FRAC_CONST(0.9997428098581069), + FRAC_CONST(0.9997532222980933), FRAC_CONST(0.9997632863694836), FRAC_CONST(0.9997730113415246), FRAC_CONST(0.9997824063016426), FRAC_CONST(0.9997914801575380), FRAC_CONST(0.9998002416392840), + FRAC_CONST(0.9998086993014300), FRAC_CONST(0.9998168615251084), FRAC_CONST(0.9998247365201450), FRAC_CONST(0.9998323323271717), FRAC_CONST(0.9998396568197407), FRAC_CONST(0.9998467177064404), + FRAC_CONST(0.9998535225330116), FRAC_CONST(0.9998600786844637), FRAC_CONST(0.9998663933871905), FRAC_CONST(0.9998724737110845), FRAC_CONST(0.9998783265716498), FRAC_CONST(0.9998839587321121), + FRAC_CONST(0.9998893768055266), FRAC_CONST(0.9998945872568815), FRAC_CONST(0.9998995964051983), FRAC_CONST(0.9999044104256269), FRAC_CONST(0.9999090353515359), FRAC_CONST(0.9999134770765971), + FRAC_CONST(0.9999177413568642), FRAC_CONST(0.9999218338128448), FRAC_CONST(0.9999257599315647), FRAC_CONST(0.9999295250686255), FRAC_CONST(0.9999331344502529), FRAC_CONST(0.9999365931753376), + FRAC_CONST(0.9999399062174669), FRAC_CONST(0.9999430784269460), FRAC_CONST(0.9999461145328103), FRAC_CONST(0.9999490191448277), FRAC_CONST(0.9999517967554878), FRAC_CONST(0.9999544517419835), + FRAC_CONST(0.9999569883681778), FRAC_CONST(0.9999594107865607), FRAC_CONST(0.9999617230401926), FRAC_CONST(0.9999639290646355), FRAC_CONST(0.9999660326898712), FRAC_CONST(0.9999680376422052), + FRAC_CONST(0.9999699475461585), FRAC_CONST(0.9999717659263435), FRAC_CONST(0.9999734962093266), FRAC_CONST(0.9999751417254756), FRAC_CONST(0.9999767057107922), FRAC_CONST(0.9999781913087290), + FRAC_CONST(0.9999796015719915), FRAC_CONST(0.9999809394643231), FRAC_CONST(0.9999822078622751), FRAC_CONST(0.9999834095569596), FRAC_CONST(0.9999845472557860), FRAC_CONST(0.9999856235841805), + FRAC_CONST(0.9999866410872889), FRAC_CONST(0.9999876022316609), FRAC_CONST(0.9999885094069193), FRAC_CONST(0.9999893649274085), FRAC_CONST(0.9999901710338274), FRAC_CONST(0.9999909298948430), + FRAC_CONST(0.9999916436086862), FRAC_CONST(0.9999923142047299), FRAC_CONST(0.9999929436450469), FRAC_CONST(0.9999935338259505), FRAC_CONST(0.9999940865795161), FRAC_CONST(0.9999946036750835), + FRAC_CONST(0.9999950868207405), FRAC_CONST(0.9999955376647868), FRAC_CONST(0.9999959577971798), FRAC_CONST(0.9999963487509599), FRAC_CONST(0.9999967120036571), FRAC_CONST(0.9999970489786785), + FRAC_CONST(0.9999973610466748), FRAC_CONST(0.9999976495268890), FRAC_CONST(0.9999979156884846), FRAC_CONST(0.9999981607518545), FRAC_CONST(0.9999983858899099), FRAC_CONST(0.9999985922293493), + FRAC_CONST(0.9999987808519092), FRAC_CONST(0.9999989527955938), FRAC_CONST(0.9999991090558848), FRAC_CONST(0.9999992505869332), FRAC_CONST(0.9999993783027293), FRAC_CONST(0.9999994930782556), + FRAC_CONST(0.9999995957506171), FRAC_CONST(0.9999996871201549), FRAC_CONST(0.9999997679515386), FRAC_CONST(0.9999998389748399), FRAC_CONST(0.9999999008865869), FRAC_CONST(0.9999999543507984)}; +#endif +static const real_t kbd_short_128[] = { + FRAC_CONST(4.3795702929468881e-005), FRAC_CONST(0.00011867384265436617), FRAC_CONST(0.0002307165763996192), FRAC_CONST(0.00038947282760568383), FRAC_CONST(0.00060581272288302553), + FRAC_CONST(0.00089199695169487453), FRAC_CONST(0.0012617254423430522), FRAC_CONST(0.0017301724373162003), FRAC_CONST(0.0023140071937421476), FRAC_CONST(0.0030313989666022221), + FRAC_CONST(0.0039020049735530842), FRAC_CONST(0.0049469401815512024), FRAC_CONST(0.0061887279335368318), FRAC_CONST(0.0076512306364647726), FRAC_CONST(0.0093595599562652423), + FRAC_CONST(0.011339966208377799), FRAC_CONST(0.013619706891715299), FRAC_CONST(0.016226894586323766), FRAC_CONST(0.019190324717288168), FRAC_CONST(0.022539283975960878), + FRAC_CONST(0.026303340480472455), FRAC_CONST(0.030512117046644357), FRAC_CONST(0.03519504922365594), FRAC_CONST(0.040381130021856941), FRAC_CONST(0.046098643518702249), + FRAC_CONST(0.052374889768730587), FRAC_CONST(0.059235903660769147), FRAC_CONST(0.066706170556282418), FRAC_CONST(0.074808341703430481), FRAC_CONST(0.083562952548726227), + FRAC_CONST(0.092988147159339674), FRAC_CONST(0.1030994120216919), FRAC_CONST(0.11390932249409955), FRAC_CONST(0.12542730516149531), FRAC_CONST(0.13765941926783826), + FRAC_CONST(0.15060816028651081), FRAC_CONST(0.16427228853114245), FRAC_CONST(0.17864668550988483), FRAC_CONST(0.19372224048676889), FRAC_CONST(0.20948576943658073), + FRAC_CONST(0.22591996826744942), FRAC_CONST(0.24300340184133981), FRAC_CONST(0.26071052995068139), FRAC_CONST(0.27901177101369551), FRAC_CONST(0.29787360383626599), + FRAC_CONST(0.3172587073594233), FRAC_CONST(0.33712613787396362), FRAC_CONST(0.35743154274286698), FRAC_CONST(0.37812740923363009), FRAC_CONST(0.39916334663203618), + FRAC_CONST(0.42048639939189658), FRAC_CONST(0.4420413886774246), FRAC_CONST(0.4637712792815169), FRAC_CONST(0.4856175685594023), FRAC_CONST(0.50752069370766872), + FRAC_CONST(0.52942045344797806), FRAC_CONST(0.55125643994680196), FRAC_CONST(0.57296847662071559), FRAC_CONST(0.59449705734411495), FRAC_CONST(0.61578378249506627), + FRAC_CONST(0.63677178724712891), FRAC_CONST(0.65740615754163356), FRAC_CONST(0.67763432925662526), FRAC_CONST(0.69740646622548552), FRAC_CONST(0.71667581294953808), + FRAC_CONST(0.73539901809352737), FRAC_CONST(0.75353642514900732), FRAC_CONST(0.77105232699609816), FRAC_CONST(0.78791518148597028), FRAC_CONST(0.80409778560147072), + FRAC_CONST(0.81957740622770781), FRAC_CONST(0.83433586607383625), FRAC_CONST(0.84835958382689225), FRAC_CONST(0.86163956818294229), FRAC_CONST(0.87417136598406997), + FRAC_CONST(0.88595496528524853), FRAC_CONST(0.89699465477567619), FRAC_CONST(0.90729884157670959), FRAC_CONST(0.91687983002436779), FRAC_CONST(0.92575356460899649), + FRAC_CONST(0.93393934077779084), FRAC_CONST(0.94145948779657318), FRAC_CONST(0.94833902830402828), FRAC_CONST(0.95460531956280026), FRAC_CONST(0.96028768170574896), + FRAC_CONST(0.96541701848104766), FRAC_CONST(0.97002543610646474), FRAC_CONST(0.97414586584250062), FRAC_CONST(0.97781169577969584), FRAC_CONST(0.98105641710392333), + FRAC_CONST(0.98391328975491177), FRAC_CONST(0.98641503193166202), FRAC_CONST(0.98859353733226141), FRAC_CONST(0.99047962335771556), FRAC_CONST(0.9921028127769449), + FRAC_CONST(0.99349115056397752), FRAC_CONST(0.99467105680259038), FRAC_CONST(0.9956672157341897), FRAC_CONST(0.99650250022834352), FRAC_CONST(0.99719793020823266), + FRAC_CONST(0.99777266288955657), FRAC_CONST(0.99824401211201486), FRAC_CONST(0.99862749357391212), FRAC_CONST(0.99893689243401962), FRAC_CONST(0.99918434952623147), + FRAC_CONST(0.99938046234161726), FRAC_CONST(0.99953439696357238), FRAC_CONST(0.99965400728430465), FRAC_CONST(0.99974595807027455), FRAC_CONST(0.99981584876278362), + FRAC_CONST(0.99986833527824281), FRAC_CONST(0.99990724749057802), FRAC_CONST(0.99993570051598468), FRAC_CONST(0.99995619835942084), FRAC_CONST(0.99997072890647543), + FRAC_CONST(0.9999808496399144), FRAC_CONST(0.99998776381655818), FRAC_CONST(0.99999238714961569), FRAC_CONST(0.99999540529959718), FRAC_CONST(0.99999732268176988), + FRAC_CONST(0.99999850325054862), FRAC_CONST(0.99999920402413744), FRAC_CONST(0.9999996021706401), FRAC_CONST(0.99999981649545566), FRAC_CONST(0.99999992415545547), + FRAC_CONST(0.99999997338493041), FRAC_CONST(0.99999999295825959), FRAC_CONST(0.99999999904096815)}; +#ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t kbd_short_120[] = { + FRAC_CONST(0.0000452320086910), FRAC_CONST(0.0001274564692111), FRAC_CONST(0.0002529398385345), FRAC_CONST(0.0004335140496648), FRAC_CONST(0.0006827100966952), FRAC_CONST(0.0010158708222246), + FRAC_CONST(0.0014502162869659), FRAC_CONST(0.0020048865156264), FRAC_CONST(0.0027009618393178), FRAC_CONST(0.0035614590925043), FRAC_CONST(0.0046113018122711), FRAC_CONST(0.0058772627936484), + FRAC_CONST(0.0073878776584103), FRAC_CONST(0.0091733284512589), FRAC_CONST(0.0112652966728373), FRAC_CONST(0.0136967855861945), FRAC_CONST(0.0165019120857793), FRAC_CONST(0.0197156688892217), + FRAC_CONST(0.0233736582950619), FRAC_CONST(0.0275117992367496), FRAC_CONST(0.0321660098468534), FRAC_CONST(0.0373718682174417), FRAC_CONST(0.0431642544948834), FRAC_CONST(0.0495769778717676), + FRAC_CONST(0.0566423924273392), FRAC_CONST(0.0643910061132260), FRAC_CONST(0.0728510874761729), FRAC_CONST(0.0820482749475221), FRAC_CONST(0.0920051937045235), FRAC_CONST(0.1027410852163450), + FRAC_CONST(0.1142714546239370), FRAC_CONST(0.1266077410648368), FRAC_CONST(0.1397570159398145), FRAC_CONST(0.1537217139274270), FRAC_CONST(0.1684994012857075), FRAC_CONST(0.1840825856392944), + FRAC_CONST(0.2004585710384133), FRAC_CONST(0.2176093615976121), FRAC_CONST(0.2355116164824983), FRAC_CONST(0.2541366584185075), FRAC_CONST(0.2734505372545160), FRAC_CONST(0.2934141494343369), + FRAC_CONST(0.3139834135200387), FRAC_CONST(0.3351095011824163), FRAC_CONST(0.3567391223361566), FRAC_CONST(0.3788148623608774), FRAC_CONST(0.4012755686250732), FRAC_CONST(0.4240567828288110), + FRAC_CONST(0.4470912150133537), FRAC_CONST(0.4703092544619664), FRAC_CONST(0.4936395121456694), FRAC_CONST(0.5170093888596962), FRAC_CONST(0.5403456627591340), FRAC_CONST(0.5635750896430154), + FRAC_CONST(0.5866250090612892), FRAC_CONST(0.6094239491338723), FRAC_CONST(0.6319022228794100), FRAC_CONST(0.6539925088563087), FRAC_CONST(0.6756304090216887), FRAC_CONST(0.6967549769155277), + FRAC_CONST(0.7173092095766250), FRAC_CONST(0.7372404969921184), FRAC_CONST(0.7565010233699827), FRAC_CONST(0.7750481150999984), FRAC_CONST(0.7928445309277697), FRAC_CONST(0.8098586906021583), + FRAC_CONST(0.8260648390616000), FRAC_CONST(0.8414431440907889), FRAC_CONST(0.8559797262966709), FRAC_CONST(0.8696666212110165), FRAC_CONST(0.8825016743142358), FRAC_CONST(0.8944883707784486), + FRAC_CONST(0.9056356027326216), FRAC_CONST(0.9159573778427816), FRAC_CONST(0.9254724739583072), FRAC_CONST(0.9342040454819434), FRAC_CONST(0.9421791879559176), FRAC_CONST(0.9494284680976784), + FRAC_CONST(0.9559854271440150), FRAC_CONST(0.9618860658493898), FRAC_CONST(0.9671683198119525), FRAC_CONST(0.9718715339497299), FRAC_CONST(0.9760359449042233), FRAC_CONST(0.9797021798981759), + FRAC_CONST(0.9829107801140203), FRAC_CONST(0.9857017559923277), FRAC_CONST(0.9881141809867999), FRAC_CONST(0.9901858292742826), FRAC_CONST(0.9919528617340944), FRAC_CONST(0.9934495632180476), + FRAC_CONST(0.9947081327749199), FRAC_CONST(0.9957585271195989), FRAC_CONST(0.9966283562984427), FRAC_CONST(0.9973428292485683), FRAC_CONST(0.9979247458259197), FRAC_CONST(0.9983945309245774), + FRAC_CONST(0.9987703055583410), FRAC_CONST(0.9990679892449266), FRAC_CONST(0.9993014277313617), FRAC_CONST(0.9994825400228521), FRAC_CONST(0.9996214788122335), FRAC_CONST(0.9997267987294857), + FRAC_CONST(0.9998056273097539), FRAC_CONST(0.9998638341781910), FRAC_CONST(0.9999061946325793), FRAC_CONST(0.9999365445321382), FRAC_CONST(0.9999579241373735), FRAC_CONST(0.9999727092594598), + FRAC_CONST(0.9999827287418790), FRAC_CONST(0.9999893678912771), FRAC_CONST(0.9999936579844555), FRAC_CONST(0.9999963523959187), FRAC_CONST(0.9999979902130101), FRAC_CONST(0.9999989484358076), + FRAC_CONST(0.9999994840031031), FRAC_CONST(0.9999997669534347), FRAC_CONST(0.9999999060327799), FRAC_CONST(0.9999999680107184), FRAC_CONST(0.9999999918774242), FRAC_CONST(0.9999999989770326)}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sine_long_1024[] = { + FRAC_CONST(0.00076699031874270449), FRAC_CONST(0.002300969151425805), FRAC_CONST(0.0038349425697062275), FRAC_CONST(0.0053689069639963425), FRAC_CONST(0.0069028587247297558), + FRAC_CONST(0.0084367942423697988), FRAC_CONST(0.0099707099074180308), FRAC_CONST(0.011504602110422714), FRAC_CONST(0.013038467241987334), FRAC_CONST(0.014572301692779064), + FRAC_CONST(0.016106101853537287), FRAC_CONST(0.017639864115082053), FRAC_CONST(0.019173584868322623), FRAC_CONST(0.020707260504265895), FRAC_CONST(0.022240887414024961), + FRAC_CONST(0.023774461988827555), FRAC_CONST(0.025307980620024571), FRAC_CONST(0.026841439699098531), FRAC_CONST(0.028374835617672099), FRAC_CONST(0.029908164767516555), + FRAC_CONST(0.031441423540560301), FRAC_CONST(0.032974608328897335), FRAC_CONST(0.03450771552479575), FRAC_CONST(0.036040741520706229), FRAC_CONST(0.037573682709270494), + FRAC_CONST(0.039106535483329888), FRAC_CONST(0.040639296235933736), FRAC_CONST(0.042171961360347947), FRAC_CONST(0.043704527250063421), FRAC_CONST(0.04523699029880459), + FRAC_CONST(0.046769346900537863), FRAC_CONST(0.048301593449480144), FRAC_CONST(0.049833726340107277), FRAC_CONST(0.051365741967162593), FRAC_CONST(0.052897636725665324), + FRAC_CONST(0.054429407010919133), FRAC_CONST(0.055961049218520569), FRAC_CONST(0.057492559744367566), FRAC_CONST(0.059023934984667931), FRAC_CONST(0.060555171335947788), + FRAC_CONST(0.062086265195060088), FRAC_CONST(0.063617212959193106), FRAC_CONST(0.065148011025878833), FRAC_CONST(0.066678655793001557), FRAC_CONST(0.068209143658806329), + FRAC_CONST(0.069739471021907307), FRAC_CONST(0.071269634281296401), FRAC_CONST(0.072799629836351673), FRAC_CONST(0.074329454086845756), FRAC_CONST(0.075859103432954447), + FRAC_CONST(0.077388574275265049), FRAC_CONST(0.078917863014784942), FRAC_CONST(0.080446966052950014), FRAC_CONST(0.081975879791633066), FRAC_CONST(0.083504600633152432), + FRAC_CONST(0.085033124980280275), FRAC_CONST(0.08656144923625117), FRAC_CONST(0.088089569804770507), FRAC_CONST(0.089617483090022959), FRAC_CONST(0.091145185496681005), + FRAC_CONST(0.09267267342991331), FRAC_CONST(0.094199943295393204), FRAC_CONST(0.095726991499307162), FRAC_CONST(0.097253814448363271), FRAC_CONST(0.098780408549799623), + FRAC_CONST(0.10030677021139286), FRAC_CONST(0.10183289584146653), FRAC_CONST(0.10335878184889961), FRAC_CONST(0.10488442464313497), FRAC_CONST(0.10640982063418768), + FRAC_CONST(0.10793496623265365), FRAC_CONST(0.10945985784971798), FRAC_CONST(0.11098449189716339), FRAC_CONST(0.11250886478737869), FRAC_CONST(0.1140329729333672), + FRAC_CONST(0.11555681274875526), FRAC_CONST(0.11708038064780059), FRAC_CONST(0.11860367304540072), FRAC_CONST(0.1201266863571015), FRAC_CONST(0.12164941699910553), + FRAC_CONST(0.12317186138828048), FRAC_CONST(0.12469401594216764), FRAC_CONST(0.12621587707899035), FRAC_CONST(0.12773744121766231), FRAC_CONST(0.12925870477779614), + FRAC_CONST(0.13077966417971171), FRAC_CONST(0.13230031584444465), FRAC_CONST(0.13382065619375472), FRAC_CONST(0.13534068165013421), FRAC_CONST(0.13686038863681638), + FRAC_CONST(0.13837977357778389), FRAC_CONST(0.13989883289777721), FRAC_CONST(0.14141756302230302), FRAC_CONST(0.14293596037764267), FRAC_CONST(0.14445402139086047), + FRAC_CONST(0.14597174248981221), FRAC_CONST(0.14748912010315357), FRAC_CONST(0.14900615066034845), FRAC_CONST(0.1505228305916774), FRAC_CONST(0.15203915632824605), + FRAC_CONST(0.15355512430199345), FRAC_CONST(0.15507073094570051), FRAC_CONST(0.15658597269299843), FRAC_CONST(0.15810084597837698), FRAC_CONST(0.15961534723719306), + FRAC_CONST(0.16112947290567881), FRAC_CONST(0.16264321942095031), FRAC_CONST(0.16415658322101581), FRAC_CONST(0.16566956074478412), FRAC_CONST(0.16718214843207294), + FRAC_CONST(0.16869434272361733), FRAC_CONST(0.17020614006107807), FRAC_CONST(0.17171753688704997), FRAC_CONST(0.17322852964507032), FRAC_CONST(0.1747391147796272), + FRAC_CONST(0.17624928873616788), FRAC_CONST(0.17775904796110717), FRAC_CONST(0.17926838890183575), FRAC_CONST(0.18077730800672859), FRAC_CONST(0.1822858017251533), + FRAC_CONST(0.18379386650747845), FRAC_CONST(0.1853014988050819), FRAC_CONST(0.18680869507035927), FRAC_CONST(0.18831545175673212), FRAC_CONST(0.18982176531865641), + FRAC_CONST(0.1913276322116309), FRAC_CONST(0.19283304889220523), FRAC_CONST(0.1943380118179886), FRAC_CONST(0.19584251744765785), FRAC_CONST(0.19734656224096592), + FRAC_CONST(0.19885014265875009), FRAC_CONST(0.20035325516294045), FRAC_CONST(0.20185589621656805), FRAC_CONST(0.20335806228377332), FRAC_CONST(0.20485974982981442), + FRAC_CONST(0.20636095532107551), FRAC_CONST(0.20786167522507507), FRAC_CONST(0.20936190601047416), FRAC_CONST(0.21086164414708486), FRAC_CONST(0.21236088610587842), + FRAC_CONST(0.21385962835899375), FRAC_CONST(0.21535786737974555), FRAC_CONST(0.21685559964263262), FRAC_CONST(0.21835282162334632), FRAC_CONST(0.2198495297987787), + FRAC_CONST(0.22134572064703081), FRAC_CONST(0.22284139064742112), FRAC_CONST(0.2243365362804936), FRAC_CONST(0.22583115402802617), FRAC_CONST(0.22732524037303886), + FRAC_CONST(0.22881879179980222), FRAC_CONST(0.23031180479384544), FRAC_CONST(0.23180427584196478), FRAC_CONST(0.23329620143223159), FRAC_CONST(0.23478757805400097), + FRAC_CONST(0.23627840219791957), FRAC_CONST(0.23776867035593419), FRAC_CONST(0.23925837902129998), FRAC_CONST(0.24074752468858843), FRAC_CONST(0.24223610385369601), + FRAC_CONST(0.24372411301385216), FRAC_CONST(0.24521154866762754), FRAC_CONST(0.24669840731494241), FRAC_CONST(0.24818468545707478), FRAC_CONST(0.24967037959666857), + FRAC_CONST(0.25115548623774192), FRAC_CONST(0.25264000188569552), FRAC_CONST(0.25412392304732062), FRAC_CONST(0.25560724623080738), FRAC_CONST(0.25708996794575312), + FRAC_CONST(0.25857208470317034), FRAC_CONST(0.26005359301549519), FRAC_CONST(0.26153448939659552), FRAC_CONST(0.263014770361779), FRAC_CONST(0.26449443242780163), + FRAC_CONST(0.26597347211287559), FRAC_CONST(0.26745188593667762), FRAC_CONST(0.26892967042035726), FRAC_CONST(0.27040682208654482), FRAC_CONST(0.27188333745935972), + FRAC_CONST(0.27335921306441868), FRAC_CONST(0.27483444542884394), FRAC_CONST(0.27630903108127108), FRAC_CONST(0.27778296655185769), FRAC_CONST(0.27925624837229118), + FRAC_CONST(0.28072887307579719), FRAC_CONST(0.28220083719714756), FRAC_CONST(0.28367213727266843), FRAC_CONST(0.28514276984024867), FRAC_CONST(0.28661273143934779), + FRAC_CONST(0.28808201861100413), FRAC_CONST(0.28955062789784303), FRAC_CONST(0.29101855584408509), FRAC_CONST(0.29248579899555388), FRAC_CONST(0.29395235389968466), + FRAC_CONST(0.29541821710553201), FRAC_CONST(0.29688338516377827), FRAC_CONST(0.2983478546267414), FRAC_CONST(0.29981162204838335), FRAC_CONST(0.30127468398431795), + FRAC_CONST(0.30273703699181914), FRAC_CONST(0.30419867762982911), FRAC_CONST(0.30565960245896612), FRAC_CONST(0.3071198080415331), FRAC_CONST(0.30857929094152509), + FRAC_CONST(0.31003804772463789), FRAC_CONST(0.31149607495827591), FRAC_CONST(0.3129533692115602), FRAC_CONST(0.31440992705533666), FRAC_CONST(0.31586574506218396), + FRAC_CONST(0.31732081980642174), FRAC_CONST(0.31877514786411848), FRAC_CONST(0.32022872581309986), FRAC_CONST(0.32168155023295658), FRAC_CONST(0.32313361770505233), + FRAC_CONST(0.32458492481253215), FRAC_CONST(0.32603546814033024), FRAC_CONST(0.327485244275178), FRAC_CONST(0.3289342498056122), FRAC_CONST(0.33038248132198278), + FRAC_CONST(0.33182993541646111), FRAC_CONST(0.33327660868304793), FRAC_CONST(0.33472249771758122), FRAC_CONST(0.33616759911774452), FRAC_CONST(0.33761190948307462), + FRAC_CONST(0.33905542541496964), FRAC_CONST(0.34049814351669716), FRAC_CONST(0.34194006039340219), FRAC_CONST(0.34338117265211504), FRAC_CONST(0.34482147690175929), + FRAC_CONST(0.34626096975316001), FRAC_CONST(0.34769964781905138), FRAC_CONST(0.34913750771408497), FRAC_CONST(0.35057454605483751), FRAC_CONST(0.35201075945981908), + FRAC_CONST(0.35344614454948081), FRAC_CONST(0.35488069794622279), FRAC_CONST(0.35631441627440241), FRAC_CONST(0.3577472961603419), FRAC_CONST(0.3591793342323365), + FRAC_CONST(0.36061052712066227), FRAC_CONST(0.36204087145758418), FRAC_CONST(0.36347036387736376), FRAC_CONST(0.36489900101626732), FRAC_CONST(0.36632677951257359), + FRAC_CONST(0.36775369600658198), FRAC_CONST(0.36917974714062002), FRAC_CONST(0.37060492955905167), FRAC_CONST(0.37202923990828501), FRAC_CONST(0.3734526748367803), + FRAC_CONST(0.37487523099505754), FRAC_CONST(0.37629690503570479), FRAC_CONST(0.37771769361338564), FRAC_CONST(0.37913759338484732), FRAC_CONST(0.38055660100892852), + FRAC_CONST(0.38197471314656722), FRAC_CONST(0.38339192646080866), FRAC_CONST(0.38480823761681288), FRAC_CONST(0.38622364328186298), FRAC_CONST(0.38763814012537273), + FRAC_CONST(0.38905172481889438), FRAC_CONST(0.39046439403612659), FRAC_CONST(0.39187614445292235), FRAC_CONST(0.3932869727472964), FRAC_CONST(0.39469687559943356), + FRAC_CONST(0.39610584969169627), FRAC_CONST(0.39751389170863233), FRAC_CONST(0.39892099833698291), FRAC_CONST(0.40032716626569009), FRAC_CONST(0.40173239218590501), + FRAC_CONST(0.4031366727909953), FRAC_CONST(0.404540004776553), FRAC_CONST(0.40594238484040251), FRAC_CONST(0.40734380968260797), FRAC_CONST(0.40874427600548136), + FRAC_CONST(0.41014378051359024), FRAC_CONST(0.41154231991376522), FRAC_CONST(0.41293989091510808), FRAC_CONST(0.4143364902289991), FRAC_CONST(0.41573211456910536), + FRAC_CONST(0.41712676065138787), FRAC_CONST(0.4185204251941097), FRAC_CONST(0.41991310491784362), FRAC_CONST(0.42130479654547964), FRAC_CONST(0.42269549680223295), + FRAC_CONST(0.42408520241565156), FRAC_CONST(0.4254739101156238), FRAC_CONST(0.42686161663438643), FRAC_CONST(0.42824831870653196), FRAC_CONST(0.42963401306901638), + FRAC_CONST(0.43101869646116703), FRAC_CONST(0.43240236562469014), FRAC_CONST(0.43378501730367852), FRAC_CONST(0.43516664824461926), FRAC_CONST(0.4365472551964012), + FRAC_CONST(0.43792683491032286), FRAC_CONST(0.43930538414009995), FRAC_CONST(0.4406828996418729), FRAC_CONST(0.4420593781742147), FRAC_CONST(0.44343481649813848), + FRAC_CONST(0.44480921137710488), FRAC_CONST(0.44618255957703007), FRAC_CONST(0.44755485786629301), FRAC_CONST(0.44892610301574326), FRAC_CONST(0.45029629179870861), + FRAC_CONST(0.45166542099100249), FRAC_CONST(0.45303348737093158), FRAC_CONST(0.45440048771930358), FRAC_CONST(0.45576641881943464), FRAC_CONST(0.45713127745715698), + FRAC_CONST(0.45849506042082627), FRAC_CONST(0.45985776450132954), FRAC_CONST(0.46121938649209238), FRAC_CONST(0.46257992318908681), FRAC_CONST(0.46393937139083852), + FRAC_CONST(0.4652977278984346), FRAC_CONST(0.46665498951553092), FRAC_CONST(0.46801115304835983), FRAC_CONST(0.46936621530573752), FRAC_CONST(0.4707201730990716), + FRAC_CONST(0.47207302324236866), FRAC_CONST(0.47342476255224153), FRAC_CONST(0.47477538784791712), FRAC_CONST(0.47612489595124358), FRAC_CONST(0.47747328368669806), + FRAC_CONST(0.47882054788139389), FRAC_CONST(0.48016668536508839), FRAC_CONST(0.48151169297018986), FRAC_CONST(0.48285556753176567), FRAC_CONST(0.48419830588754903), + FRAC_CONST(0.48553990487794696), FRAC_CONST(0.48688036134604734), FRAC_CONST(0.48821967213762679), FRAC_CONST(0.48955783410115744), FRAC_CONST(0.49089484408781509), + FRAC_CONST(0.49223069895148602), FRAC_CONST(0.49356539554877477), FRAC_CONST(0.49489893073901126), FRAC_CONST(0.49623130138425825), FRAC_CONST(0.49756250434931915), + FRAC_CONST(0.49889253650174459), FRAC_CONST(0.50022139471184068), FRAC_CONST(0.50154907585267539), FRAC_CONST(0.50287557680008699), FRAC_CONST(0.50420089443269034), + FRAC_CONST(0.50552502563188539), FRAC_CONST(0.50684796728186321), FRAC_CONST(0.5081697162696146), FRAC_CONST(0.50949026948493636), FRAC_CONST(0.51080962382043904), + FRAC_CONST(0.51212777617155469), FRAC_CONST(0.51344472343654346), FRAC_CONST(0.5147604625165012), FRAC_CONST(0.51607499031536663), FRAC_CONST(0.51738830373992906), + FRAC_CONST(0.51870039969983495), FRAC_CONST(0.52001127510759604), FRAC_CONST(0.52132092687859566), FRAC_CONST(0.52262935193109661), FRAC_CONST(0.5239365471862486), + FRAC_CONST(0.52524250956809471), FRAC_CONST(0.52654723600357944), FRAC_CONST(0.52785072342255523), FRAC_CONST(0.52915296875779061), FRAC_CONST(0.53045396894497632), + FRAC_CONST(0.53175372092273332), FRAC_CONST(0.53305222163261945), FRAC_CONST(0.53434946801913752), FRAC_CONST(0.53564545702974109), FRAC_CONST(0.53694018561484291), + FRAC_CONST(0.5382336507278217), FRAC_CONST(0.53952584932502889), FRAC_CONST(0.54081677836579667), FRAC_CONST(0.54210643481244392), FRAC_CONST(0.5433948156302848), + FRAC_CONST(0.54468191778763453), FRAC_CONST(0.54596773825581757), FRAC_CONST(0.54725227400917409), FRAC_CONST(0.54853552202506739), FRAC_CONST(0.54981747928389091), + FRAC_CONST(0.55109814276907543), FRAC_CONST(0.55237750946709607), FRAC_CONST(0.55365557636747931), FRAC_CONST(0.55493234046281037), FRAC_CONST(0.55620779874873993), + FRAC_CONST(0.55748194822399155), FRAC_CONST(0.55875478589036831), FRAC_CONST(0.56002630875276038), FRAC_CONST(0.56129651381915147), FRAC_CONST(0.56256539810062656), + FRAC_CONST(0.56383295861137817), FRAC_CONST(0.56509919236871398), FRAC_CONST(0.56636409639306384), FRAC_CONST(0.56762766770798623), FRAC_CONST(0.56888990334017586), + FRAC_CONST(0.5701508003194703), FRAC_CONST(0.57141035567885723), FRAC_CONST(0.57266856645448116), FRAC_CONST(0.57392542968565075), FRAC_CONST(0.57518094241484508), + FRAC_CONST(0.57643510168772183), FRAC_CONST(0.5776879045531228), FRAC_CONST(0.57893934806308178), FRAC_CONST(0.58018942927283168), FRAC_CONST(0.58143814524081017), + FRAC_CONST(0.58268549302866846), FRAC_CONST(0.58393146970127618), FRAC_CONST(0.58517607232673041), FRAC_CONST(0.5864192979763605), FRAC_CONST(0.58766114372473666), + FRAC_CONST(0.58890160664967572), FRAC_CONST(0.59014068383224882), FRAC_CONST(0.59137837235678758), FRAC_CONST(0.59261466931089113), FRAC_CONST(0.59384957178543363), + FRAC_CONST(0.59508307687456996), FRAC_CONST(0.59631518167574371), FRAC_CONST(0.59754588328969316), FRAC_CONST(0.59877517882045872), FRAC_CONST(0.60000306537538894), + FRAC_CONST(0.6012295400651485), FRAC_CONST(0.60245460000372375), FRAC_CONST(0.60367824230843037), FRAC_CONST(0.60490046409991982), FRAC_CONST(0.60612126250218612), + FRAC_CONST(0.60734063464257293), FRAC_CONST(0.60855857765177945), FRAC_CONST(0.60977508866386843), FRAC_CONST(0.61099016481627166), FRAC_CONST(0.61220380324979795), + FRAC_CONST(0.61341600110863859), FRAC_CONST(0.61462675554037505), FRAC_CONST(0.61583606369598509), FRAC_CONST(0.61704392272984976), FRAC_CONST(0.61825032979976025), + FRAC_CONST(0.61945528206692402), FRAC_CONST(0.62065877669597214), FRAC_CONST(0.62186081085496536), FRAC_CONST(0.62306138171540126), FRAC_CONST(0.62426048645222065), + FRAC_CONST(0.62545812224381436), FRAC_CONST(0.62665428627202935), FRAC_CONST(0.62784897572217646), FRAC_CONST(0.629042187783036), FRAC_CONST(0.63023391964686437), + FRAC_CONST(0.63142416850940186), FRAC_CONST(0.63261293156987741), FRAC_CONST(0.63380020603101728), FRAC_CONST(0.63498598909904946), FRAC_CONST(0.63617027798371217), + FRAC_CONST(0.63735306989825913), FRAC_CONST(0.63853436205946679), FRAC_CONST(0.63971415168764045), FRAC_CONST(0.64089243600662138), FRAC_CONST(0.64206921224379254), + FRAC_CONST(0.64324447763008585), FRAC_CONST(0.64441822939998838), FRAC_CONST(0.64559046479154869), FRAC_CONST(0.64676118104638392), FRAC_CONST(0.64793037540968534), + FRAC_CONST(0.64909804513022595), FRAC_CONST(0.65026418746036585), FRAC_CONST(0.65142879965605982), FRAC_CONST(0.65259187897686244), FRAC_CONST(0.65375342268593606), + FRAC_CONST(0.65491342805005603), FRAC_CONST(0.6560718923396176), FRAC_CONST(0.65722881282864254), FRAC_CONST(0.65838418679478505), FRAC_CONST(0.65953801151933866), + FRAC_CONST(0.6606902842872423), FRAC_CONST(0.66184100238708687), FRAC_CONST(0.66299016311112147), FRAC_CONST(0.66413776375526001), FRAC_CONST(0.66528380161908718), + FRAC_CONST(0.66642827400586524), FRAC_CONST(0.66757117822254031), FRAC_CONST(0.66871251157974798), FRAC_CONST(0.66985227139182102), FRAC_CONST(0.67099045497679422), + FRAC_CONST(0.67212705965641173), FRAC_CONST(0.67326208275613297), FRAC_CONST(0.67439552160513905), FRAC_CONST(0.67552737353633852), FRAC_CONST(0.67665763588637495), + FRAC_CONST(0.6777863059956315), FRAC_CONST(0.67891338120823841), FRAC_CONST(0.68003885887207893), FRAC_CONST(0.68116273633879543), FRAC_CONST(0.68228501096379557), + FRAC_CONST(0.68340568010625868), FRAC_CONST(0.6845247411291423), FRAC_CONST(0.68564219139918747), FRAC_CONST(0.68675802828692589), FRAC_CONST(0.68787224916668555), + FRAC_CONST(0.68898485141659704), FRAC_CONST(0.69009583241859995), FRAC_CONST(0.69120518955844845), FRAC_CONST(0.69231292022571822), FRAC_CONST(0.69341902181381176), + FRAC_CONST(0.69452349171996552), FRAC_CONST(0.69562632734525487), FRAC_CONST(0.6967275260946012), FRAC_CONST(0.69782708537677729), FRAC_CONST(0.69892500260441415), + FRAC_CONST(0.70002127519400625), FRAC_CONST(0.70111590056591866), FRAC_CONST(0.70220887614439187), FRAC_CONST(0.70330019935754873), FRAC_CONST(0.70438986763740041), + FRAC_CONST(0.7054778784198521), FRAC_CONST(0.70656422914470951), FRAC_CONST(0.70764891725568435), FRAC_CONST(0.70873194020040065), FRAC_CONST(0.70981329543040084), + FRAC_CONST(0.71089298040115168), FRAC_CONST(0.71197099257204999), FRAC_CONST(0.71304732940642923), FRAC_CONST(0.71412198837156471), FRAC_CONST(0.71519496693868001), + FRAC_CONST(0.71626626258295312), FRAC_CONST(0.71733587278352173), FRAC_CONST(0.71840379502348972), FRAC_CONST(0.71947002678993299), FRAC_CONST(0.72053456557390527), + FRAC_CONST(0.72159740887044366), FRAC_CONST(0.72265855417857561), FRAC_CONST(0.72371799900132339), FRAC_CONST(0.72477574084571128), FRAC_CONST(0.72583177722277037), + FRAC_CONST(0.72688610564754497), FRAC_CONST(0.72793872363909862), FRAC_CONST(0.72898962872051931), FRAC_CONST(0.73003881841892615), FRAC_CONST(0.73108629026547423), + FRAC_CONST(0.73213204179536129), FRAC_CONST(0.73317607054783274), FRAC_CONST(0.73421837406618817), FRAC_CONST(0.73525894989778673), FRAC_CONST(0.73629779559405306), + FRAC_CONST(0.73733490871048279), FRAC_CONST(0.73837028680664851), FRAC_CONST(0.73940392744620576), FRAC_CONST(0.74043582819689802), FRAC_CONST(0.74146598663056329), + FRAC_CONST(0.74249440032313918), FRAC_CONST(0.74352106685466912), FRAC_CONST(0.74454598380930725), FRAC_CONST(0.74556914877532543), FRAC_CONST(0.74659055934511731), + FRAC_CONST(0.74761021311520515), FRAC_CONST(0.74862810768624533), FRAC_CONST(0.74964424066303348), FRAC_CONST(0.75065860965451059), FRAC_CONST(0.75167121227376843), + FRAC_CONST(0.75268204613805523), FRAC_CONST(0.75369110886878121), FRAC_CONST(0.75469839809152439), FRAC_CONST(0.75570391143603588), FRAC_CONST(0.75670764653624567), + FRAC_CONST(0.75770960103026808), FRAC_CONST(0.75870977256040739), FRAC_CONST(0.75970815877316344), FRAC_CONST(0.76070475731923692), FRAC_CONST(0.76169956585353527), + FRAC_CONST(0.76269258203517787), FRAC_CONST(0.76368380352750187), FRAC_CONST(0.76467322799806714), FRAC_CONST(0.76566085311866239), FRAC_CONST(0.76664667656531038), + FRAC_CONST(0.76763069601827327), FRAC_CONST(0.76861290916205827), FRAC_CONST(0.76959331368542294), FRAC_CONST(0.7705719072813807), FRAC_CONST(0.7715486876472063), + FRAC_CONST(0.77252365248444133), FRAC_CONST(0.77349679949889905), FRAC_CONST(0.77446812640067086), FRAC_CONST(0.77543763090413043), FRAC_CONST(0.77640531072794039), + FRAC_CONST(0.7773711635950562), FRAC_CONST(0.77833518723273309), FRAC_CONST(0.7792973793725303), FRAC_CONST(0.78025773775031659), FRAC_CONST(0.78121626010627609), + FRAC_CONST(0.7821729441849129), FRAC_CONST(0.78312778773505731), FRAC_CONST(0.78408078850986995), FRAC_CONST(0.78503194426684808), FRAC_CONST(0.78598125276783015), + FRAC_CONST(0.7869287117790017), FRAC_CONST(0.78787431907090011), FRAC_CONST(0.78881807241842017), FRAC_CONST(0.78975996960081907), FRAC_CONST(0.79070000840172161), + FRAC_CONST(0.79163818660912577), FRAC_CONST(0.79257450201540758), FRAC_CONST(0.79350895241732666), FRAC_CONST(0.79444153561603059), FRAC_CONST(0.79537224941706119), + FRAC_CONST(0.79630109163035911), FRAC_CONST(0.7972280600702687), FRAC_CONST(0.79815315255554375), FRAC_CONST(0.79907636690935235), FRAC_CONST(0.79999770095928191), + FRAC_CONST(0.8009171525373443), FRAC_CONST(0.80183471947998131), FRAC_CONST(0.80275039962806916), FRAC_CONST(0.80366419082692409), FRAC_CONST(0.804576090926307), + FRAC_CONST(0.80548609778042912), FRAC_CONST(0.80639420924795624), FRAC_CONST(0.80730042319201445), FRAC_CONST(0.80820473748019472), FRAC_CONST(0.80910714998455813), + FRAC_CONST(0.81000765858164114), FRAC_CONST(0.81090626115245967), FRAC_CONST(0.81180295558251536), FRAC_CONST(0.81269773976179949), FRAC_CONST(0.81359061158479851), + FRAC_CONST(0.81448156895049861), FRAC_CONST(0.81537060976239129), FRAC_CONST(0.81625773192847739), FRAC_CONST(0.81714293336127297), FRAC_CONST(0.81802621197781344), + FRAC_CONST(0.81890756569965895), FRAC_CONST(0.81978699245289899), FRAC_CONST(0.82066449016815746), FRAC_CONST(0.82154005678059761), FRAC_CONST(0.82241369022992639), + FRAC_CONST(0.82328538846040011), FRAC_CONST(0.82415514942082857), FRAC_CONST(0.82502297106458022), FRAC_CONST(0.82588885134958678), FRAC_CONST(0.82675278823834852), + FRAC_CONST(0.8276147796979384), FRAC_CONST(0.82847482370000713), FRAC_CONST(0.82933291822078825), FRAC_CONST(0.83018906124110237), FRAC_CONST(0.83104325074636232), + FRAC_CONST(0.83189548472657759), FRAC_CONST(0.83274576117635946), FRAC_CONST(0.83359407809492514), FRAC_CONST(0.83444043348610319), FRAC_CONST(0.83528482535833737), + FRAC_CONST(0.83612725172469216), FRAC_CONST(0.83696771060285702), FRAC_CONST(0.83780620001515094), FRAC_CONST(0.8386427179885273), FRAC_CONST(0.83947726255457855), + FRAC_CONST(0.84030983174954077), FRAC_CONST(0.84114042361429808), FRAC_CONST(0.84196903619438768), FRAC_CONST(0.84279566754000412), FRAC_CONST(0.84362031570600404), + FRAC_CONST(0.84444297875191066), FRAC_CONST(0.84526365474191822), FRAC_CONST(0.84608234174489694), FRAC_CONST(0.84689903783439735), FRAC_CONST(0.84771374108865427), + FRAC_CONST(0.84852644959059265), FRAC_CONST(0.84933716142783067), FRAC_CONST(0.85014587469268521), FRAC_CONST(0.85095258748217573), FRAC_CONST(0.85175729789802912), + FRAC_CONST(0.85256000404668397), FRAC_CONST(0.85336070403929543), FRAC_CONST(0.85415939599173873), FRAC_CONST(0.85495607802461482), FRAC_CONST(0.85575074826325392), + FRAC_CONST(0.85654340483771996), FRAC_CONST(0.85733404588281559), FRAC_CONST(0.85812266953808602), FRAC_CONST(0.8589092739478239), FRAC_CONST(0.85969385726107261), + FRAC_CONST(0.86047641763163207), FRAC_CONST(0.86125695321806206), FRAC_CONST(0.86203546218368721), FRAC_CONST(0.86281194269660033), FRAC_CONST(0.86358639292966799), + FRAC_CONST(0.86435881106053403), FRAC_CONST(0.86512919527162369), FRAC_CONST(0.86589754375014882), FRAC_CONST(0.86666385468811102), FRAC_CONST(0.86742812628230692), + FRAC_CONST(0.86819035673433131), FRAC_CONST(0.86895054425058238), FRAC_CONST(0.86970868704226556), FRAC_CONST(0.87046478332539767), FRAC_CONST(0.8712188313208109), + FRAC_CONST(0.8719708292541577), FRAC_CONST(0.8727207753559143), FRAC_CONST(0.87346866786138488), FRAC_CONST(0.8742145050107063), FRAC_CONST(0.87495828504885154), + FRAC_CONST(0.8757000062256346), FRAC_CONST(0.87643966679571361), FRAC_CONST(0.87717726501859594), FRAC_CONST(0.87791279915864173), FRAC_CONST(0.87864626748506813), + FRAC_CONST(0.87937766827195318), FRAC_CONST(0.88010699979824036), FRAC_CONST(0.88083426034774204), FRAC_CONST(0.88155944820914378), FRAC_CONST(0.8822825616760086), + FRAC_CONST(0.88300359904678072), FRAC_CONST(0.88372255862478966), FRAC_CONST(0.8844394387182537), FRAC_CONST(0.88515423764028511), FRAC_CONST(0.88586695370889279), + FRAC_CONST(0.88657758524698704), FRAC_CONST(0.88728613058238315), FRAC_CONST(0.88799258804780556), FRAC_CONST(0.88869695598089171), FRAC_CONST(0.88939923272419552), + FRAC_CONST(0.89009941662519221), FRAC_CONST(0.89079750603628149), FRAC_CONST(0.89149349931479138), FRAC_CONST(0.89218739482298248), FRAC_CONST(0.89287919092805168), + FRAC_CONST(0.89356888600213602), FRAC_CONST(0.89425647842231604), FRAC_CONST(0.89494196657062075), FRAC_CONST(0.89562534883403), FRAC_CONST(0.89630662360447966), + FRAC_CONST(0.89698578927886397), FRAC_CONST(0.89766284425904075), FRAC_CONST(0.89833778695183419), FRAC_CONST(0.89901061576903907), FRAC_CONST(0.89968132912742393), + FRAC_CONST(0.9003499254487356), FRAC_CONST(0.90101640315970233), FRAC_CONST(0.90168076069203773), FRAC_CONST(0.9023429964824442), FRAC_CONST(0.90300310897261704), + FRAC_CONST(0.90366109660924798), FRAC_CONST(0.90431695784402832), FRAC_CONST(0.90497069113365325), FRAC_CONST(0.90562229493982516), FRAC_CONST(0.90627176772925766), + FRAC_CONST(0.90691910797367803), FRAC_CONST(0.90756431414983252), FRAC_CONST(0.9082073847394887), FRAC_CONST(0.90884831822943912), FRAC_CONST(0.90948711311150543), + FRAC_CONST(0.91012376788254157), FRAC_CONST(0.91075828104443757), FRAC_CONST(0.91139065110412232), FRAC_CONST(0.91202087657356823), FRAC_CONST(0.9126489559697939), + FRAC_CONST(0.91327488781486776), FRAC_CONST(0.91389867063591168), FRAC_CONST(0.91452030296510445), FRAC_CONST(0.91513978333968526), FRAC_CONST(0.91575711030195672), + FRAC_CONST(0.91637228239928914), FRAC_CONST(0.91698529818412289), FRAC_CONST(0.91759615621397295), FRAC_CONST(0.9182048550514309), FRAC_CONST(0.91881139326416994), + FRAC_CONST(0.91941576942494696), FRAC_CONST(0.92001798211160657), FRAC_CONST(0.92061802990708386), FRAC_CONST(0.92121591139940873), FRAC_CONST(0.92181162518170812), + FRAC_CONST(0.92240516985220988), FRAC_CONST(0.92299654401424625), FRAC_CONST(0.92358574627625656), FRAC_CONST(0.9241727752517912), FRAC_CONST(0.92475762955951391), + FRAC_CONST(0.9253403078232062), FRAC_CONST(0.92592080867176996), FRAC_CONST(0.92649913073923051), FRAC_CONST(0.9270752726647401), FRAC_CONST(0.92764923309258118), + FRAC_CONST(0.92822101067216944), FRAC_CONST(0.92879060405805702), FRAC_CONST(0.9293580119099355), FRAC_CONST(0.92992323289263956), FRAC_CONST(0.93048626567614978), + FRAC_CONST(0.93104710893559517), FRAC_CONST(0.93160576135125783), FRAC_CONST(0.93216222160857432), FRAC_CONST(0.93271648839814025), FRAC_CONST(0.93326856041571205), + FRAC_CONST(0.93381843636221096), FRAC_CONST(0.9343661149437259), FRAC_CONST(0.93491159487151609), FRAC_CONST(0.93545487486201462), FRAC_CONST(0.9359959536368313), + FRAC_CONST(0.9365348299227555), FRAC_CONST(0.93707150245175919), FRAC_CONST(0.93760596996099999), FRAC_CONST(0.93813823119282436), FRAC_CONST(0.93866828489477017), + FRAC_CONST(0.9391961298195699), FRAC_CONST(0.93972176472515334), FRAC_CONST(0.94024518837465088), FRAC_CONST(0.94076639953639607), FRAC_CONST(0.94128539698392866), + FRAC_CONST(0.94180217949599765), FRAC_CONST(0.94231674585656378), FRAC_CONST(0.94282909485480271), FRAC_CONST(0.94333922528510772), FRAC_CONST(0.94384713594709269), + FRAC_CONST(0.94435282564559475), FRAC_CONST(0.94485629319067721), FRAC_CONST(0.94535753739763229), FRAC_CONST(0.94585655708698391), FRAC_CONST(0.94635335108449059), + FRAC_CONST(0.946847918221148), FRAC_CONST(0.94734025733319194), FRAC_CONST(0.94783036726210101), FRAC_CONST(0.94831824685459909), FRAC_CONST(0.94880389496265838), + FRAC_CONST(0.94928731044350201), FRAC_CONST(0.94976849215960668), FRAC_CONST(0.95024743897870523), FRAC_CONST(0.95072414977378961), FRAC_CONST(0.95119862342311323), + FRAC_CONST(0.95167085881019386), FRAC_CONST(0.95214085482381583), FRAC_CONST(0.95260861035803324), FRAC_CONST(0.9530741243121722), FRAC_CONST(0.95353739559083328), + FRAC_CONST(0.95399842310389449), FRAC_CONST(0.95445720576651349), FRAC_CONST(0.95491374249913052), FRAC_CONST(0.95536803222747024), FRAC_CONST(0.95582007388254542), + FRAC_CONST(0.95626986640065814), FRAC_CONST(0.95671740872340305), FRAC_CONST(0.9571626997976701), FRAC_CONST(0.95760573857564624), FRAC_CONST(0.9580465240148186), + FRAC_CONST(0.9584850550779761), FRAC_CONST(0.95892133073321306), FRAC_CONST(0.95935534995393079), FRAC_CONST(0.9597871117188399), FRAC_CONST(0.96021661501196343), + FRAC_CONST(0.96064385882263847), FRAC_CONST(0.96106884214551935), FRAC_CONST(0.961491563980579), FRAC_CONST(0.9619120233331121), FRAC_CONST(0.9623302192137374), + FRAC_CONST(0.96274615063839941), FRAC_CONST(0.96315981662837136), FRAC_CONST(0.96357121621025721), FRAC_CONST(0.96398034841599411), FRAC_CONST(0.96438721228285429), + FRAC_CONST(0.9647918068534479), FRAC_CONST(0.96519413117572472), FRAC_CONST(0.96559418430297683), FRAC_CONST(0.96599196529384057), FRAC_CONST(0.96638747321229879), + FRAC_CONST(0.96678070712768327), FRAC_CONST(0.96717166611467664), FRAC_CONST(0.96756034925331436), FRAC_CONST(0.9679467556289878), FRAC_CONST(0.9683308843324453), + FRAC_CONST(0.96871273445979478), FRAC_CONST(0.9690923051125061), FRAC_CONST(0.96946959539741295), FRAC_CONST(0.96984460442671483), FRAC_CONST(0.97021733131797916), + FRAC_CONST(0.97058777519414363), FRAC_CONST(0.97095593518351797), FRAC_CONST(0.97132181041978616), FRAC_CONST(0.97168540004200854), FRAC_CONST(0.9720467031946235), + FRAC_CONST(0.97240571902744977), FRAC_CONST(0.97276244669568857), FRAC_CONST(0.97311688535992513), FRAC_CONST(0.97346903418613095), FRAC_CONST(0.9738188923456661), + FRAC_CONST(0.97416645901528032), FRAC_CONST(0.97451173337711572), FRAC_CONST(0.97485471461870843), FRAC_CONST(0.97519540193299037), FRAC_CONST(0.97553379451829136), + FRAC_CONST(0.97586989157834103), FRAC_CONST(0.97620369232227056), FRAC_CONST(0.97653519596461447), FRAC_CONST(0.97686440172531264), FRAC_CONST(0.97719130882971228), + FRAC_CONST(0.97751591650856928), FRAC_CONST(0.97783822399805043), FRAC_CONST(0.97815823053973505), FRAC_CONST(0.97847593538061683), FRAC_CONST(0.97879133777310567), + FRAC_CONST(0.97910443697502925), FRAC_CONST(0.97941523224963478), FRAC_CONST(0.97972372286559117), FRAC_CONST(0.98002990809698998), FRAC_CONST(0.98033378722334796), + FRAC_CONST(0.98063535952960812), FRAC_CONST(0.98093462430614164), FRAC_CONST(0.98123158084874973), FRAC_CONST(0.98152622845866466), FRAC_CONST(0.9818185664425525), + FRAC_CONST(0.98210859411251361), FRAC_CONST(0.98239631078608469), FRAC_CONST(0.98268171578624086), FRAC_CONST(0.98296480844139644), FRAC_CONST(0.98324558808540707), + FRAC_CONST(0.98352405405757126), FRAC_CONST(0.98380020570263149), FRAC_CONST(0.98407404237077645), FRAC_CONST(0.9843455634176419), FRAC_CONST(0.9846147682043126), + FRAC_CONST(0.9848816560973237), FRAC_CONST(0.98514622646866223), FRAC_CONST(0.98540847869576842), FRAC_CONST(0.98566841216153755), FRAC_CONST(0.98592602625432113), + FRAC_CONST(0.98618132036792827), FRAC_CONST(0.98643429390162707), FRAC_CONST(0.98668494626014669), FRAC_CONST(0.98693327685367771), FRAC_CONST(0.98717928509787434), + FRAC_CONST(0.98742297041385541), FRAC_CONST(0.98766433222820571), FRAC_CONST(0.98790336997297779), FRAC_CONST(0.98814008308569257), FRAC_CONST(0.98837447100934128), + FRAC_CONST(0.98860653319238645), FRAC_CONST(0.98883626908876354), FRAC_CONST(0.98906367815788154), FRAC_CONST(0.98928875986462517), FRAC_CONST(0.98951151367935519), + FRAC_CONST(0.98973193907791057), FRAC_CONST(0.98995003554160899), FRAC_CONST(0.9901658025572484), FRAC_CONST(0.99037923961710816), FRAC_CONST(0.99059034621895015), + FRAC_CONST(0.99079912186602037), FRAC_CONST(0.99100556606704937), FRAC_CONST(0.99120967833625406), FRAC_CONST(0.99141145819333854), FRAC_CONST(0.99161090516349537), + FRAC_CONST(0.99180801877740643), FRAC_CONST(0.99200279857124452), FRAC_CONST(0.99219524408667392), FRAC_CONST(0.99238535487085167), FRAC_CONST(0.99257313047642881), + FRAC_CONST(0.99275857046155114), FRAC_CONST(0.99294167438986047), FRAC_CONST(0.99312244183049558), FRAC_CONST(0.99330087235809328), FRAC_CONST(0.99347696555278919), + FRAC_CONST(0.99365072100021912), FRAC_CONST(0.99382213829151966), FRAC_CONST(0.99399121702332938), FRAC_CONST(0.99415795679778973), FRAC_CONST(0.99432235722254581), + FRAC_CONST(0.9944844179107476), FRAC_CONST(0.99464413848105071), FRAC_CONST(0.99480151855761711), FRAC_CONST(0.99495655777011638), FRAC_CONST(0.99510925575372611), + FRAC_CONST(0.99525961214913339), FRAC_CONST(0.9954076266025349), FRAC_CONST(0.99555329876563847), FRAC_CONST(0.99569662829566352), FRAC_CONST(0.99583761485534161), + FRAC_CONST(0.99597625811291779), FRAC_CONST(0.99611255774215113), FRAC_CONST(0.99624651342231552), FRAC_CONST(0.99637812483820021), FRAC_CONST(0.99650739168011082), + FRAC_CONST(0.9966343136438699), FRAC_CONST(0.996758890430818), FRAC_CONST(0.99688112174781385), FRAC_CONST(0.99700100730723529), FRAC_CONST(0.99711854682697998), + FRAC_CONST(0.99723374003046616), FRAC_CONST(0.99734658664663323), FRAC_CONST(0.99745708640994191), FRAC_CONST(0.99756523906037575), FRAC_CONST(0.997671044343441), + FRAC_CONST(0.99777450201016782), FRAC_CONST(0.99787561181711015), FRAC_CONST(0.99797437352634699), FRAC_CONST(0.99807078690548234), FRAC_CONST(0.99816485172764624), + FRAC_CONST(0.99825656777149518), FRAC_CONST(0.99834593482121237), FRAC_CONST(0.99843295266650844), FRAC_CONST(0.99851762110262221), FRAC_CONST(0.99859993993032037), + FRAC_CONST(0.99867990895589909), FRAC_CONST(0.99875752799118334), FRAC_CONST(0.99883279685352799), FRAC_CONST(0.99890571536581829), FRAC_CONST(0.99897628335646982), + FRAC_CONST(0.99904450065942929), FRAC_CONST(0.99911036711417489), FRAC_CONST(0.99917388256571638), FRAC_CONST(0.99923504686459585), FRAC_CONST(0.99929385986688779), + FRAC_CONST(0.99935032143419944), FRAC_CONST(0.9994044314336713), FRAC_CONST(0.99945618973797734), FRAC_CONST(0.99950559622532531), FRAC_CONST(0.99955265077945699), + FRAC_CONST(0.99959735328964838), FRAC_CONST(0.9996397036507102), FRAC_CONST(0.99967970176298793), FRAC_CONST(0.99971734753236219), FRAC_CONST(0.99975264087024884), + FRAC_CONST(0.99978558169359921), FRAC_CONST(0.99981616992490041), FRAC_CONST(0.99984440549217524), FRAC_CONST(0.99987028832898295), FRAC_CONST(0.99989381837441849), + FRAC_CONST(0.99991499557311347), FRAC_CONST(0.999933819875236), FRAC_CONST(0.99995029123649048), FRAC_CONST(0.99996440961811828), FRAC_CONST(0.99997617498689761), + FRAC_CONST(0.9999855873151432), FRAC_CONST(0.99999264658070719), FRAC_CONST(0.99999735276697821), FRAC_CONST(0.99999970586288223)}; + +#ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t sine_long_960[] = { + FRAC_CONST(0.00081812299560725323), FRAC_CONST(0.0024543667964602917), FRAC_CONST(0.0040906040262347889), FRAC_CONST(0.0057268303042312674), FRAC_CONST(0.0073630412497795667), + FRAC_CONST(0.0089992324822505774), FRAC_CONST(0.010635399621067975), FRAC_CONST(0.012271538285719924), FRAC_CONST(0.013907644095770845), FRAC_CONST(0.015543712670873098), + FRAC_CONST(0.017179739630778748), FRAC_CONST(0.018815720595351273), FRAC_CONST(0.020451651184577292), FRAC_CONST(0.022087527018578291), FRAC_CONST(0.023723343717622358), + FRAC_CONST(0.025359096902135895), FRAC_CONST(0.02699478219271537), FRAC_CONST(0.028630395210139003), FRAC_CONST(0.030265931575378519), FRAC_CONST(0.031901386909610863), + FRAC_CONST(0.033536756834229922), FRAC_CONST(0.035172036970858266), FRAC_CONST(0.036807222941358832), FRAC_CONST(0.038442310367846677), FRAC_CONST(0.040077294872700696), + FRAC_CONST(0.041712172078575326), FRAC_CONST(0.043346937608412288), FRAC_CONST(0.044981587085452281), FRAC_CONST(0.046616116133246711), FRAC_CONST(0.048250520375669431), + FRAC_CONST(0.049884795436928406), FRAC_CONST(0.051518936941577477), FRAC_CONST(0.053152940514528055), FRAC_CONST(0.05478680178106083), FRAC_CONST(0.056420516366837495), + FRAC_CONST(0.05805407989791244), FRAC_CONST(0.059687488000744485), FRAC_CONST(0.061320736302208578), FRAC_CONST(0.062953820429607482), FRAC_CONST(0.064586736010683557), + FRAC_CONST(0.066219478673630344), FRAC_CONST(0.06785204404710439), FRAC_CONST(0.069484427760236861), FRAC_CONST(0.071116625442645326), FRAC_CONST(0.072748632724445372), + FRAC_CONST(0.07438044523626236), FRAC_CONST(0.076012058609243122), FRAC_CONST(0.077643468475067631), FRAC_CONST(0.079274670465960706), FRAC_CONST(0.080905660214703745), + FRAC_CONST(0.082536433354646319), FRAC_CONST(0.084166985519717977), FRAC_CONST(0.085797312344439894), FRAC_CONST(0.08742740946393647), FRAC_CONST(0.089057272513947183), + FRAC_CONST(0.090686897130838162), FRAC_CONST(0.092316278951613845), FRAC_CONST(0.093945413613928788), FRAC_CONST(0.095574296756099186), FRAC_CONST(0.097202924017114667), + FRAC_CONST(0.098831291036649963), FRAC_CONST(0.10045939345507648), FRAC_CONST(0.10208722691347409), FRAC_CONST(0.10371478705364276), FRAC_CONST(0.10534206951811415), + FRAC_CONST(0.10696906995016341), FRAC_CONST(0.10859578399382072), FRAC_CONST(0.11022220729388306), FRAC_CONST(0.11184833549592579), FRAC_CONST(0.11347416424631435), + FRAC_CONST(0.11509968919221586), FRAC_CONST(0.11672490598161089), FRAC_CONST(0.11834981026330495), FRAC_CONST(0.11997439768694031), FRAC_CONST(0.12159866390300751), + FRAC_CONST(0.12322260456285709), FRAC_CONST(0.12484621531871121), FRAC_CONST(0.12646949182367517), FRAC_CONST(0.12809242973174936), FRAC_CONST(0.12971502469784052), + FRAC_CONST(0.13133727237777362), FRAC_CONST(0.13295916842830346), FRAC_CONST(0.13458070850712617), FRAC_CONST(0.13620188827289101), FRAC_CONST(0.1378227033852118), + FRAC_CONST(0.13944314950467873), FRAC_CONST(0.14106322229286994), FRAC_CONST(0.14268291741236291), FRAC_CONST(0.14430223052674654), FRAC_CONST(0.1459211573006321), + FRAC_CONST(0.14753969339966552), FRAC_CONST(0.14915783449053857), FRAC_CONST(0.15077557624100058), FRAC_CONST(0.15239291431987001), FRAC_CONST(0.1540098443970461), + FRAC_CONST(0.15562636214352044), FRAC_CONST(0.15724246323138855), FRAC_CONST(0.15885814333386142), FRAC_CONST(0.16047339812527725), FRAC_CONST(0.16208822328111283), + FRAC_CONST(0.16370261447799525), FRAC_CONST(0.16531656739371339), FRAC_CONST(0.16693007770722967), FRAC_CONST(0.16854314109869134), FRAC_CONST(0.17015575324944232), + FRAC_CONST(0.17176790984203447), FRAC_CONST(0.17337960656023954), FRAC_CONST(0.1749908390890603), FRAC_CONST(0.17660160311474243), FRAC_CONST(0.17821189432478593), + FRAC_CONST(0.17982170840795647), FRAC_CONST(0.18143104105429744), FRAC_CONST(0.18303988795514095), FRAC_CONST(0.1846482448031197), FRAC_CONST(0.18625610729217834), + FRAC_CONST(0.1878634711175852), FRAC_CONST(0.18947033197594348), FRAC_CONST(0.19107668556520319), FRAC_CONST(0.19268252758467228), FRAC_CONST(0.19428785373502844), + FRAC_CONST(0.19589265971833042), FRAC_CONST(0.19749694123802966), FRAC_CONST(0.19910069399898173), FRAC_CONST(0.20070391370745785), FRAC_CONST(0.20230659607115639), + FRAC_CONST(0.20390873679921437), FRAC_CONST(0.20551033160221882), FRAC_CONST(0.20711137619221856), FRAC_CONST(0.2087118662827353), FRAC_CONST(0.21031179758877552), + FRAC_CONST(0.21191116582684155), FRAC_CONST(0.21350996671494335), FRAC_CONST(0.21510819597260972), FRAC_CONST(0.21670584932089998), FRAC_CONST(0.2183029224824154), + FRAC_CONST(0.21989941118131037), FRAC_CONST(0.22149531114330431), FRAC_CONST(0.22309061809569264), FRAC_CONST(0.22468532776735861), FRAC_CONST(0.22627943588878449), + FRAC_CONST(0.22787293819206314), FRAC_CONST(0.22946583041090929), FRAC_CONST(0.23105810828067114), FRAC_CONST(0.23264976753834157), FRAC_CONST(0.23424080392256985), + FRAC_CONST(0.2358312131736727), FRAC_CONST(0.23742099103364595), FRAC_CONST(0.23901013324617584), FRAC_CONST(0.24059863555665045), FRAC_CONST(0.24218649371217096), + FRAC_CONST(0.24377370346156332), FRAC_CONST(0.24536026055538934), FRAC_CONST(0.24694616074595824), FRAC_CONST(0.24853139978733788), FRAC_CONST(0.25011597343536629), + FRAC_CONST(0.25169987744766298), FRAC_CONST(0.25328310758364025), FRAC_CONST(0.25486565960451457), FRAC_CONST(0.25644752927331788), FRAC_CONST(0.25802871235490898), + FRAC_CONST(0.25960920461598508), FRAC_CONST(0.26118900182509258), FRAC_CONST(0.26276809975263904), FRAC_CONST(0.264346494170904), FRAC_CONST(0.26592418085405067), + FRAC_CONST(0.26750115557813692), FRAC_CONST(0.2690774141211269), FRAC_CONST(0.27065295226290209), FRAC_CONST(0.2722277657852728), FRAC_CONST(0.27380185047198918), + FRAC_CONST(0.27537520210875299), FRAC_CONST(0.2769478164832283), FRAC_CONST(0.27851968938505312), FRAC_CONST(0.28009081660585067), FRAC_CONST(0.28166119393924061), + FRAC_CONST(0.28323081718085019), FRAC_CONST(0.28479968212832563), FRAC_CONST(0.28636778458134327), FRAC_CONST(0.28793512034162105), FRAC_CONST(0.2895016852129294), + FRAC_CONST(0.29106747500110264), FRAC_CONST(0.29263248551405047), FRAC_CONST(0.2941967125617686), FRAC_CONST(0.29576015195635058), FRAC_CONST(0.29732279951199847), + FRAC_CONST(0.29888465104503475), FRAC_CONST(0.30044570237391266), FRAC_CONST(0.30200594931922808), FRAC_CONST(0.30356538770373032), FRAC_CONST(0.30512401335233358), + FRAC_CONST(0.30668182209212791), FRAC_CONST(0.3082388097523906), FRAC_CONST(0.30979497216459695), FRAC_CONST(0.31135030516243201), FRAC_CONST(0.3129048045818012), + FRAC_CONST(0.31445846626084178), FRAC_CONST(0.31601128603993378), FRAC_CONST(0.31756325976171151), FRAC_CONST(0.31911438327107416), FRAC_CONST(0.32066465241519732), + FRAC_CONST(0.32221406304354389), FRAC_CONST(0.3237626110078754), FRAC_CONST(0.32531029216226293), FRAC_CONST(0.32685710236309828), FRAC_CONST(0.32840303746910487), + FRAC_CONST(0.32994809334134939), FRAC_CONST(0.3314922658432522), FRAC_CONST(0.33303555084059877), FRAC_CONST(0.33457794420155085), FRAC_CONST(0.33611944179665709), + FRAC_CONST(0.33766003949886464), FRAC_CONST(0.33919973318352969), FRAC_CONST(0.34073851872842903), FRAC_CONST(0.34227639201377064), FRAC_CONST(0.34381334892220483), + FRAC_CONST(0.34534938533883547), FRAC_CONST(0.34688449715123082), FRAC_CONST(0.34841868024943456), FRAC_CONST(0.34995193052597684), FRAC_CONST(0.35148424387588523), + FRAC_CONST(0.3530156161966958), FRAC_CONST(0.35454604338846402), FRAC_CONST(0.35607552135377557), FRAC_CONST(0.35760404599775775), FRAC_CONST(0.35913161322809023), + FRAC_CONST(0.36065821895501554), FRAC_CONST(0.36218385909135092), FRAC_CONST(0.36370852955249849), FRAC_CONST(0.36523222625645668), FRAC_CONST(0.36675494512383078), + FRAC_CONST(0.36827668207784414), FRAC_CONST(0.36979743304434909), FRAC_CONST(0.37131719395183754), FRAC_CONST(0.37283596073145214), FRAC_CONST(0.37435372931699717), + FRAC_CONST(0.37587049564494951), FRAC_CONST(0.37738625565446909), FRAC_CONST(0.37890100528741022), FRAC_CONST(0.38041474048833229), FRAC_CONST(0.38192745720451066), + FRAC_CONST(0.38343915138594736), FRAC_CONST(0.38494981898538222), FRAC_CONST(0.38645945595830333), FRAC_CONST(0.38796805826295838), FRAC_CONST(0.38947562186036483), + FRAC_CONST(0.39098214271432141), FRAC_CONST(0.39248761679141814), FRAC_CONST(0.3939920400610481), FRAC_CONST(0.39549540849541737), FRAC_CONST(0.39699771806955625), + FRAC_CONST(0.39849896476132979), FRAC_CONST(0.39999914455144892), FRAC_CONST(0.40149825342348083), FRAC_CONST(0.4029962873638599), FRAC_CONST(0.40449324236189854), + FRAC_CONST(0.40598911440979762), FRAC_CONST(0.40748389950265762), FRAC_CONST(0.40897759363848879), FRAC_CONST(0.41047019281822261), FRAC_CONST(0.41196169304572178), + FRAC_CONST(0.4134520903277914), FRAC_CONST(0.41494138067418929), FRAC_CONST(0.41642956009763715), FRAC_CONST(0.41791662461383078), FRAC_CONST(0.41940257024145089), + FRAC_CONST(0.42088739300217382), FRAC_CONST(0.42237108892068231), FRAC_CONST(0.42385365402467584), FRAC_CONST(0.42533508434488143), FRAC_CONST(0.42681537591506419), + FRAC_CONST(0.42829452477203828), FRAC_CONST(0.42977252695567697), FRAC_CONST(0.43124937850892364), FRAC_CONST(0.4327250754778022), FRAC_CONST(0.43419961391142781), + FRAC_CONST(0.43567298986201736), FRAC_CONST(0.43714519938489987), FRAC_CONST(0.43861623853852766), FRAC_CONST(0.44008610338448595), FRAC_CONST(0.44155478998750436), + FRAC_CONST(0.44302229441546676), FRAC_CONST(0.4444886127394222), FRAC_CONST(0.44595374103359531), FRAC_CONST(0.44741767537539667), FRAC_CONST(0.44888041184543348), + FRAC_CONST(0.45034194652752002), FRAC_CONST(0.45180227550868812), FRAC_CONST(0.45326139487919759), FRAC_CONST(0.45471930073254679), FRAC_CONST(0.45617598916548296), + FRAC_CONST(0.45763145627801283), FRAC_CONST(0.45908569817341294), FRAC_CONST(0.46053871095824001), FRAC_CONST(0.46199049074234161), FRAC_CONST(0.46344103363886635), + FRAC_CONST(0.46489033576427435), FRAC_CONST(0.46633839323834758), FRAC_CONST(0.46778520218420055), FRAC_CONST(0.46923075872829029), FRAC_CONST(0.47067505900042683), + FRAC_CONST(0.47211809913378361), FRAC_CONST(0.47355987526490806), FRAC_CONST(0.47500038353373153), FRAC_CONST(0.47643962008357982), FRAC_CONST(0.47787758106118372), + FRAC_CONST(0.47931426261668875), FRAC_CONST(0.48074966090366611), FRAC_CONST(0.48218377207912272), FRAC_CONST(0.48361659230351117), FRAC_CONST(0.48504811774074069), + FRAC_CONST(0.48647834455818684), FRAC_CONST(0.48790726892670194), FRAC_CONST(0.48933488702062544), FRAC_CONST(0.49076119501779414), FRAC_CONST(0.49218618909955225), + FRAC_CONST(0.4936098654507618), FRAC_CONST(0.49503222025981269), FRAC_CONST(0.49645324971863303), FRAC_CONST(0.49787295002269943), FRAC_CONST(0.49929131737104687), + FRAC_CONST(0.50070834796627917), FRAC_CONST(0.50212403801457872), FRAC_CONST(0.50353838372571758), FRAC_CONST(0.50495138131306638), FRAC_CONST(0.50636302699360547), + FRAC_CONST(0.50777331698793449), FRAC_CONST(0.50918224752028263), FRAC_CONST(0.51058981481851906), FRAC_CONST(0.51199601511416237), FRAC_CONST(0.51340084464239111), + FRAC_CONST(0.51480429964205421), FRAC_CONST(0.51620637635567967), FRAC_CONST(0.51760707102948678), FRAC_CONST(0.51900637991339404), FRAC_CONST(0.5204042992610306), + FRAC_CONST(0.52180082532974559), FRAC_CONST(0.5231959543806185), FRAC_CONST(0.52458968267846895), FRAC_CONST(0.52598200649186677), FRAC_CONST(0.52737292209314235), + FRAC_CONST(0.52876242575839572), FRAC_CONST(0.53015051376750777), FRAC_CONST(0.53153718240414882), FRAC_CONST(0.53292242795578992), FRAC_CONST(0.53430624671371152), + FRAC_CONST(0.53568863497301467), FRAC_CONST(0.5370695890326298), FRAC_CONST(0.5384491051953274), FRAC_CONST(0.53982717976772743), FRAC_CONST(0.54120380906030963), + FRAC_CONST(0.54257898938742311), FRAC_CONST(0.54395271706729609), FRAC_CONST(0.54532498842204646), FRAC_CONST(0.54669579977769045), FRAC_CONST(0.54806514746415402), + FRAC_CONST(0.54943302781528081), FRAC_CONST(0.55079943716884383), FRAC_CONST(0.55216437186655387), FRAC_CONST(0.55352782825406999), FRAC_CONST(0.55488980268100907), + FRAC_CONST(0.55625029150095584), FRAC_CONST(0.55760929107147217), FRAC_CONST(0.55896679775410718), FRAC_CONST(0.56032280791440714), FRAC_CONST(0.56167731792192455), + FRAC_CONST(0.56303032415022869), FRAC_CONST(0.56438182297691453), FRAC_CONST(0.56573181078361312), FRAC_CONST(0.56708028395600085), FRAC_CONST(0.56842723888380908), + FRAC_CONST(0.56977267196083425), FRAC_CONST(0.57111657958494688), FRAC_CONST(0.5724589581581021), FRAC_CONST(0.57379980408634845), FRAC_CONST(0.57513911377983773), + FRAC_CONST(0.57647688365283478), FRAC_CONST(0.57781311012372738), FRAC_CONST(0.57914778961503466), FRAC_CONST(0.58048091855341843), FRAC_CONST(0.5818124933696911), + FRAC_CONST(0.58314251049882604), FRAC_CONST(0.58447096637996743), FRAC_CONST(0.58579785745643886), FRAC_CONST(0.5871231801757536), FRAC_CONST(0.58844693098962408), + FRAC_CONST(0.58976910635397084), FRAC_CONST(0.59108970272893235), FRAC_CONST(0.59240871657887517), FRAC_CONST(0.59372614437240179), FRAC_CONST(0.59504198258236196), + FRAC_CONST(0.5963562276858605), FRAC_CONST(0.59766887616426767), FRAC_CONST(0.5989799245032289), FRAC_CONST(0.60028936919267273), FRAC_CONST(0.60159720672682204), + FRAC_CONST(0.60290343360420195), FRAC_CONST(0.60420804632765002), FRAC_CONST(0.60551104140432543), FRAC_CONST(0.60681241534571839), FRAC_CONST(0.60811216466765883), + FRAC_CONST(0.60941028589032709), FRAC_CONST(0.61070677553826169), FRAC_CONST(0.61200163014036979), FRAC_CONST(0.61329484622993602), FRAC_CONST(0.6145864203446314), + FRAC_CONST(0.61587634902652377), FRAC_CONST(0.61716462882208556), FRAC_CONST(0.61845125628220421), FRAC_CONST(0.61973622796219074), FRAC_CONST(0.6210195404217892), + FRAC_CONST(0.62230119022518593), FRAC_CONST(0.62358117394101897), FRAC_CONST(0.62485948814238634), FRAC_CONST(0.62613612940685637), FRAC_CONST(0.62741109431647646), + FRAC_CONST(0.62868437945778133), FRAC_CONST(0.62995598142180387), FRAC_CONST(0.6312258968040827), FRAC_CONST(0.63249412220467238), FRAC_CONST(0.63376065422815175), + FRAC_CONST(0.63502548948363347), FRAC_CONST(0.63628862458477287), FRAC_CONST(0.63755005614977711), FRAC_CONST(0.63880978080141437), FRAC_CONST(0.6400677951670225), + FRAC_CONST(0.6413240958785188), FRAC_CONST(0.64257867957240766), FRAC_CONST(0.6438315428897915), FRAC_CONST(0.64508268247637779), FRAC_CONST(0.64633209498248945), + FRAC_CONST(0.64757977706307335), FRAC_CONST(0.64882572537770888), FRAC_CONST(0.65006993659061751), FRAC_CONST(0.65131240737067142), FRAC_CONST(0.65255313439140239), + FRAC_CONST(0.65379211433101081), FRAC_CONST(0.65502934387237444), FRAC_CONST(0.6562648197030575), FRAC_CONST(0.65749853851531959), FRAC_CONST(0.65873049700612374), + FRAC_CONST(0.65996069187714679), FRAC_CONST(0.66118911983478657), FRAC_CONST(0.66241577759017178), FRAC_CONST(0.66364066185917048), FRAC_CONST(0.66486376936239888), + FRAC_CONST(0.66608509682523009), FRAC_CONST(0.66730464097780284), FRAC_CONST(0.66852239855503071), FRAC_CONST(0.66973836629660977), FRAC_CONST(0.67095254094702894), + FRAC_CONST(0.67216491925557675), FRAC_CONST(0.67337549797635199), FRAC_CONST(0.67458427386827102), FRAC_CONST(0.67579124369507693), FRAC_CONST(0.67699640422534846), + FRAC_CONST(0.67819975223250772), FRAC_CONST(0.6794012844948305), FRAC_CONST(0.68060099779545302), FRAC_CONST(0.68179888892238183), FRAC_CONST(0.6829949546685018), + FRAC_CONST(0.68418919183158522), FRAC_CONST(0.68538159721429948), FRAC_CONST(0.6865721676242168), FRAC_CONST(0.68776089987382172), FRAC_CONST(0.68894779078052026), + FRAC_CONST(0.69013283716664853), FRAC_CONST(0.69131603585948032), FRAC_CONST(0.69249738369123692), FRAC_CONST(0.69367687749909468), FRAC_CONST(0.69485451412519361), + FRAC_CONST(0.69603029041664599), FRAC_CONST(0.6972042032255451), FRAC_CONST(0.6983762494089728), FRAC_CONST(0.69954642582900894), FRAC_CONST(0.70071472935273893), + FRAC_CONST(0.70188115685226271), FRAC_CONST(0.703045705204703), FRAC_CONST(0.70420837129221303), FRAC_CONST(0.70536915200198613), FRAC_CONST(0.70652804422626281), + FRAC_CONST(0.70768504486233985), FRAC_CONST(0.70884015081257845), FRAC_CONST(0.70999335898441229), FRAC_CONST(0.711144666290356), FRAC_CONST(0.71229406964801356), + FRAC_CONST(0.71344156598008623), FRAC_CONST(0.71458715221438096), FRAC_CONST(0.71573082528381871), FRAC_CONST(0.71687258212644234), FRAC_CONST(0.7180124196854254), + FRAC_CONST(0.71915033490907943), FRAC_CONST(0.72028632475086318), FRAC_CONST(0.72142038616938997), FRAC_CONST(0.72255251612843596), FRAC_CONST(0.72368271159694852), + FRAC_CONST(0.72481096954905444), FRAC_CONST(0.72593728696406756), FRAC_CONST(0.72706166082649704), FRAC_CONST(0.72818408812605595), FRAC_CONST(0.72930456585766834), + FRAC_CONST(0.73042309102147851), FRAC_CONST(0.73153966062285747), FRAC_CONST(0.73265427167241282), FRAC_CONST(0.73376692118599507), FRAC_CONST(0.73487760618470677), + FRAC_CONST(0.73598632369490979), FRAC_CONST(0.73709307074823405), FRAC_CONST(0.73819784438158409), FRAC_CONST(0.73930064163714881), FRAC_CONST(0.74040145956240788), + FRAC_CONST(0.74150029521014049), FRAC_CONST(0.74259714563843304), FRAC_CONST(0.74369200791068657), FRAC_CONST(0.74478487909562552), FRAC_CONST(0.74587575626730485), + FRAC_CONST(0.74696463650511791), FRAC_CONST(0.74805151689380456), FRAC_CONST(0.74913639452345926), FRAC_CONST(0.75021926648953785), FRAC_CONST(0.75130012989286621), + FRAC_CONST(0.7523789818396478), FRAC_CONST(0.75345581944147111), FRAC_CONST(0.75453063981531809), FRAC_CONST(0.75560344008357094), FRAC_CONST(0.75667421737402052), + FRAC_CONST(0.7577429688198738), FRAC_CONST(0.75880969155976163), FRAC_CONST(0.75987438273774599), FRAC_CONST(0.76093703950332836), FRAC_CONST(0.76199765901145666), + FRAC_CONST(0.76305623842253345), FRAC_CONST(0.76411277490242291), FRAC_CONST(0.76516726562245885), FRAC_CONST(0.76621970775945258), FRAC_CONST(0.76727009849569949), + FRAC_CONST(0.76831843501898767), FRAC_CONST(0.76936471452260458), FRAC_CONST(0.77040893420534517), FRAC_CONST(0.77145109127151923), FRAC_CONST(0.77249118293095853), + FRAC_CONST(0.77352920639902467), FRAC_CONST(0.77456515889661659), FRAC_CONST(0.77559903765017746), FRAC_CONST(0.7766308398917029), FRAC_CONST(0.77766056285874774), + FRAC_CONST(0.77868820379443371), FRAC_CONST(0.77971375994745684), FRAC_CONST(0.78073722857209438), FRAC_CONST(0.7817586069282132), FRAC_CONST(0.78277789228127592), + FRAC_CONST(0.78379508190234881), FRAC_CONST(0.78481017306810918), FRAC_CONST(0.78582316306085265), FRAC_CONST(0.78683404916849986), FRAC_CONST(0.78784282868460476), + FRAC_CONST(0.78884949890836087), FRAC_CONST(0.78985405714460888), FRAC_CONST(0.7908565007038445), FRAC_CONST(0.79185682690222425), FRAC_CONST(0.79285503306157412), + FRAC_CONST(0.79385111650939566), FRAC_CONST(0.79484507457887377), FRAC_CONST(0.79583690460888357), FRAC_CONST(0.79682660394399751), FRAC_CONST(0.79781416993449272), + FRAC_CONST(0.79879959993635785), FRAC_CONST(0.7997828913113002), FRAC_CONST(0.80076404142675273), FRAC_CONST(0.80174304765588156), FRAC_CONST(0.80271990737759213), + FRAC_CONST(0.80369461797653707), FRAC_CONST(0.80466717684312306), FRAC_CONST(0.80563758137351682), FRAC_CONST(0.80660582896965372), FRAC_CONST(0.80757191703924336), + FRAC_CONST(0.80853584299577752), FRAC_CONST(0.80949760425853612), FRAC_CONST(0.81045719825259477), FRAC_CONST(0.81141462240883167), FRAC_CONST(0.81236987416393436), + FRAC_CONST(0.81332295096040608), FRAC_CONST(0.81427385024657373), FRAC_CONST(0.81522256947659355), FRAC_CONST(0.81616910611045879), FRAC_CONST(0.817113457614006), + FRAC_CONST(0.81805562145892186), FRAC_CONST(0.81899559512275044), FRAC_CONST(0.81993337608889916), FRAC_CONST(0.82086896184664637), FRAC_CONST(0.8218023498911472), + FRAC_CONST(0.82273353772344116), FRAC_CONST(0.82366252285045805), FRAC_CONST(0.82458930278502529), FRAC_CONST(0.82551387504587381), FRAC_CONST(0.82643623715764558), + FRAC_CONST(0.82735638665089983), FRAC_CONST(0.82827432106211907), FRAC_CONST(0.82919003793371693), FRAC_CONST(0.83010353481404364), FRAC_CONST(0.83101480925739324), + FRAC_CONST(0.83192385882400965), FRAC_CONST(0.83283068108009373), FRAC_CONST(0.8337352735978093), FRAC_CONST(0.83463763395529011), FRAC_CONST(0.83553775973664579), + FRAC_CONST(0.83643564853196872), FRAC_CONST(0.83733129793734051), FRAC_CONST(0.83822470555483797), FRAC_CONST(0.83911586899254031), FRAC_CONST(0.84000478586453453), + FRAC_CONST(0.84089145379092289), FRAC_CONST(0.84177587039782842), FRAC_CONST(0.84265803331740163), FRAC_CONST(0.84353794018782702), FRAC_CONST(0.844415588653329), + FRAC_CONST(0.8452909763641786), FRAC_CONST(0.84616410097669936), FRAC_CONST(0.84703496015327406), FRAC_CONST(0.84790355156235053), FRAC_CONST(0.84876987287844818), + FRAC_CONST(0.8496339217821639), FRAC_CONST(0.85049569596017938), FRAC_CONST(0.85135519310526508), FRAC_CONST(0.85221241091628896), FRAC_CONST(0.85306734709822085), + FRAC_CONST(0.85391999936213903), FRAC_CONST(0.85477036542523732), FRAC_CONST(0.85561844301082923), FRAC_CONST(0.85646422984835635), FRAC_CONST(0.85730772367339259), + FRAC_CONST(0.85814892222765116), FRAC_CONST(0.85898782325899026), FRAC_CONST(0.85982442452141961), FRAC_CONST(0.86065872377510555), FRAC_CONST(0.86149071878637817), + FRAC_CONST(0.8623204073277364), FRAC_CONST(0.86314778717785412), FRAC_CONST(0.8639728561215867), FRAC_CONST(0.86479561194997623), FRAC_CONST(0.86561605246025763), + FRAC_CONST(0.86643417545586487), FRAC_CONST(0.8672499787464365), FRAC_CONST(0.86806346014782154), FRAC_CONST(0.8688746174820855), FRAC_CONST(0.86968344857751589), + FRAC_CONST(0.87048995126862883), FRAC_CONST(0.87129412339617363), FRAC_CONST(0.87209596280713941), FRAC_CONST(0.8728954673547612), FRAC_CONST(0.87369263489852422), + FRAC_CONST(0.87448746330417149), FRAC_CONST(0.87527995044370765), FRAC_CONST(0.8760700941954066), FRAC_CONST(0.87685789244381551), FRAC_CONST(0.87764334307976144), + FRAC_CONST(0.87842644400035663), FRAC_CONST(0.8792071931090043), FRAC_CONST(0.87998558831540408), FRAC_CONST(0.88076162753555787), FRAC_CONST(0.88153530869177488), + FRAC_CONST(0.88230662971267804), FRAC_CONST(0.88307558853320878), FRAC_CONST(0.88384218309463292), FRAC_CONST(0.8846064113445461), FRAC_CONST(0.88536827123687933), + FRAC_CONST(0.88612776073190425), FRAC_CONST(0.88688487779623937), FRAC_CONST(0.88763962040285393), FRAC_CONST(0.8883919865310751), FRAC_CONST(0.88914197416659235), + FRAC_CONST(0.88988958130146301), FRAC_CONST(0.8906348059341177), FRAC_CONST(0.89137764606936609), FRAC_CONST(0.89211809971840139), FRAC_CONST(0.89285616489880615), + FRAC_CONST(0.89359183963455813), FRAC_CONST(0.89432512195603453), FRAC_CONST(0.89505600990001799), FRAC_CONST(0.89578450150970124), FRAC_CONST(0.8965105948346932), + FRAC_CONST(0.89723428793102367), FRAC_CONST(0.89795557886114807), FRAC_CONST(0.89867446569395382), FRAC_CONST(0.89939094650476448), FRAC_CONST(0.90010501937534515), + FRAC_CONST(0.900816682393908), FRAC_CONST(0.90152593365511691), FRAC_CONST(0.90223277126009283), FRAC_CONST(0.90293719331641886), FRAC_CONST(0.90363919793814496), + FRAC_CONST(0.90433878324579353), FRAC_CONST(0.90503594736636439), FRAC_CONST(0.90573068843333915), FRAC_CONST(0.90642300458668679), FRAC_CONST(0.90711289397286898), + FRAC_CONST(0.90780035474484411), FRAC_CONST(0.90848538506207266), FRAC_CONST(0.90916798309052227), FRAC_CONST(0.90984814700267291), FRAC_CONST(0.9105258749775208), + FRAC_CONST(0.91120116520058425), FRAC_CONST(0.91187401586390815), FRAC_CONST(0.91254442516606893), FRAC_CONST(0.9132123913121788), FRAC_CONST(0.91387791251389161), + FRAC_CONST(0.91454098698940678), FRAC_CONST(0.91520161296347435), FRAC_CONST(0.91585978866739981), FRAC_CONST(0.91651551233904871), FRAC_CONST(0.91716878222285148), + FRAC_CONST(0.91781959656980805), FRAC_CONST(0.91846795363749245), FRAC_CONST(0.91911385169005766), FRAC_CONST(0.9197572889982405), FRAC_CONST(0.9203982638393654), + FRAC_CONST(0.92103677449734989), FRAC_CONST(0.92167281926270861), FRAC_CONST(0.92230639643255874), FRAC_CONST(0.92293750431062316), FRAC_CONST(0.92356614120723612), + FRAC_CONST(0.92419230543934783), FRAC_CONST(0.92481599533052783), FRAC_CONST(0.92543720921097061), FRAC_CONST(0.92605594541749991), FRAC_CONST(0.92667220229357261), + FRAC_CONST(0.92728597818928349), FRAC_CONST(0.9278972714613698), FRAC_CONST(0.92850608047321548), FRAC_CONST(0.9291124035948557), FRAC_CONST(0.92971623920298097), + FRAC_CONST(0.93031758568094147), FRAC_CONST(0.93091644141875196), FRAC_CONST(0.93151280481309506), FRAC_CONST(0.93210667426732674), FRAC_CONST(0.93269804819147983), + FRAC_CONST(0.93328692500226818), FRAC_CONST(0.93387330312309147), FRAC_CONST(0.93445718098403896), FRAC_CONST(0.93503855702189376), FRAC_CONST(0.9356174296801375), + FRAC_CONST(0.93619379740895381), FRAC_CONST(0.93676765866523259), FRAC_CONST(0.93733901191257496), FRAC_CONST(0.93790785562129597), FRAC_CONST(0.93847418826842988), + FRAC_CONST(0.93903800833773399), FRAC_CONST(0.93959931431969212), FRAC_CONST(0.94015810471151917), FRAC_CONST(0.94071437801716529), FRAC_CONST(0.94126813274731924), + FRAC_CONST(0.94181936741941319), FRAC_CONST(0.94236808055762578), FRAC_CONST(0.94291427069288691), FRAC_CONST(0.94345793636288133), FRAC_CONST(0.94399907611205225), + FRAC_CONST(0.9445376884916058), FRAC_CONST(0.94507377205951448), FRAC_CONST(0.94560732538052128), FRAC_CONST(0.94613834702614352), FRAC_CONST(0.94666683557467624), + FRAC_CONST(0.94719278961119657), FRAC_CONST(0.94771620772756759), FRAC_CONST(0.94823708852244104), FRAC_CONST(0.94875543060126255), FRAC_CONST(0.94927123257627433), + FRAC_CONST(0.94978449306651924), FRAC_CONST(0.95029521069784428), FRAC_CONST(0.9508033841029051), FRAC_CONST(0.95130901192116835), FRAC_CONST(0.9518120927989161), + FRAC_CONST(0.95231262538924943), FRAC_CONST(0.95281060835209208), FRAC_CONST(0.95330604035419386), FRAC_CONST(0.95379892006913403), FRAC_CONST(0.95428924617732525), + FRAC_CONST(0.95477701736601728), FRAC_CONST(0.95526223232929941), FRAC_CONST(0.95574488976810545), FRAC_CONST(0.95622498839021619), FRAC_CONST(0.95670252691026292), + FRAC_CONST(0.95717750404973156), FRAC_CONST(0.95764991853696524), FRAC_CONST(0.95811976910716812), FRAC_CONST(0.95858705450240911), FRAC_CONST(0.95905177347162429), + FRAC_CONST(0.95951392477062125), FRAC_CONST(0.95997350716208196), FRAC_CONST(0.96043051941556579), FRAC_CONST(0.96088496030751369), FRAC_CONST(0.96133682862125036), + FRAC_CONST(0.96178612314698864), FRAC_CONST(0.96223284268183173), FRAC_CONST(0.9626769860297768), FRAC_CONST(0.96311855200171881), FRAC_CONST(0.96355753941545252), + FRAC_CONST(0.96399394709567654), FRAC_CONST(0.96442777387399625), FRAC_CONST(0.96485901858892686), FRAC_CONST(0.96528768008589627), FRAC_CONST(0.96571375721724895), + FRAC_CONST(0.96613724884224783), FRAC_CONST(0.96655815382707866), FRAC_CONST(0.96697647104485207), FRAC_CONST(0.96739219937560694), FRAC_CONST(0.96780533770631338), + FRAC_CONST(0.96821588493087585), FRAC_CONST(0.9686238399501359), FRAC_CONST(0.96902920167187501), FRAC_CONST(0.96943196901081796), FRAC_CONST(0.96983214088863534), + FRAC_CONST(0.9702297162339466), FRAC_CONST(0.97062469398232287), FRAC_CONST(0.97101707307629004), FRAC_CONST(0.97140685246533098), FRAC_CONST(0.97179403110588902), + FRAC_CONST(0.97217860796137046), FRAC_CONST(0.97256058200214734), FRAC_CONST(0.97293995220556007), FRAC_CONST(0.97331671755592064), FRAC_CONST(0.97369087704451474), + FRAC_CONST(0.97406242966960455), FRAC_CONST(0.97443137443643235), FRAC_CONST(0.97479771035722163), FRAC_CONST(0.97516143645118103), FRAC_CONST(0.97552255174450631), + FRAC_CONST(0.97588105527038305), FRAC_CONST(0.97623694606898959), FRAC_CONST(0.97659022318749911), FRAC_CONST(0.97694088568008242), FRAC_CONST(0.97728893260791039), + FRAC_CONST(0.97763436303915685), FRAC_CONST(0.97797717604900047), FRAC_CONST(0.97831737071962765), FRAC_CONST(0.97865494614023485), FRAC_CONST(0.97898990140703124), + FRAC_CONST(0.97932223562324061), FRAC_CONST(0.97965194789910426), FRAC_CONST(0.9799790373518833), FRAC_CONST(0.98030350310586067), FRAC_CONST(0.98062534429234405), + FRAC_CONST(0.98094456004966768), FRAC_CONST(0.98126114952319499), FRAC_CONST(0.98157511186532054), FRAC_CONST(0.98188644623547261), FRAC_CONST(0.98219515180011563), + FRAC_CONST(0.98250122773275184), FRAC_CONST(0.98280467321392362), FRAC_CONST(0.98310548743121629), FRAC_CONST(0.98340366957925973), FRAC_CONST(0.98369921885973044), + FRAC_CONST(0.98399213448135414), FRAC_CONST(0.98428241565990748), FRAC_CONST(0.98457006161822058), FRAC_CONST(0.98485507158617835), FRAC_CONST(0.98513744480072363), + FRAC_CONST(0.98541718050585803), FRAC_CONST(0.98569427795264519), FRAC_CONST(0.98596873639921168), FRAC_CONST(0.98624055511074971), FRAC_CONST(0.98650973335951875), + FRAC_CONST(0.98677627042484772), FRAC_CONST(0.98704016559313645), FRAC_CONST(0.98730141815785832), FRAC_CONST(0.98756002741956173), FRAC_CONST(0.9878159926858715), + FRAC_CONST(0.98806931327149194), FRAC_CONST(0.98831998849820735), FRAC_CONST(0.98856801769488489), FRAC_CONST(0.98881340019747566), FRAC_CONST(0.98905613534901682), + FRAC_CONST(0.98929622249963345), FRAC_CONST(0.98953366100653983), FRAC_CONST(0.98976845023404181), FRAC_CONST(0.99000058955353776), FRAC_CONST(0.99023007834352106), + FRAC_CONST(0.99045691598958097), FRAC_CONST(0.99068110188440506), FRAC_CONST(0.99090263542778001), FRAC_CONST(0.99112151602659404), FRAC_CONST(0.99133774309483769), + FRAC_CONST(0.99155131605360625), FRAC_CONST(0.99176223433110056), FRAC_CONST(0.99197049736262888), FRAC_CONST(0.99217610459060845), FRAC_CONST(0.99237905546456673), + FRAC_CONST(0.99257934944114334), FRAC_CONST(0.99277698598409092), FRAC_CONST(0.99297196456427694), FRAC_CONST(0.99316428465968509), FRAC_CONST(0.99335394575541669), + FRAC_CONST(0.99354094734369169), FRAC_CONST(0.99372528892385081), FRAC_CONST(0.99390697000235606), FRAC_CONST(0.99408599009279242), FRAC_CONST(0.99426234871586938), + FRAC_CONST(0.99443604539942176), FRAC_CONST(0.99460707967841133), FRAC_CONST(0.99477545109492771), FRAC_CONST(0.99494115919819004), FRAC_CONST(0.99510420354454787), + FRAC_CONST(0.99526458369748239), FRAC_CONST(0.99542229922760772), FRAC_CONST(0.99557734971267187), FRAC_CONST(0.9957297347375581), FRAC_CONST(0.99587945389428578), + FRAC_CONST(0.99602650678201154), FRAC_CONST(0.99617089300703077), FRAC_CONST(0.996312612182778), FRAC_CONST(0.99645166392982831), FRAC_CONST(0.99658804787589839), + FRAC_CONST(0.99672176365584741), FRAC_CONST(0.99685281091167788), FRAC_CONST(0.99698118929253687), FRAC_CONST(0.99710689845471678), FRAC_CONST(0.99722993806165661), + FRAC_CONST(0.99735030778394196), FRAC_CONST(0.99746800729930707), FRAC_CONST(0.99758303629263489), FRAC_CONST(0.99769539445595812), FRAC_CONST(0.99780508148846014), + FRAC_CONST(0.99791209709647588), FRAC_CONST(0.99801644099349218), FRAC_CONST(0.99811811290014918), FRAC_CONST(0.9982171125442405), FRAC_CONST(0.9983134396607144), + FRAC_CONST(0.99840709399167404), FRAC_CONST(0.99849807528637868), FRAC_CONST(0.99858638330124405), FRAC_CONST(0.99867201779984294), FRAC_CONST(0.99875497855290607), + FRAC_CONST(0.99883526533832245), FRAC_CONST(0.99891287794114036), FRAC_CONST(0.99898781615356746), FRAC_CONST(0.99906007977497147), FRAC_CONST(0.99912966861188113), + FRAC_CONST(0.99919658247798593), FRAC_CONST(0.99926082119413751), FRAC_CONST(0.99932238458834954), FRAC_CONST(0.999381272495798), FRAC_CONST(0.99943748475882255), + FRAC_CONST(0.9994910212269259), FRAC_CONST(0.99954188175677483), FRAC_CONST(0.99959006621220048), FRAC_CONST(0.99963557446419837), FRAC_CONST(0.99967840639092931), + FRAC_CONST(0.99971856187771946), FRAC_CONST(0.99975604081706027), FRAC_CONST(0.99979084310860955), FRAC_CONST(0.99982296865919107), FRAC_CONST(0.99985241738279484), + FRAC_CONST(0.99987918920057806), FRAC_CONST(0.99990328404086426), FRAC_CONST(0.9999247018391445), FRAC_CONST(0.99994344253807688), FRAC_CONST(0.99995950608748674), + FRAC_CONST(0.99997289244436727), FRAC_CONST(0.99998360157287902), FRAC_CONST(0.9999916334443506), FRAC_CONST(0.99999698803727821), FRAC_CONST(0.99999966533732598)}; +#endif + +static const real_t sine_short_128[] = { + FRAC_CONST(0.0061358846491544753), FRAC_CONST(0.01840672990580482), FRAC_CONST(0.030674803176636626), FRAC_CONST(0.04293825693494082), FRAC_CONST(0.055195244349689934), + FRAC_CONST(0.067443919563664051), FRAC_CONST(0.079682437971430126), FRAC_CONST(0.091908956497132724), FRAC_CONST(0.10412163387205459), FRAC_CONST(0.11631863091190475), + FRAC_CONST(0.12849811079379317), FRAC_CONST(0.14065823933284921), FRAC_CONST(0.15279718525844344), FRAC_CONST(0.16491312048996989), FRAC_CONST(0.17700422041214875), + FRAC_CONST(0.18906866414980619), FRAC_CONST(0.2011046348420919), FRAC_CONST(0.21311031991609136), FRAC_CONST(0.22508391135979283), FRAC_CONST(0.2370236059943672), + FRAC_CONST(0.24892760574572015), FRAC_CONST(0.26079411791527551), FRAC_CONST(0.27262135544994898), FRAC_CONST(0.28440753721127188), FRAC_CONST(0.29615088824362379), + FRAC_CONST(0.30784964004153487), FRAC_CONST(0.31950203081601569), FRAC_CONST(0.33110630575987643), FRAC_CONST(0.34266071731199438), FRAC_CONST(0.35416352542049034), + FRAC_CONST(0.36561299780477385), FRAC_CONST(0.37700741021641826), FRAC_CONST(0.38834504669882625), FRAC_CONST(0.39962419984564679), FRAC_CONST(0.41084317105790391), + FRAC_CONST(0.42200027079979968), FRAC_CONST(0.43309381885315196), FRAC_CONST(0.4441221445704292), FRAC_CONST(0.45508358712634384), FRAC_CONST(0.46597649576796618), + FRAC_CONST(0.47679923006332209), FRAC_CONST(0.487550160148436), FRAC_CONST(0.49822766697278187), FRAC_CONST(0.50883014254310699), FRAC_CONST(0.51935599016558964), + FRAC_CONST(0.52980362468629461), FRAC_CONST(0.54017147272989285), FRAC_CONST(0.55045797293660481), FRAC_CONST(0.56066157619733603), FRAC_CONST(0.57078074588696726), + FRAC_CONST(0.58081395809576453), FRAC_CONST(0.59075970185887416), FRAC_CONST(0.60061647938386897), FRAC_CONST(0.61038280627630948), FRAC_CONST(0.6200572117632891), + FRAC_CONST(0.62963823891492698), FRAC_CONST(0.63912444486377573), FRAC_CONST(0.64851440102211244), FRAC_CONST(0.65780669329707864), FRAC_CONST(0.66699992230363747), + FRAC_CONST(0.67609270357531592), FRAC_CONST(0.68508366777270036), FRAC_CONST(0.693971460889654), FRAC_CONST(0.7027547444572253), FRAC_CONST(0.71143219574521643), + FRAC_CONST(0.72000250796138165), FRAC_CONST(0.7284643904482252), FRAC_CONST(0.73681656887736979), FRAC_CONST(0.74505778544146595), FRAC_CONST(0.75318679904361241), + FRAC_CONST(0.76120238548426178), FRAC_CONST(0.76910333764557959), FRAC_CONST(0.77688846567323244), FRAC_CONST(0.78455659715557524), FRAC_CONST(0.79210657730021239), + FRAC_CONST(0.79953726910790501), FRAC_CONST(0.80684755354379922), FRAC_CONST(0.8140363297059483), FRAC_CONST(0.82110251499110465), FRAC_CONST(0.8280450452577558), + FRAC_CONST(0.83486287498638001), FRAC_CONST(0.84155497743689833), FRAC_CONST(0.84812034480329712), FRAC_CONST(0.85455798836540053), FRAC_CONST(0.86086693863776731), + FRAC_CONST(0.86704624551569265), FRAC_CONST(0.87309497841829009), FRAC_CONST(0.87901222642863341), FRAC_CONST(0.88479709843093779), FRAC_CONST(0.89044872324475788), + FRAC_CONST(0.89596624975618511), FRAC_CONST(0.90134884704602203), FRAC_CONST(0.90659570451491533), FRAC_CONST(0.91170603200542988), FRAC_CONST(0.9166790599210427), + FRAC_CONST(0.9215140393420419), FRAC_CONST(0.92621024213831127), FRAC_CONST(0.93076696107898371), FRAC_CONST(0.9351835099389475), FRAC_CONST(0.93945922360218992), + FRAC_CONST(0.94359345816196039), FRAC_CONST(0.94758559101774109), FRAC_CONST(0.95143502096900834), FRAC_CONST(0.95514116830577067), FRAC_CONST(0.9587034748958716), + FRAC_CONST(0.96212140426904158), FRAC_CONST(0.9653944416976894), FRAC_CONST(0.96852209427441727), FRAC_CONST(0.97150389098625178), FRAC_CONST(0.97433938278557586), + FRAC_CONST(0.97702814265775439), FRAC_CONST(0.97956976568544052), FRAC_CONST(0.98196386910955524), FRAC_CONST(0.98421009238692903), FRAC_CONST(0.98630809724459867), + FRAC_CONST(0.98825756773074946), FRAC_CONST(0.99005821026229712), FRAC_CONST(0.99170975366909953), FRAC_CONST(0.9932119492347945), FRAC_CONST(0.99456457073425542), + FRAC_CONST(0.99576741446765982), FRAC_CONST(0.99682029929116567), FRAC_CONST(0.99772306664419164), FRAC_CONST(0.99847558057329477), FRAC_CONST(0.99907772775264536), + FRAC_CONST(0.99952941750109314), FRAC_CONST(0.9998305817958234), FRAC_CONST(0.99998117528260111)}; + +#ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t sine_short_120[] = { + FRAC_CONST(0.0065449379673518581), FRAC_CONST(0.019633692460628301), FRAC_CONST(0.032719082821776137), FRAC_CONST(0.045798866936520771), FRAC_CONST(0.058870803651189033), + FRAC_CONST(0.071932653156719387), FRAC_CONST(0.084982177372441667), FRAC_CONST(0.09801714032956059), FRAC_CONST(0.11103530855427769), FRAC_CONST(0.12403445145048532), + FRAC_CONST(0.13701234168196802), FRAC_CONST(0.14996675555404498), FRAC_CONST(0.16289547339458874), FRAC_CONST(0.17579627993435451), FRAC_CONST(0.18866696468655525), + FRAC_CONST(0.2015053223256171), FRAC_CONST(0.21430915306505074), FRAC_CONST(0.2270762630343732), FRAC_CONST(0.23980446465501654), FRAC_CONST(0.25249157701515795), + FRAC_CONST(0.26513542624340797), FRAC_CONST(0.27773384588129219), FRAC_CONST(0.29028467725446233), FRAC_CONST(0.3027857698425746), FRAC_CONST(0.31523498164776964), + FRAC_CONST(0.32763017956169349), FRAC_CONST(0.33996923973099424), FRAC_CONST(0.35225004792123354), FRAC_CONST(0.36447049987914965), FRAC_CONST(0.37662850169321077), + FRAC_CONST(0.38872197015239557), FRAC_CONST(0.40074883310314097), FRAC_CONST(0.41270702980439467), FRAC_CONST(0.42459451128071307), FRAC_CONST(0.43640924067334208), + FRAC_CONST(0.44814919358922256), FRAC_CONST(0.45981235844785984), FRAC_CONST(0.47139673682599764), FRAC_CONST(0.48290034380003727), FRAC_CONST(0.49432120828614462), + FRAC_CONST(0.50565737337798455), FRAC_CONST(0.51690689668202761), FRAC_CONST(0.52806785065036799), FRAC_CONST(0.53913832291100017), FRAC_CONST(0.55011641659549337), + FRAC_CONST(0.56100025066400983), FRAC_CONST(0.57178796022761225), FRAC_CONST(0.58247769686780215), FRAC_CONST(0.59306762895323706), FRAC_CONST(0.60355594195357143), + FRAC_CONST(0.61394083875036642), FRAC_CONST(0.62422053994501758), FRAC_CONST(0.63439328416364549), FRAC_CONST(0.64445732835889735), FRAC_CONST(0.65441094810861034), + FRAC_CONST(0.66425243791128175), FRAC_CONST(0.67398011147829784), FRAC_CONST(0.68359230202287125), FRAC_CONST(0.69308736254563585), FRAC_CONST(0.70246366611685174), + FRAC_CONST(0.71171960615517138), FRAC_CONST(0.72085359670291882), FRAC_CONST(0.7298640726978356), FRAC_CONST(0.73874949024124625), FRAC_CONST(0.74750832686259672), + FRAC_CONST(0.75613908178032285), FRAC_CONST(0.76464027615900032), FRAC_CONST(0.77301045336273699), FRAC_CONST(0.78124817920475853), FRAC_CONST(0.78935204219315003), + FRAC_CONST(0.79732065377270711), FRAC_CONST(0.80515264856285829), FRAC_CONST(0.81284668459161513), FRAC_CONST(0.82040144352551359), FRAC_CONST(0.82781563089550203), + FRAC_CONST(0.83508797631874299), FRAC_CONST(0.84221723371628654), FRAC_CONST(0.84920218152657889), FRAC_CONST(0.85604162291477137), FRAC_CONST(0.86273438597779184), + FRAC_CONST(0.86927932394514362), FRAC_CONST(0.87567531537539967), FRAC_CONST(0.88192126434835494), FRAC_CONST(0.88801610065280734), FRAC_CONST(0.89395877996993212), + FRAC_CONST(0.8997482840522214), FRAC_CONST(0.90538362089795521), FRAC_CONST(0.91086382492117568), FRAC_CONST(0.91618795711713596), FRAC_CONST(0.92135510522319242), + FRAC_CONST(0.9263643838751181), FRAC_CONST(0.93121493475880346), FRAC_CONST(0.93590592675732565), FRAC_CONST(0.94043655609335486), FRAC_CONST(0.94480604646687805), + FRAC_CONST(0.94901364918821385), FRAC_CONST(0.95305864330629697), FRAC_CONST(0.95694033573220882), FRAC_CONST(0.9606580613579353), FRAC_CONST(0.96421118317032928), + FRAC_CONST(0.96759909236025976), FRAC_CONST(0.9708212084269281), FRAC_CONST(0.97387697927733363), FRAC_CONST(0.97676588132087239), FRAC_CONST(0.97948741955905139), + FRAC_CONST(0.98204112767030394), FRAC_CONST(0.98442656808989171), FRAC_CONST(0.98664333208487898), FRAC_CONST(0.98869103982416728), FRAC_CONST(0.99056934044357725), + FRAC_CONST(0.99227791210596705), FRAC_CONST(0.99381646205637808), FRAC_CONST(0.99518472667219682), FRAC_CONST(0.99638247150832537), FRAC_CONST(0.99740949133735191), + FRAC_CONST(0.99826561018471593), FRAC_CONST(0.99895068135886012), FRAC_CONST(0.99946458747636568), FRAC_CONST(0.99980724048206482), FRAC_CONST(0.99997858166412923)}; +#endif + +#ifdef LD_DEC +static const real_t sine_mid_512[] = { + FRAC_CONST(0.0015339801862847655), FRAC_CONST(0.0046019261204485705), FRAC_CONST(0.007669828739531097), FRAC_CONST(0.010737659167264491), FRAC_CONST(0.013805388528060391), + FRAC_CONST(0.01687298794728171), FRAC_CONST(0.019940428551514441), FRAC_CONST(0.023007681468839369), FRAC_CONST(0.026074717829103901), FRAC_CONST(0.029141508764193722), + FRAC_CONST(0.032208025408304586), FRAC_CONST(0.035274238898213947), FRAC_CONST(0.038340120373552694), FRAC_CONST(0.041405640977076739), FRAC_CONST(0.044470771854938668), + FRAC_CONST(0.047535484156959303), FRAC_CONST(0.050599749036899282), FRAC_CONST(0.05366353765273052), FRAC_CONST(0.056726821166907748), FRAC_CONST(0.059789570746639868), + FRAC_CONST(0.062851757564161406), FRAC_CONST(0.065913352797003805), FRAC_CONST(0.068974327628266746), FRAC_CONST(0.072034653246889332), FRAC_CONST(0.075094300847921305), + FRAC_CONST(0.078153241632794232), FRAC_CONST(0.081211446809592441), FRAC_CONST(0.084268887593324071), FRAC_CONST(0.087325535206192059), FRAC_CONST(0.090381360877864983), + FRAC_CONST(0.093436335845747787), FRAC_CONST(0.096490431355252593), FRAC_CONST(0.099543618660069319), FRAC_CONST(0.10259586902243628), FRAC_CONST(0.10564715371341062), + FRAC_CONST(0.10869744401313872), FRAC_CONST(0.11174671121112659), FRAC_CONST(0.11479492660651008), FRAC_CONST(0.11784206150832498), FRAC_CONST(0.12088808723577708), + FRAC_CONST(0.12393297511851216), FRAC_CONST(0.12697669649688587), FRAC_CONST(0.13001922272223335), FRAC_CONST(0.13306052515713906), FRAC_CONST(0.1361005751757062), + FRAC_CONST(0.1391393441638262), FRAC_CONST(0.14217680351944803), FRAC_CONST(0.14521292465284746), FRAC_CONST(0.14824767898689603), FRAC_CONST(0.15128103795733022), + FRAC_CONST(0.1543129730130201), FRAC_CONST(0.15734345561623825), FRAC_CONST(0.16037245724292828), FRAC_CONST(0.16339994938297323), FRAC_CONST(0.1664259035404641), + FRAC_CONST(0.16945029123396796), FRAC_CONST(0.17247308399679595), FRAC_CONST(0.17549425337727143), FRAC_CONST(0.17851377093899751), FRAC_CONST(0.18153160826112497), + FRAC_CONST(0.18454773693861962), FRAC_CONST(0.1875621285825296), FRAC_CONST(0.19057475482025274), FRAC_CONST(0.19358558729580361), FRAC_CONST(0.19659459767008022), + FRAC_CONST(0.19960175762113097), FRAC_CONST(0.20260703884442113), FRAC_CONST(0.20561041305309924), FRAC_CONST(0.20861185197826349), FRAC_CONST(0.21161132736922755), + FRAC_CONST(0.21460881099378676), FRAC_CONST(0.21760427463848364), FRAC_CONST(0.22059769010887351), FRAC_CONST(0.22358902922978999), FRAC_CONST(0.22657826384561), + FRAC_CONST(0.22956536582051887), FRAC_CONST(0.23255030703877524), FRAC_CONST(0.23553305940497549), FRAC_CONST(0.23851359484431842), FRAC_CONST(0.24149188530286933), + FRAC_CONST(0.24446790274782415), FRAC_CONST(0.24744161916777327), FRAC_CONST(0.25041300657296522), FRAC_CONST(0.25338203699557016), FRAC_CONST(0.25634868248994291), + FRAC_CONST(0.25931291513288623), FRAC_CONST(0.26227470702391359), FRAC_CONST(0.26523403028551179), FRAC_CONST(0.26819085706340318), FRAC_CONST(0.27114515952680801), + FRAC_CONST(0.27409690986870638), FRAC_CONST(0.2770460803060999), FRAC_CONST(0.27999264308027322), FRAC_CONST(0.28293657045705539), FRAC_CONST(0.28587783472708062), + FRAC_CONST(0.28881640820604948), FRAC_CONST(0.29175226323498926), FRAC_CONST(0.29468537218051433), FRAC_CONST(0.2976157074350862), FRAC_CONST(0.30054324141727345), + FRAC_CONST(0.30346794657201132), FRAC_CONST(0.30638979537086092), FRAC_CONST(0.30930876031226873), FRAC_CONST(0.31222481392182488), FRAC_CONST(0.31513792875252244), + FRAC_CONST(0.31804807738501495), FRAC_CONST(0.32095523242787521), FRAC_CONST(0.32385936651785285), FRAC_CONST(0.32676045232013173), FRAC_CONST(0.32965846252858749), + FRAC_CONST(0.33255336986604422), FRAC_CONST(0.3354451470845316), FRAC_CONST(0.33833376696554113), FRAC_CONST(0.34121920232028236), FRAC_CONST(0.34410142598993881), + FRAC_CONST(0.34698041084592368), FRAC_CONST(0.34985612979013492), FRAC_CONST(0.35272855575521073), FRAC_CONST(0.35559766170478385), FRAC_CONST(0.35846342063373654), + FRAC_CONST(0.36132580556845428), FRAC_CONST(0.36418478956707989), FRAC_CONST(0.36704034571976718), FRAC_CONST(0.3698924471489341), FRAC_CONST(0.37274106700951576), + FRAC_CONST(0.37558617848921722), FRAC_CONST(0.37842775480876556), FRAC_CONST(0.38126576922216238), FRAC_CONST(0.38410019501693504), FRAC_CONST(0.38693100551438858), + FRAC_CONST(0.38975817406985641), FRAC_CONST(0.39258167407295147), FRAC_CONST(0.39540147894781635), FRAC_CONST(0.39821756215337356), FRAC_CONST(0.40102989718357562), + FRAC_CONST(0.40383845756765407), FRAC_CONST(0.40664321687036903), FRAC_CONST(0.40944414869225759), FRAC_CONST(0.41224122666988289), FRAC_CONST(0.41503442447608163), + FRAC_CONST(0.41782371582021227), FRAC_CONST(0.42060907444840251), FRAC_CONST(0.42339047414379605), FRAC_CONST(0.42616788872679962), FRAC_CONST(0.42894129205532949), + FRAC_CONST(0.43171065802505726), FRAC_CONST(0.43447596056965565), FRAC_CONST(0.43723717366104409), FRAC_CONST(0.43999427130963326), FRAC_CONST(0.44274722756457002), + FRAC_CONST(0.44549601651398174), FRAC_CONST(0.44824061228521989), FRAC_CONST(0.45098098904510386), FRAC_CONST(0.45371712100016387), FRAC_CONST(0.45644898239688392), + FRAC_CONST(0.45917654752194409), FRAC_CONST(0.46189979070246273), FRAC_CONST(0.46461868630623782), FRAC_CONST(0.46733320874198842), FRAC_CONST(0.47004333245959562), + FRAC_CONST(0.47274903195034279), FRAC_CONST(0.47545028174715587), FRAC_CONST(0.47814705642484301), FRAC_CONST(0.48083933060033396), FRAC_CONST(0.48352707893291874), + FRAC_CONST(0.48621027612448642), FRAC_CONST(0.48888889691976317), FRAC_CONST(0.4915629161065499), FRAC_CONST(0.49423230851595967), FRAC_CONST(0.49689704902265447), + FRAC_CONST(0.49955711254508184), FRAC_CONST(0.50221247404571079), FRAC_CONST(0.50486310853126759), FRAC_CONST(0.50750899105297087), FRAC_CONST(0.51015009670676681), + FRAC_CONST(0.51278640063356296), FRAC_CONST(0.51541787801946293), FRAC_CONST(0.51804450409599934), FRAC_CONST(0.52066625414036716), FRAC_CONST(0.52328310347565643), + FRAC_CONST(0.52589502747108463), FRAC_CONST(0.52850200154222848), FRAC_CONST(0.531104001151255), FRAC_CONST(0.53370100180715296), FRAC_CONST(0.53629297906596318), + FRAC_CONST(0.53887990853100842), FRAC_CONST(0.54146176585312344), FRAC_CONST(0.54403852673088382), FRAC_CONST(0.54661016691083486), FRAC_CONST(0.54917666218771966), + FRAC_CONST(0.55173798840470734), FRAC_CONST(0.55429412145362), FRAC_CONST(0.5568450372751601), FRAC_CONST(0.55939071185913614), FRAC_CONST(0.56193112124468947), + FRAC_CONST(0.5644662415205195), FRAC_CONST(0.56699604882510868), FRAC_CONST(0.56952051934694714), FRAC_CONST(0.57203962932475705), FRAC_CONST(0.57455335504771576), + FRAC_CONST(0.57706167285567944), FRAC_CONST(0.57956455913940563), FRAC_CONST(0.58206199034077544), FRAC_CONST(0.58455394295301533), FRAC_CONST(0.58704039352091797), + FRAC_CONST(0.58952131864106394), FRAC_CONST(0.59199669496204099), FRAC_CONST(0.59446649918466443), FRAC_CONST(0.5969307080621965), FRAC_CONST(0.59938929840056454), + FRAC_CONST(0.60184224705858003), FRAC_CONST(0.60428953094815596), FRAC_CONST(0.60673112703452448), FRAC_CONST(0.60916701233645321), FRAC_CONST(0.61159716392646191), + FRAC_CONST(0.61402155893103838), FRAC_CONST(0.61644017453085365), FRAC_CONST(0.61885298796097632), FRAC_CONST(0.62125997651108755), FRAC_CONST(0.62366111752569453), + FRAC_CONST(0.62605638840434352), FRAC_CONST(0.62844576660183271), FRAC_CONST(0.63082922962842447), FRAC_CONST(0.63320675505005719), FRAC_CONST(0.63557832048855611), + FRAC_CONST(0.63794390362184406), FRAC_CONST(0.64030348218415167), FRAC_CONST(0.64265703396622686), FRAC_CONST(0.64500453681554393), FRAC_CONST(0.64734596863651206), + FRAC_CONST(0.64968130739068319), FRAC_CONST(0.6520105310969595), FRAC_CONST(0.65433361783180044), FRAC_CONST(0.65665054572942894), FRAC_CONST(0.65896129298203732), + FRAC_CONST(0.66126583783999227), FRAC_CONST(0.66356415861203977), FRAC_CONST(0.66585623366550972), FRAC_CONST(0.66814204142651845), FRAC_CONST(0.67042156038017309), + FRAC_CONST(0.67269476907077286), FRAC_CONST(0.67496164610201193), FRAC_CONST(0.67722217013718033), FRAC_CONST(0.67947631989936497), FRAC_CONST(0.68172407417164971), + FRAC_CONST(0.6839654117973154), FRAC_CONST(0.68620031168003859), FRAC_CONST(0.68842875278409044), FRAC_CONST(0.6906507141345346), FRAC_CONST(0.69286617481742463), + FRAC_CONST(0.69507511398000088), FRAC_CONST(0.69727751083088652), FRAC_CONST(0.69947334464028377), FRAC_CONST(0.70166259474016845), FRAC_CONST(0.70384524052448494), + FRAC_CONST(0.70602126144933974), FRAC_CONST(0.70819063703319529), FRAC_CONST(0.71035334685706231), FRAC_CONST(0.71250937056469232), FRAC_CONST(0.71465868786276898), + FRAC_CONST(0.71680127852109954), FRAC_CONST(0.71893712237280438), FRAC_CONST(0.72106619931450811), FRAC_CONST(0.72318848930652735), FRAC_CONST(0.72530397237306066), + FRAC_CONST(0.72741262860237577), FRAC_CONST(0.7295144381469969), FRAC_CONST(0.73160938122389252), FRAC_CONST(0.73369743811466026), FRAC_CONST(0.73577858916571348), + FRAC_CONST(0.73785281478846598), FRAC_CONST(0.73992009545951609), FRAC_CONST(0.74198041172083096), FRAC_CONST(0.74403374417992918), FRAC_CONST(0.74608007351006378), + FRAC_CONST(0.74811938045040349), FRAC_CONST(0.75015164580621496), FRAC_CONST(0.7521768504490427), FRAC_CONST(0.75419497531688917), FRAC_CONST(0.75620600141439454), + FRAC_CONST(0.75820990981301528), FRAC_CONST(0.76020668165120242), FRAC_CONST(0.7621962981345789), FRAC_CONST(0.76417874053611667), FRAC_CONST(0.76615399019631281), + FRAC_CONST(0.76812202852336531), FRAC_CONST(0.7700828369933479), FRAC_CONST(0.77203639715038441), FRAC_CONST(0.77398269060682279), FRAC_CONST(0.77592169904340758), + FRAC_CONST(0.77785340420945304), FRAC_CONST(0.77977778792301444), FRAC_CONST(0.78169483207105939), FRAC_CONST(0.7836045186096382), FRAC_CONST(0.78550682956405393), + FRAC_CONST(0.78740174702903132), FRAC_CONST(0.78928925316888565), FRAC_CONST(0.79116933021769009), FRAC_CONST(0.79304196047944364), FRAC_CONST(0.79490712632823701), + FRAC_CONST(0.79676481020841872), FRAC_CONST(0.79861499463476082), FRAC_CONST(0.80045766219262271), FRAC_CONST(0.80229279553811572), FRAC_CONST(0.8041203773982657), + FRAC_CONST(0.80594039057117628), FRAC_CONST(0.80775281792619036), FRAC_CONST(0.80955764240405126), FRAC_CONST(0.81135484701706373), FRAC_CONST(0.81314441484925359), + FRAC_CONST(0.81492632905652662), FRAC_CONST(0.81670057286682785), FRAC_CONST(0.81846712958029866), FRAC_CONST(0.82022598256943469), FRAC_CONST(0.82197711527924155), + FRAC_CONST(0.82372051122739132), FRAC_CONST(0.82545615400437744), FRAC_CONST(0.82718402727366902), FRAC_CONST(0.82890411477186487), FRAC_CONST(0.8306164003088462), + FRAC_CONST(0.83232086776792968), FRAC_CONST(0.83401750110601813), FRAC_CONST(0.8357062843537526), FRAC_CONST(0.83738720161566194), FRAC_CONST(0.83906023707031263), + FRAC_CONST(0.84072537497045807), FRAC_CONST(0.84238259964318596), FRAC_CONST(0.84403189549006641), FRAC_CONST(0.84567324698729907), FRAC_CONST(0.84730663868585832), + FRAC_CONST(0.84893205521163961), FRAC_CONST(0.85054948126560337), FRAC_CONST(0.85215890162391983), FRAC_CONST(0.8537603011381113), FRAC_CONST(0.85535366473519603), + FRAC_CONST(0.85693897741782865), FRAC_CONST(0.85851622426444274), FRAC_CONST(0.86008539042939014), FRAC_CONST(0.8616464611430813), FRAC_CONST(0.86319942171212416), + FRAC_CONST(0.86474425751946238), FRAC_CONST(0.86628095402451299), FRAC_CONST(0.86780949676330321), FRAC_CONST(0.86932987134860673), FRAC_CONST(0.87084206347007886), + FRAC_CONST(0.87234605889439154), FRAC_CONST(0.87384184346536675), FRAC_CONST(0.87532940310411078), FRAC_CONST(0.87680872380914576), FRAC_CONST(0.87827979165654146), + FRAC_CONST(0.87974259280004741), FRAC_CONST(0.88119711347122198), FRAC_CONST(0.88264333997956279), FRAC_CONST(0.88408125871263499), FRAC_CONST(0.88551085613619995), + FRAC_CONST(0.88693211879434208), FRAC_CONST(0.88834503330959624), FRAC_CONST(0.88974958638307289), FRAC_CONST(0.89114576479458318), FRAC_CONST(0.89253355540276469), + FRAC_CONST(0.89391294514520325), FRAC_CONST(0.89528392103855758), FRAC_CONST(0.89664647017868015), FRAC_CONST(0.89800057974073988), FRAC_CONST(0.89934623697934146), + FRAC_CONST(0.90068342922864686), FRAC_CONST(0.90201214390249307), FRAC_CONST(0.90333236849451182), FRAC_CONST(0.90464409057824624), FRAC_CONST(0.90594729780726846), + FRAC_CONST(0.90724197791529593), FRAC_CONST(0.90852811871630612), FRAC_CONST(0.90980570810465222), FRAC_CONST(0.91107473405517625), FRAC_CONST(0.91233518462332275), + FRAC_CONST(0.91358704794525081), FRAC_CONST(0.91483031223794609), FRAC_CONST(0.91606496579933161), FRAC_CONST(0.91729099700837791), FRAC_CONST(0.91850839432521225), + FRAC_CONST(0.91971714629122736), FRAC_CONST(0.92091724152918952), FRAC_CONST(0.92210866874334507), FRAC_CONST(0.92329141671952764), FRAC_CONST(0.9244654743252626), + FRAC_CONST(0.92563083050987272), FRAC_CONST(0.92678747430458175), FRAC_CONST(0.92793539482261789), FRAC_CONST(0.92907458125931575), FRAC_CONST(0.93020502289221907), + FRAC_CONST(0.93132670908118043), FRAC_CONST(0.93243962926846236), FRAC_CONST(0.93354377297883617), FRAC_CONST(0.93463912981968078), FRAC_CONST(0.93572568948108037), + FRAC_CONST(0.93680344173592156), FRAC_CONST(0.93787237643998989), FRAC_CONST(0.93893248353206449), FRAC_CONST(0.93998375303401394), FRAC_CONST(0.94102617505088926), + FRAC_CONST(0.94205973977101731), FRAC_CONST(0.94308443746609349), FRAC_CONST(0.94410025849127266), FRAC_CONST(0.94510719328526061), FRAC_CONST(0.94610523237040334), + FRAC_CONST(0.94709436635277722), FRAC_CONST(0.94807458592227623), FRAC_CONST(0.94904588185270056), FRAC_CONST(0.950008245001843), FRAC_CONST(0.95096166631157508), + FRAC_CONST(0.95190613680793223), FRAC_CONST(0.95284164760119872), FRAC_CONST(0.95376818988599033), FRAC_CONST(0.95468575494133834), FRAC_CONST(0.95559433413077111), + FRAC_CONST(0.95649391890239499), FRAC_CONST(0.95738450078897586), FRAC_CONST(0.95826607140801767), FRAC_CONST(0.95913862246184189), FRAC_CONST(0.96000214573766585), + FRAC_CONST(0.96085663310767966), FRAC_CONST(0.96170207652912254), FRAC_CONST(0.96253846804435916), FRAC_CONST(0.96336579978095405), FRAC_CONST(0.96418406395174572), + FRAC_CONST(0.96499325285492032), FRAC_CONST(0.96579335887408357), FRAC_CONST(0.96658437447833312), FRAC_CONST(0.96736629222232851), FRAC_CONST(0.96813910474636233), + FRAC_CONST(0.96890280477642887), FRAC_CONST(0.96965738512429245), FRAC_CONST(0.9704028386875555), FRAC_CONST(0.97113915844972509), FRAC_CONST(0.9718663374802794), + FRAC_CONST(0.97258436893473221), FRAC_CONST(0.97329324605469825), FRAC_CONST(0.97399296216795583), FRAC_CONST(0.97468351068851067), FRAC_CONST(0.97536488511665687), + FRAC_CONST(0.97603707903903902), FRAC_CONST(0.97670008612871184), FRAC_CONST(0.97735390014519996), FRAC_CONST(0.97799851493455714), FRAC_CONST(0.9786339244294231), + FRAC_CONST(0.97926012264908202), FRAC_CONST(0.97987710369951764), FRAC_CONST(0.98048486177346938), FRAC_CONST(0.98108339115048659), FRAC_CONST(0.98167268619698311), + FRAC_CONST(0.98225274136628937), FRAC_CONST(0.98282355119870524), FRAC_CONST(0.98338511032155118), FRAC_CONST(0.98393741344921892), FRAC_CONST(0.98448045538322093), + FRAC_CONST(0.98501423101223984), FRAC_CONST(0.98553873531217606), FRAC_CONST(0.98605396334619544), FRAC_CONST(0.98655991026477541), FRAC_CONST(0.98705657130575097), + FRAC_CONST(0.98754394179435923), FRAC_CONST(0.98802201714328353), FRAC_CONST(0.98849079285269659), FRAC_CONST(0.98895026451030299), FRAC_CONST(0.98940042779138038), + FRAC_CONST(0.98984127845882053), FRAC_CONST(0.99027281236316911), FRAC_CONST(0.99069502544266463), FRAC_CONST(0.99110791372327678), FRAC_CONST(0.9915114733187439), + FRAC_CONST(0.99190570043060933), FRAC_CONST(0.99229059134825737), FRAC_CONST(0.99266614244894802), FRAC_CONST(0.99303235019785141), FRAC_CONST(0.99338921114808065), + FRAC_CONST(0.9937367219407246), FRAC_CONST(0.99407487930487937), FRAC_CONST(0.9944036800576791), FRAC_CONST(0.9947231211043257), FRAC_CONST(0.99503319943811863), + FRAC_CONST(0.99533391214048228), FRAC_CONST(0.99562525638099431), FRAC_CONST(0.99590722941741172), FRAC_CONST(0.99617982859569687), FRAC_CONST(0.99644305135004263), + FRAC_CONST(0.99669689520289606), FRAC_CONST(0.99694135776498216), FRAC_CONST(0.99717643673532619), FRAC_CONST(0.9974021299012753), FRAC_CONST(0.99761843513851955), + FRAC_CONST(0.99782535041111164), FRAC_CONST(0.99802287377148624), FRAC_CONST(0.99821100336047819), FRAC_CONST(0.99838973740734016), FRAC_CONST(0.99855907422975931), + FRAC_CONST(0.99871901223387294), FRAC_CONST(0.99886954991428356), FRAC_CONST(0.99901068585407338), FRAC_CONST(0.99914241872481691), FRAC_CONST(0.99926474728659442), + FRAC_CONST(0.99937767038800285), FRAC_CONST(0.99948118696616695), FRAC_CONST(0.99957529604674922), FRAC_CONST(0.99965999674395922), FRAC_CONST(0.99973528826056168), + FRAC_CONST(0.99980116988788426), FRAC_CONST(0.99985764100582386), FRAC_CONST(0.9999047010828529), FRAC_CONST(0.99994234967602391), FRAC_CONST(0.99997058643097414), + FRAC_CONST(0.9999894110819284), FRAC_CONST(0.99999882345170188)}; + + #ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t sine_mid_480[] = { + FRAC_CONST(0.0016362454436240478), FRAC_CONST(0.00490871880799799), FRAC_CONST(0.0081811396039371282), FRAC_CONST(0.011453472786443779), FRAC_CONST(0.014725683311458524), + FRAC_CONST(0.017997736136235509), FRAC_CONST(0.021269596219717739), FRAC_CONST(0.024541228522912285), FRAC_CONST(0.027812598009265607), FRAC_CONST(0.03108366964503869), + FRAC_CONST(0.034354408399682276), FRAC_CONST(0.037624779246211978), FRAC_CONST(0.04089474716158345), FRAC_CONST(0.044164277127067358), FRAC_CONST(0.047433334128624507), + FRAC_CONST(0.050701883157280733), FRAC_CONST(0.053969889209501881), FRAC_CONST(0.057237317287568618), FRAC_CONST(0.060504132399951269), FRAC_CONST(0.063770299561684493), + FRAC_CONST(0.06703578379474201), FRAC_CONST(0.070300550128411174), FRAC_CONST(0.073564563599667426), FRAC_CONST(0.076827789253548759), FRAC_CONST(0.080090192143530081), + FRAC_CONST(0.083351737331897449), FRAC_CONST(0.086612389890122182), FRAC_CONST(0.089872114899234967), FRAC_CONST(0.093130877450199795), FRAC_CONST(0.096388642644287828), + FRAC_CONST(0.09964537559345106), FRAC_CONST(0.1029010414206961), FRAC_CONST(0.10615560526045748), FRAC_CONST(0.10940903225897117), FRAC_CONST(0.11266128757464781), + FRAC_CONST(0.11591233637844581), FRAC_CONST(0.11916214385424433), FRAC_CONST(0.1224106751992162), FRAC_CONST(0.12565789562420052), FRAC_CONST(0.12890377035407541), + FRAC_CONST(0.13214826462813015), FRAC_CONST(0.13539134370043773), FRAC_CONST(0.13863297284022669), FRAC_CONST(0.14187311733225325), FRAC_CONST(0.14511174247717309), + FRAC_CONST(0.14834881359191271), FRAC_CONST(0.15158429601004111), FRAC_CONST(0.15481815508214106), FRAC_CONST(0.1580503561761798), FRAC_CONST(0.16128086467788047), + FRAC_CONST(0.16450964599109233), FRAC_CONST(0.16773666553816149), FRAC_CONST(0.17096188876030122), FRAC_CONST(0.17418528111796186), FRAC_CONST(0.17740680809120093), + FRAC_CONST(0.18062643518005275), FRAC_CONST(0.18384412790489776), FRAC_CONST(0.18705985180683199), FRAC_CONST(0.19027357244803589), FRAC_CONST(0.19348525541214331), + FRAC_CONST(0.19669486630460997), FRAC_CONST(0.19990237075308173), FRAC_CONST(0.20310773440776286), FRAC_CONST(0.20631092294178383), FRAC_CONST(0.20951190205156878), + FRAC_CONST(0.21271063745720317), FRAC_CONST(0.21590709490280058), FRAC_CONST(0.2191012401568698), FRAC_CONST(0.22229303901268133), FRAC_CONST(0.22548245728863364), + FRAC_CONST(0.22866946082861941), FRAC_CONST(0.23185401550239115), FRAC_CONST(0.23503608720592667), FRAC_CONST(0.23821564186179459), FRAC_CONST(0.24139264541951888), + FRAC_CONST(0.24456706385594387), FRAC_CONST(0.24773886317559846), FRAC_CONST(0.25090800941106001), FRAC_CONST(0.25407446862331851), FRAC_CONST(0.25723820690213967), + FRAC_CONST(0.26039919036642817), FRAC_CONST(0.26355738516459076), FRAC_CONST(0.26671275747489837), FRAC_CONST(0.2698652735058486), FRAC_CONST(0.27301489949652735), + FRAC_CONST(0.27616160171697068), FRAC_CONST(0.27930534646852595), FRAC_CONST(0.28244610008421245), FRAC_CONST(0.2855838289290823), FRAC_CONST(0.28871849940058025), + FRAC_CONST(0.29185007792890405), FRAC_CONST(0.29497853097736348), FRAC_CONST(0.2981038250427398), FRAC_CONST(0.30122592665564446), FRAC_CONST(0.30434480238087736), + FRAC_CONST(0.30746041881778519), FRAC_CONST(0.31057274260061901), FRAC_CONST(0.31368174039889146), FRAC_CONST(0.31678737891773395), FRAC_CONST(0.31988962489825296), + FRAC_CONST(0.32298844511788638), FRAC_CONST(0.32608380639075912), FRAC_CONST(0.32917567556803889), FRAC_CONST(0.33226401953829071), FRAC_CONST(0.33534880522783189), + FRAC_CONST(0.33842999960108583), FRAC_CONST(0.34150756966093632), FRAC_CONST(0.34458148244908043), FRAC_CONST(0.34765170504638188), FRAC_CONST(0.35071820457322322), + FRAC_CONST(0.35378094818985806), FRAC_CONST(0.35683990309676283), FRAC_CONST(0.35989503653498811), FRAC_CONST(0.36294631578650921), FRAC_CONST(0.36599370817457672), + FRAC_CONST(0.36903718106406647), FRAC_CONST(0.37207670186182878), FRAC_CONST(0.37511223801703802), FRAC_CONST(0.37814375702154046), FRAC_CONST(0.38117122641020335), + FRAC_CONST(0.38419461376126157), FRAC_CONST(0.38721388669666562), FRAC_CONST(0.39022901288242801), FRAC_CONST(0.39323996002896966), FRAC_CONST(0.39624669589146555), + FRAC_CONST(0.39924918827019029), FRAC_CONST(0.40224740501086254), FRAC_CONST(0.40524131400498986), FRAC_CONST(0.40823088319021217), FRAC_CONST(0.41121608055064529), + FRAC_CONST(0.41419687411722372), FRAC_CONST(0.41717323196804335), FRAC_CONST(0.42014512222870243), FRAC_CONST(0.42311251307264408), FRAC_CONST(0.42607537272149631), + FRAC_CONST(0.4290336694454126), FRAC_CONST(0.43198737156341183), FRAC_CONST(0.43493644744371707), FRAC_CONST(0.43788086550409511), FRAC_CONST(0.44082059421219388), + FRAC_CONST(0.44375560208588088), FRAC_CONST(0.44668585769357955), FRAC_CONST(0.4496113296546066), FRAC_CONST(0.45253198663950756), FRAC_CONST(0.45544779737039259), + FRAC_CONST(0.45835873062127125), FRAC_CONST(0.46126475521838717), FRAC_CONST(0.46416584004055156), FRAC_CONST(0.46706195401947659), FRAC_CONST(0.46995306614010829), + FRAC_CONST(0.47283914544095862), FRAC_CONST(0.47572016101443682), FRAC_CONST(0.47859608200718085), FRAC_CONST(0.4814668776203872), FRAC_CONST(0.48433251711014125), + FRAC_CONST(0.4871929697877464), FRAC_CONST(0.49004820502005247), FRAC_CONST(0.49289819222978404), FRAC_CONST(0.49574290089586776), FRAC_CONST(0.49858230055375902), + FRAC_CONST(0.50141636079576901), FRAC_CONST(0.50424505127138919), FRAC_CONST(0.50706834168761705), FRAC_CONST(0.50988620180928057), FRAC_CONST(0.51269860145936175), + FRAC_CONST(0.51550551051931948), FRAC_CONST(0.51830689892941317), FRAC_CONST(0.5211027366890234), FRAC_CONST(0.52389299385697385), FRAC_CONST(0.52667764055185196), + FRAC_CONST(0.52945664695232897), FRAC_CONST(0.53222998329747884), FRAC_CONST(0.53499761988709726), FRAC_CONST(0.53775952708201991), FRAC_CONST(0.54051567530443978), + FRAC_CONST(0.54326603503822357), FRAC_CONST(0.54601057682922816), FRAC_CONST(0.54874927128561579), FRAC_CONST(0.55148208907816942), FRAC_CONST(0.55420900094060566), + FRAC_CONST(0.55692997766988939), FRAC_CONST(0.559644990126546), FRAC_CONST(0.56235400923497314), FRAC_CONST(0.56505700598375252), FRAC_CONST(0.56775395142596052), + FRAC_CONST(0.57044481667947822), FRAC_CONST(0.57312957292730071), FRAC_CONST(0.57580819141784534), FRAC_CONST(0.57848064346525996), FRAC_CONST(0.58114690044973039), + FRAC_CONST(0.58380693381778626), FRAC_CONST(0.58646071508260733), FRAC_CONST(0.58910821582432815), FRAC_CONST(0.5917494076903429), FRAC_CONST(0.5943842623956086), + FRAC_CONST(0.59701275172294799), FRAC_CONST(0.59963484752335228), FRAC_CONST(0.60225052171628191), FRAC_CONST(0.60485974628996786), FRAC_CONST(0.60746249330171098), + FRAC_CONST(0.61005873487818185), FRAC_CONST(0.61264844321571899), FRAC_CONST(0.61523159058062682), FRAC_CONST(0.61780814930947225), FRAC_CONST(0.62037809180938108), + FRAC_CONST(0.62294139055833397), FRAC_CONST(0.6254980181054608), FRAC_CONST(0.62804794707133416), FRAC_CONST(0.63059115014826372), FRAC_CONST(0.63312760010058777), + FRAC_CONST(0.63565726976496484), FRAC_CONST(0.63818013205066515), FRAC_CONST(0.64069615993986073), FRAC_CONST(0.64320532648791406), FRAC_CONST(0.64570760482366729), + FRAC_CONST(0.64820296814972966), FRAC_CONST(0.65069138974276486), FRAC_CONST(0.65317284295377676), FRAC_CONST(0.65564730120839498), FRAC_CONST(0.65811473800715958), + FRAC_CONST(0.660575126925805), FRAC_CONST(0.66302844161554231), FRAC_CONST(0.6654746558033422), FRAC_CONST(0.66791374329221598), FRAC_CONST(0.67034567796149647), + FRAC_CONST(0.67277043376711676), FRAC_CONST(0.67518798474189046), FRAC_CONST(0.67759830499578866), FRAC_CONST(0.68000136871621808), FRAC_CONST(0.68239715016829683), + FRAC_CONST(0.6847856236951303), FRAC_CONST(0.68716676371808583), FRAC_CONST(0.68954054473706683), FRAC_CONST(0.69190694133078579), FRAC_CONST(0.69426592815703603), + FRAC_CONST(0.69661747995296419), FRAC_CONST(0.69896157153533944), FRAC_CONST(0.70129817780082437), FRAC_CONST(0.7036272737262429), FRAC_CONST(0.70594883436884903), + FRAC_CONST(0.70826283486659336), FRAC_CONST(0.71056925043838959), FRAC_CONST(0.71286805638437978), FRAC_CONST(0.71515922808619936), FRAC_CONST(0.71744274100723993), + FRAC_CONST(0.71971857069291278), FRAC_CONST(0.7219866927709101), FRAC_CONST(0.72424708295146689), FRAC_CONST(0.72649971702762028), FRAC_CONST(0.72874457087546896), + FRAC_CONST(0.73098162045443171), FRAC_CONST(0.73321084180750484), FRAC_CONST(0.73543221106151868), FRAC_CONST(0.73764570442739286), FRAC_CONST(0.73985129820039208), + FRAC_CONST(0.74204896876037885), FRAC_CONST(0.7442386925720671), FRAC_CONST(0.74642044618527381), FRAC_CONST(0.74859420623517081), FRAC_CONST(0.75075994944253421), + FRAC_CONST(0.75291765261399446), FRAC_CONST(0.75506729264228367), FRAC_CONST(0.75720884650648446), FRAC_CONST(0.75934229127227548), FRAC_CONST(0.76146760409217706), + FRAC_CONST(0.76358476220579641), FRAC_CONST(0.7656937429400712), FRAC_CONST(0.76779452370951196), FRAC_CONST(0.76988708201644451), FRAC_CONST(0.77197139545125026), + FRAC_CONST(0.7740474416926072), FRAC_CONST(0.77611519850772781), FRAC_CONST(0.77817464375259782), FRAC_CONST(0.78022575537221317), FRAC_CONST(0.78226851140081632), + FRAC_CONST(0.78430288996213138), FRAC_CONST(0.78632886926959822), FRAC_CONST(0.78834642762660623), FRAC_CONST(0.79035554342672631), FRAC_CONST(0.79235619515394229), + FRAC_CONST(0.79434836138288134), FRAC_CONST(0.79633202077904397), FRAC_CONST(0.79830715209903147), FRAC_CONST(0.8002737341907743), FRAC_CONST(0.80223174599375802), + FRAC_CONST(0.80418116653924954), FRAC_CONST(0.80612197495052085), FRAC_CONST(0.80805415044307316), FRAC_CONST(0.80997767232485907), FRAC_CONST(0.81189251999650469), + FRAC_CONST(0.81379867295152986), FRAC_CONST(0.81569611077656778), FRAC_CONST(0.81758481315158371), FRAC_CONST(0.81946475985009259), FRAC_CONST(0.82133593073937561), + FRAC_CONST(0.82319830578069586), FRAC_CONST(0.82505186502951278), FRAC_CONST(0.82689658863569615), FRAC_CONST(0.82873245684373809), FRAC_CONST(0.83055944999296494), + FRAC_CONST(0.83237754851774781), FRAC_CONST(0.83418673294771239), FRAC_CONST(0.83598698390794668), FRAC_CONST(0.83777828211920935), FRAC_CONST(0.83956060839813562), + FRAC_CONST(0.84133394365744296), FRAC_CONST(0.84309826890613537), FRAC_CONST(0.84485356524970701), FRAC_CONST(0.84659981389034411), FRAC_CONST(0.84833699612712676), + FRAC_CONST(0.85006509335622882), FRAC_CONST(0.8517840870711173), FRAC_CONST(0.85349395886275037), FRAC_CONST(0.85519469041977514), FRAC_CONST(0.85688626352872277), + FRAC_CONST(0.85856866007420429), FRAC_CONST(0.86024186203910447), FRAC_CONST(0.86190585150477417), FRAC_CONST(0.86356061065122347), FRAC_CONST(0.86520612175731115), + FRAC_CONST(0.86684236720093533), FRAC_CONST(0.86846932945922151), FRAC_CONST(0.87008699110871135), FRAC_CONST(0.87169533482554817), FRAC_CONST(0.87329434338566281), + FRAC_CONST(0.87488399966495822), FRAC_CONST(0.87646428663949283), FRAC_CONST(0.87803518738566277), FRAC_CONST(0.87959668508038291), FRAC_CONST(0.88114876300126743), + FRAC_CONST(0.88269140452680916), FRAC_CONST(0.8842245931365561), FRAC_CONST(0.88574831241129048), FRAC_CONST(0.88726254603320276), FRAC_CONST(0.88876727778606746), + FRAC_CONST(0.89026249155541637), FRAC_CONST(0.8917481713287112), FRAC_CONST(0.89322430119551532), FRAC_CONST(0.89469086534766362), FRAC_CONST(0.89614784807943237), + FRAC_CONST(0.89759523378770689), FRAC_CONST(0.89903300697214927), FRAC_CONST(0.9004611522353636), FRAC_CONST(0.90187965428306172), FRAC_CONST(0.90328849792422594), + FRAC_CONST(0.90468766807127299), FRAC_CONST(0.90607714974021469), FRAC_CONST(0.90745692805081868), FRAC_CONST(0.90882698822676755), FRAC_CONST(0.91018731559581767), + FRAC_CONST(0.91153789558995579), FRAC_CONST(0.91287871374555518), FRAC_CONST(0.91420975570353069), FRAC_CONST(0.9155310072094921), FRAC_CONST(0.91684245411389753), + FRAC_CONST(0.91814408237220391), FRAC_CONST(0.91943587804501858), FRAC_CONST(0.92071782729824769), FRAC_CONST(0.92198991640324446), FRAC_CONST(0.92325213173695675), + FRAC_CONST(0.92450445978207241), FRAC_CONST(0.92574688712716402), FRAC_CONST(0.92697940046683291), FRAC_CONST(0.92820198660185149), FRAC_CONST(0.92941463243930444), + FRAC_CONST(0.93061732499272909), FRAC_CONST(0.93181005138225426), FRAC_CONST(0.93299279883473885), FRAC_CONST(0.93416555468390772), FRAC_CONST(0.93532830637048769), + FRAC_CONST(0.93648104144234268), FRAC_CONST(0.93762374755460598), FRAC_CONST(0.93875641246981323), FRAC_CONST(0.93987902405803303), FRAC_CONST(0.94099157029699743), + FRAC_CONST(0.94209403927222979), FRAC_CONST(0.94318641917717327), FRAC_CONST(0.9442686983133165), FRAC_CONST(0.94534086509031956), FRAC_CONST(0.9464029080261378), + FRAC_CONST(0.94745481574714419), FRAC_CONST(0.94849657698825252), FRAC_CONST(0.94952818059303667), FRAC_CONST(0.95054961551385087), FRAC_CONST(0.95156087081194762), + FRAC_CONST(0.95256193565759528), FRAC_CONST(0.95355279933019343), FRAC_CONST(0.9545334512183884), FRAC_CONST(0.95550388082018611), FRAC_CONST(0.95646407774306541), + FRAC_CONST(0.95741403170408834), FRAC_CONST(0.95835373253001133), FRAC_CONST(0.95928317015739362), FRAC_CONST(0.96020233463270466), FRAC_CONST(0.96111121611243155), + FRAC_CONST(0.96200980486318388), FRAC_CONST(0.96289809126179782), FRAC_CONST(0.96377606579543984), FRAC_CONST(0.96464371906170809), FRAC_CONST(0.96550104176873297), + FRAC_CONST(0.96634802473527726), FRAC_CONST(0.96718465889083372), FRAC_CONST(0.96801093527572268), FRAC_CONST(0.96882684504118799), FRAC_CONST(0.96963237944949143), + FRAC_CONST(0.97042752987400682), FRAC_CONST(0.97121228779931179), FRAC_CONST(0.97198664482127939), FRAC_CONST(0.97275059264716823), FRAC_CONST(0.97350412309571066), + FRAC_CONST(0.97424722809720088), FRAC_CONST(0.97497989969358168), FRAC_CONST(0.97570213003852857), FRAC_CONST(0.97641391139753486), FRAC_CONST(0.97711523614799412), + FRAC_CONST(0.97780609677928154), FRAC_CONST(0.97848648589283505), FRAC_CONST(0.97915639620223371), FRAC_CONST(0.9798158205332762), FRAC_CONST(0.98046475182405801), + FRAC_CONST(0.98110318312504607), FRAC_CONST(0.98173110759915416), FRAC_CONST(0.98234851852181571), FRAC_CONST(0.98295540928105563), FRAC_CONST(0.9835517733775615), + FRAC_CONST(0.98413760442475307), FRAC_CONST(0.98471289614885038), FRAC_CONST(0.98527764238894122), FRAC_CONST(0.98583183709704714), FRAC_CONST(0.98637547433818806), + FRAC_CONST(0.98690854829044583), FRAC_CONST(0.98743105324502667), FRAC_CONST(0.98794298360632238), FRAC_CONST(0.98844433389196995), FRAC_CONST(0.98893509873291074), + FRAC_CONST(0.98941527287344755), FRAC_CONST(0.98988485117130098), FRAC_CONST(0.99034382859766479), FRAC_CONST(0.99079220023725967), FRAC_CONST(0.99122996128838525), + FRAC_CONST(0.9916571070629725), FRAC_CONST(0.99207363298663342), FRAC_CONST(0.99247953459870997), FRAC_CONST(0.99287480755232194), FRAC_CONST(0.99325944761441354), + FRAC_CONST(0.99363345066579889), FRAC_CONST(0.99399681270120555), FRAC_CONST(0.99434952982931812), FRAC_CONST(0.9946915982728195), FRAC_CONST(0.99502301436843166), + FRAC_CONST(0.99534377456695422), FRAC_CONST(0.9956538754333033), FRAC_CONST(0.99595331364654771), FRAC_CONST(0.99624208599994479), FRAC_CONST(0.99652018940097464), + FRAC_CONST(0.99678762087137318), FRAC_CONST(0.99704437754716424), FRAC_CONST(0.99729045667869021), FRAC_CONST(0.99752585563064111), FRAC_CONST(0.99775057188208349), + FRAC_CONST(0.9979646030264866), FRAC_CONST(0.99816794677174903), FRAC_CONST(0.9983606009402225), FRAC_CONST(0.99854256346873571), FRAC_CONST(0.99871383240861611), + FRAC_CONST(0.99887440592571108), FRAC_CONST(0.99902428230040718), FRAC_CONST(0.99916345992764877), FRAC_CONST(0.99929193731695531), FRAC_CONST(0.99940971309243731), + FRAC_CONST(0.99951678599281069), FRAC_CONST(0.99961315487141078), FRAC_CONST(0.99969881869620425), FRAC_CONST(0.99977377654980037), FRAC_CONST(0.99983802762946083), + FRAC_CONST(0.99989157124710804), FRAC_CONST(0.9999344068293331), FRAC_CONST(0.99996653391740109), FRAC_CONST(0.99998795216725689), FRAC_CONST(0.99999866134952808)}; + #endif + +static const real_t ld_mid_512[] = {FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0.0061358846491544753), + FRAC_CONST(0.01840672990580482), + FRAC_CONST(0.030674803176636626), + FRAC_CONST(0.04293825693494082), + FRAC_CONST(0.055195244349689934), + FRAC_CONST(0.067443919563664051), + FRAC_CONST(0.079682437971430126), + FRAC_CONST(0.091908956497132724), + FRAC_CONST(0.10412163387205459), + FRAC_CONST(0.11631863091190475), + FRAC_CONST(0.12849811079379317), + FRAC_CONST(0.14065823933284921), + FRAC_CONST(0.15279718525844344), + FRAC_CONST(0.16491312048996989), + FRAC_CONST(0.17700422041214875), + FRAC_CONST(0.18906866414980619), + FRAC_CONST(0.2011046348420919), + FRAC_CONST(0.21311031991609136), + FRAC_CONST(0.22508391135979283), + FRAC_CONST(0.2370236059943672), + FRAC_CONST(0.24892760574572015), + FRAC_CONST(0.26079411791527551), + FRAC_CONST(0.27262135544994898), + FRAC_CONST(0.28440753721127188), + FRAC_CONST(0.29615088824362379), + FRAC_CONST(0.30784964004153487), + FRAC_CONST(0.31950203081601569), + FRAC_CONST(0.33110630575987643), + FRAC_CONST(0.34266071731199438), + FRAC_CONST(0.35416352542049034), + FRAC_CONST(0.36561299780477385), + FRAC_CONST(0.37700741021641826), + FRAC_CONST(0.38834504669882625), + FRAC_CONST(0.39962419984564679), + FRAC_CONST(0.41084317105790391), + FRAC_CONST(0.42200027079979968), + FRAC_CONST(0.43309381885315196), + FRAC_CONST(0.4441221445704292), + FRAC_CONST(0.45508358712634384), + FRAC_CONST(0.46597649576796618), + FRAC_CONST(0.47679923006332209), + FRAC_CONST(0.487550160148436), + FRAC_CONST(0.49822766697278187), + FRAC_CONST(0.50883014254310699), + FRAC_CONST(0.51935599016558964), + FRAC_CONST(0.52980362468629461), + FRAC_CONST(0.54017147272989285), + FRAC_CONST(0.55045797293660481), + FRAC_CONST(0.56066157619733603), + FRAC_CONST(0.57078074588696726), + FRAC_CONST(0.58081395809576453), + FRAC_CONST(0.59075970185887416), + FRAC_CONST(0.60061647938386897), + FRAC_CONST(0.61038280627630948), + FRAC_CONST(0.6200572117632891), + FRAC_CONST(0.62963823891492698), + FRAC_CONST(0.63912444486377573), + FRAC_CONST(0.64851440102211244), + FRAC_CONST(0.65780669329707864), + FRAC_CONST(0.66699992230363747), + FRAC_CONST(0.67609270357531592), + FRAC_CONST(0.68508366777270036), + FRAC_CONST(0.693971460889654), + FRAC_CONST(0.7027547444572253), + FRAC_CONST(0.71143219574521643), + FRAC_CONST(0.72000250796138165), + FRAC_CONST(0.7284643904482252), + FRAC_CONST(0.73681656887736979), + FRAC_CONST(0.74505778544146595), + FRAC_CONST(0.75318679904361241), + FRAC_CONST(0.76120238548426178), + FRAC_CONST(0.76910333764557959), + FRAC_CONST(0.77688846567323244), + FRAC_CONST(0.78455659715557524), + FRAC_CONST(0.79210657730021239), + FRAC_CONST(0.79953726910790501), + FRAC_CONST(0.80684755354379922), + FRAC_CONST(0.8140363297059483), + FRAC_CONST(0.82110251499110465), + FRAC_CONST(0.8280450452577558), + FRAC_CONST(0.83486287498638001), + FRAC_CONST(0.84155497743689833), + FRAC_CONST(0.84812034480329712), + FRAC_CONST(0.85455798836540053), + FRAC_CONST(0.86086693863776731), + FRAC_CONST(0.86704624551569265), + FRAC_CONST(0.87309497841829009), + FRAC_CONST(0.87901222642863341), + FRAC_CONST(0.88479709843093779), + FRAC_CONST(0.89044872324475788), + FRAC_CONST(0.89596624975618511), + FRAC_CONST(0.90134884704602203), + FRAC_CONST(0.90659570451491533), + FRAC_CONST(0.91170603200542988), + FRAC_CONST(0.9166790599210427), + FRAC_CONST(0.9215140393420419), + FRAC_CONST(0.92621024213831127), + FRAC_CONST(0.93076696107898371), + FRAC_CONST(0.9351835099389475), + FRAC_CONST(0.93945922360218992), + FRAC_CONST(0.94359345816196039), + FRAC_CONST(0.94758559101774109), + FRAC_CONST(0.95143502096900834), + FRAC_CONST(0.95514116830577067), + FRAC_CONST(0.9587034748958716), + FRAC_CONST(0.96212140426904158), + FRAC_CONST(0.9653944416976894), + FRAC_CONST(0.96852209427441727), + FRAC_CONST(0.97150389098625178), + FRAC_CONST(0.97433938278557586), + FRAC_CONST(0.97702814265775439), + FRAC_CONST(0.97956976568544052), + FRAC_CONST(0.98196386910955524), + FRAC_CONST(0.98421009238692903), + FRAC_CONST(0.98630809724459867), + FRAC_CONST(0.98825756773074946), + FRAC_CONST(0.99005821026229712), + FRAC_CONST(0.99170975366909953), + FRAC_CONST(0.9932119492347945), + FRAC_CONST(0.99456457073425542), + FRAC_CONST(0.99576741446765982), + FRAC_CONST(0.99682029929116567), + FRAC_CONST(0.99772306664419164), + FRAC_CONST(0.99847558057329477), + FRAC_CONST(0.99907772775264536), + FRAC_CONST(0.99952941750109314), + FRAC_CONST(0.9998305817958234), + FRAC_CONST(0.99998117528260111), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1)}; + + #ifdef ALLOW_SMALL_FRAMELENGTH +static const real_t ld_mid_480[] = {FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0), + FRAC_CONST(0.0065449379673518581), + FRAC_CONST(0.019633692460628301), + FRAC_CONST(0.032719082821776137), + FRAC_CONST(0.045798866936520771), + FRAC_CONST(0.058870803651189033), + FRAC_CONST(0.071932653156719387), + FRAC_CONST(0.084982177372441667), + FRAC_CONST(0.09801714032956059), + FRAC_CONST(0.11103530855427769), + FRAC_CONST(0.12403445145048532), + FRAC_CONST(0.13701234168196802), + FRAC_CONST(0.14996675555404498), + FRAC_CONST(0.16289547339458874), + FRAC_CONST(0.17579627993435451), + FRAC_CONST(0.18866696468655525), + FRAC_CONST(0.2015053223256171), + FRAC_CONST(0.21430915306505074), + FRAC_CONST(0.2270762630343732), + FRAC_CONST(0.23980446465501654), + FRAC_CONST(0.25249157701515795), + FRAC_CONST(0.26513542624340797), + FRAC_CONST(0.27773384588129219), + FRAC_CONST(0.29028467725446233), + FRAC_CONST(0.3027857698425746), + FRAC_CONST(0.31523498164776964), + FRAC_CONST(0.32763017956169349), + FRAC_CONST(0.33996923973099424), + FRAC_CONST(0.35225004792123354), + FRAC_CONST(0.36447049987914965), + FRAC_CONST(0.37662850169321077), + FRAC_CONST(0.38872197015239557), + FRAC_CONST(0.40074883310314097), + FRAC_CONST(0.41270702980439467), + FRAC_CONST(0.42459451128071307), + FRAC_CONST(0.43640924067334208), + FRAC_CONST(0.44814919358922256), + FRAC_CONST(0.45981235844785984), + FRAC_CONST(0.47139673682599764), + FRAC_CONST(0.48290034380003727), + FRAC_CONST(0.49432120828614462), + FRAC_CONST(0.50565737337798455), + FRAC_CONST(0.51690689668202761), + FRAC_CONST(0.52806785065036799), + FRAC_CONST(0.53913832291100017), + FRAC_CONST(0.55011641659549337), + FRAC_CONST(0.56100025066400983), + FRAC_CONST(0.57178796022761225), + FRAC_CONST(0.58247769686780215), + FRAC_CONST(0.59306762895323706), + FRAC_CONST(0.60355594195357143), + FRAC_CONST(0.61394083875036642), + FRAC_CONST(0.62422053994501758), + FRAC_CONST(0.63439328416364549), + FRAC_CONST(0.64445732835889735), + FRAC_CONST(0.65441094810861034), + FRAC_CONST(0.66425243791128175), + FRAC_CONST(0.67398011147829784), + FRAC_CONST(0.68359230202287125), + FRAC_CONST(0.69308736254563585), + FRAC_CONST(0.70246366611685174), + FRAC_CONST(0.71171960615517138), + FRAC_CONST(0.72085359670291882), + FRAC_CONST(0.7298640726978356), + FRAC_CONST(0.73874949024124625), + FRAC_CONST(0.74750832686259672), + FRAC_CONST(0.75613908178032285), + FRAC_CONST(0.76464027615900032), + FRAC_CONST(0.77301045336273699), + FRAC_CONST(0.78124817920475853), + FRAC_CONST(0.78935204219315003), + FRAC_CONST(0.79732065377270711), + FRAC_CONST(0.80515264856285829), + FRAC_CONST(0.81284668459161513), + FRAC_CONST(0.82040144352551359), + FRAC_CONST(0.82781563089550203), + FRAC_CONST(0.83508797631874299), + FRAC_CONST(0.84221723371628654), + FRAC_CONST(0.84920218152657889), + FRAC_CONST(0.85604162291477137), + FRAC_CONST(0.86273438597779184), + FRAC_CONST(0.86927932394514362), + FRAC_CONST(0.87567531537539967), + FRAC_CONST(0.88192126434835494), + FRAC_CONST(0.88801610065280734), + FRAC_CONST(0.89395877996993212), + FRAC_CONST(0.8997482840522214), + FRAC_CONST(0.90538362089795521), + FRAC_CONST(0.91086382492117568), + FRAC_CONST(0.91618795711713596), + FRAC_CONST(0.92135510522319242), + FRAC_CONST(0.9263643838751181), + FRAC_CONST(0.93121493475880346), + FRAC_CONST(0.93590592675732565), + FRAC_CONST(0.94043655609335486), + FRAC_CONST(0.94480604646687805), + FRAC_CONST(0.94901364918821385), + FRAC_CONST(0.95305864330629697), + FRAC_CONST(0.95694033573220882), + FRAC_CONST(0.9606580613579353), + FRAC_CONST(0.96421118317032928), + FRAC_CONST(0.96759909236025976), + FRAC_CONST(0.9708212084269281), + FRAC_CONST(0.97387697927733363), + FRAC_CONST(0.97676588132087239), + FRAC_CONST(0.97948741955905139), + FRAC_CONST(0.98204112767030394), + FRAC_CONST(0.98442656808989171), + FRAC_CONST(0.98664333208487898), + FRAC_CONST(0.98869103982416728), + FRAC_CONST(0.99056934044357725), + FRAC_CONST(0.99227791210596705), + FRAC_CONST(0.99381646205637808), + FRAC_CONST(0.99518472667219682), + FRAC_CONST(0.99638247150832537), + FRAC_CONST(0.99740949133735191), + FRAC_CONST(0.99826561018471593), + FRAC_CONST(0.99895068135886012), + FRAC_CONST(0.99946458747636568), + FRAC_CONST(0.99980724048206482), + FRAC_CONST(0.99997858166412923), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1), + FRAC_CONST(1)}; + #endif +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +static real_t pow05_table[] = { + COEF_CONST(1.68179283050743), /* 0.5^(-3/4) */ + COEF_CONST(1.41421356237310), /* 0.5^(-2/4) */ + COEF_CONST(1.18920711500272), /* 0.5^(-1/4) */ + COEF_CONST(1.0), /* 0.5^( 0/4) */ + COEF_CONST(0.84089641525371), /* 0.5^(+1/4) */ + COEF_CONST(0.70710678118655), /* 0.5^(+2/4) */ + COEF_CONST(0.59460355750136) /* 0.5^(+3/4) */ +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +static const real_t mnt_table[128] = { + COEF_CONST(0.9531250000), COEF_CONST(0.9453125000), COEF_CONST(0.9375000000), COEF_CONST(0.9296875000), COEF_CONST(0.9257812500), COEF_CONST(0.9179687500), COEF_CONST(0.9101562500), + COEF_CONST(0.9023437500), COEF_CONST(0.8984375000), COEF_CONST(0.8906250000), COEF_CONST(0.8828125000), COEF_CONST(0.8789062500), COEF_CONST(0.8710937500), COEF_CONST(0.8671875000), + COEF_CONST(0.8593750000), COEF_CONST(0.8515625000), COEF_CONST(0.8476562500), COEF_CONST(0.8398437500), COEF_CONST(0.8359375000), COEF_CONST(0.8281250000), COEF_CONST(0.8242187500), + COEF_CONST(0.8203125000), COEF_CONST(0.8125000000), COEF_CONST(0.8085937500), COEF_CONST(0.8007812500), COEF_CONST(0.7968750000), COEF_CONST(0.7929687500), COEF_CONST(0.7851562500), + COEF_CONST(0.7812500000), COEF_CONST(0.7773437500), COEF_CONST(0.7734375000), COEF_CONST(0.7656250000), COEF_CONST(0.7617187500), COEF_CONST(0.7578125000), COEF_CONST(0.7539062500), + COEF_CONST(0.7500000000), COEF_CONST(0.7421875000), COEF_CONST(0.7382812500), COEF_CONST(0.7343750000), COEF_CONST(0.7304687500), COEF_CONST(0.7265625000), COEF_CONST(0.7226562500), + COEF_CONST(0.7187500000), COEF_CONST(0.7148437500), COEF_CONST(0.7109375000), COEF_CONST(0.7070312500), COEF_CONST(0.6992187500), COEF_CONST(0.6953125000), COEF_CONST(0.6914062500), + COEF_CONST(0.6875000000), COEF_CONST(0.6835937500), COEF_CONST(0.6796875000), COEF_CONST(0.6796875000), COEF_CONST(0.6757812500), COEF_CONST(0.6718750000), COEF_CONST(0.6679687500), + COEF_CONST(0.6640625000), COEF_CONST(0.6601562500), COEF_CONST(0.6562500000), COEF_CONST(0.6523437500), COEF_CONST(0.6484375000), COEF_CONST(0.6445312500), COEF_CONST(0.6406250000), + COEF_CONST(0.6406250000), COEF_CONST(0.6367187500), COEF_CONST(0.6328125000), COEF_CONST(0.6289062500), COEF_CONST(0.6250000000), COEF_CONST(0.6210937500), COEF_CONST(0.6210937500), + COEF_CONST(0.6171875000), COEF_CONST(0.6132812500), COEF_CONST(0.6093750000), COEF_CONST(0.6054687500), COEF_CONST(0.6054687500), COEF_CONST(0.6015625000), COEF_CONST(0.5976562500), + COEF_CONST(0.5937500000), COEF_CONST(0.5937500000), COEF_CONST(0.5898437500), COEF_CONST(0.5859375000), COEF_CONST(0.5820312500), COEF_CONST(0.5820312500), COEF_CONST(0.5781250000), + COEF_CONST(0.5742187500), COEF_CONST(0.5742187500), COEF_CONST(0.5703125000), COEF_CONST(0.5664062500), COEF_CONST(0.5664062500), COEF_CONST(0.5625000000), COEF_CONST(0.5585937500), + COEF_CONST(0.5585937500), COEF_CONST(0.5546875000), COEF_CONST(0.5507812500), COEF_CONST(0.5507812500), COEF_CONST(0.5468750000), COEF_CONST(0.5429687500), COEF_CONST(0.5429687500), + COEF_CONST(0.5390625000), COEF_CONST(0.5390625000), COEF_CONST(0.5351562500), COEF_CONST(0.5312500000), COEF_CONST(0.5312500000), COEF_CONST(0.5273437500), COEF_CONST(0.5273437500), + COEF_CONST(0.5234375000), COEF_CONST(0.5195312500), COEF_CONST(0.5195312500), COEF_CONST(0.5156250000), COEF_CONST(0.5156250000), COEF_CONST(0.5117187500), COEF_CONST(0.5117187500), + COEF_CONST(0.5078125000), COEF_CONST(0.5078125000), COEF_CONST(0.5039062500), COEF_CONST(0.5039062500), COEF_CONST(0.5000000000), COEF_CONST(0.4980468750), COEF_CONST(0.4960937500), + COEF_CONST(0.4941406250), COEF_CONST(0.4921875000), COEF_CONST(0.4902343750), COEF_CONST(0.4882812500), COEF_CONST(0.4863281250), COEF_CONST(0.4843750000), COEF_CONST(0.4824218750), + COEF_CONST(0.4804687500), COEF_CONST(0.4785156250)}; +static const real_t exp_table[128] = {COEF_CONST(0.50000000000000000000000000000000000000000000000000), + COEF_CONST(0.25000000000000000000000000000000000000000000000000), + COEF_CONST(0.12500000000000000000000000000000000000000000000000), + COEF_CONST(0.06250000000000000000000000000000000000000000000000), + COEF_CONST(0.03125000000000000000000000000000000000000000000000), + COEF_CONST(0.01562500000000000000000000000000000000000000000000), + COEF_CONST(0.00781250000000000000000000000000000000000000000000), + COEF_CONST(0.00390625000000000000000000000000000000000000000000), + COEF_CONST(0.00195312500000000000000000000000000000000000000000), + COEF_CONST(0.00097656250000000000000000000000000000000000000000), + COEF_CONST(0.00048828125000000000000000000000000000000000000000), + COEF_CONST(0.00024414062500000000000000000000000000000000000000), + COEF_CONST(0.00012207031250000000000000000000000000000000000000), + COEF_CONST(0.00006103515625000000000000000000000000000000000000), + COEF_CONST(0.00003051757812500000000000000000000000000000000000), + COEF_CONST(0.00001525878906250000000000000000000000000000000000), + COEF_CONST(0.00000762939453125000000000000000000000000000000000), + COEF_CONST(0.00000381469726562500000000000000000000000000000000), + COEF_CONST(0.00000190734863281250000000000000000000000000000000), + COEF_CONST(0.00000095367431640625000000000000000000000000000000), + COEF_CONST(0.00000047683715820312500000000000000000000000000000), + COEF_CONST(0.00000023841857910156250000000000000000000000000000), + COEF_CONST(0.00000011920928955078125000000000000000000000000000), + COEF_CONST(0.00000005960464477539062500000000000000000000000000), + COEF_CONST(0.00000002980232238769531300000000000000000000000000), + COEF_CONST(0.00000001490116119384765600000000000000000000000000), + COEF_CONST(0.00000000745058059692382810000000000000000000000000), + COEF_CONST(0.00000000372529029846191410000000000000000000000000), + COEF_CONST(0.00000000186264514923095700000000000000000000000000), + COEF_CONST(0.00000000093132257461547852000000000000000000000000), + COEF_CONST(0.00000000046566128730773926000000000000000000000000), + COEF_CONST(0.00000000023283064365386963000000000000000000000000), + COEF_CONST(0.00000000011641532182693481000000000000000000000000), + COEF_CONST(0.00000000005820766091346740700000000000000000000000), + COEF_CONST(0.00000000002910383045673370400000000000000000000000), + COEF_CONST(0.00000000001455191522836685200000000000000000000000), + COEF_CONST(0.00000000000727595761418342590000000000000000000000), + COEF_CONST(0.00000000000363797880709171300000000000000000000000), + COEF_CONST(0.00000000000181898940354585650000000000000000000000), + COEF_CONST(0.00000000000090949470177292824000000000000000000000), + COEF_CONST(0.00000000000045474735088646412000000000000000000000), + COEF_CONST(0.00000000000022737367544323206000000000000000000000), + COEF_CONST(0.00000000000011368683772161603000000000000000000000), + COEF_CONST(0.00000000000005684341886080801500000000000000000000), + COEF_CONST(0.00000000000002842170943040400700000000000000000000), + COEF_CONST(0.00000000000001421085471520200400000000000000000000), + COEF_CONST(0.00000000000000710542735760100190000000000000000000), + COEF_CONST(0.00000000000000355271367880050090000000000000000000), + COEF_CONST(0.00000000000000177635683940025050000000000000000000), + COEF_CONST(0.00000000000000088817841970012523000000000000000000), + COEF_CONST(0.00000000000000044408920985006262000000000000000000), + COEF_CONST(0.00000000000000022204460492503131000000000000000000), + COEF_CONST(0.00000000000000011102230246251565000000000000000000), + COEF_CONST(0.00000000000000005551115123125782700000000000000000), + COEF_CONST(0.00000000000000002775557561562891400000000000000000), + COEF_CONST(0.00000000000000001387778780781445700000000000000000), + COEF_CONST(0.00000000000000000693889390390722840000000000000000), + COEF_CONST(0.00000000000000000346944695195361420000000000000000), + COEF_CONST(0.00000000000000000173472347597680710000000000000000), + COEF_CONST(0.00000000000000000086736173798840355000000000000000), + COEF_CONST(0.00000000000000000043368086899420177000000000000000), + COEF_CONST(0.00000000000000000021684043449710089000000000000000), + COEF_CONST(0.00000000000000000010842021724855044000000000000000), + COEF_CONST(0.00000000000000000005421010862427522200000000000000), + COEF_CONST(0.00000000000000000002710505431213761100000000000000), + COEF_CONST(0.00000000000000000001355252715606880500000000000000), + COEF_CONST(0.00000000000000000000677626357803440270000000000000), + COEF_CONST(0.00000000000000000000338813178901720140000000000000), + COEF_CONST(0.00000000000000000000169406589450860070000000000000), + COEF_CONST(0.00000000000000000000084703294725430034000000000000), + COEF_CONST(0.00000000000000000000042351647362715017000000000000), + COEF_CONST(0.00000000000000000000021175823681357508000000000000), + COEF_CONST(0.00000000000000000000010587911840678754000000000000), + COEF_CONST(0.00000000000000000000005293955920339377100000000000), + COEF_CONST(0.00000000000000000000002646977960169688600000000000), + COEF_CONST(0.00000000000000000000001323488980084844300000000000), + COEF_CONST(0.00000000000000000000000661744490042422140000000000), + COEF_CONST(0.00000000000000000000000330872245021211070000000000), + COEF_CONST(0.00000000000000000000000165436122510605530000000000), + COEF_CONST(0.00000000000000000000000082718061255302767000000000), + COEF_CONST(0.00000000000000000000000041359030627651384000000000), + COEF_CONST(0.00000000000000000000000020679515313825692000000000), + COEF_CONST(0.00000000000000000000000010339757656912846000000000), + COEF_CONST(0.00000000000000000000000005169878828456423000000000), + COEF_CONST(0.00000000000000000000000002584939414228211500000000), + COEF_CONST(0.00000000000000000000000001292469707114105700000000), + COEF_CONST(0.00000000000000000000000000646234853557052870000000), + COEF_CONST(0.00000000000000000000000000323117426778526440000000), + COEF_CONST(0.00000000000000000000000000161558713389263220000000), + COEF_CONST(0.00000000000000000000000000080779356694631609000000), + COEF_CONST(0.00000000000000000000000000040389678347315804000000), + COEF_CONST(0.00000000000000000000000000020194839173657902000000), + COEF_CONST(0.00000000000000000000000000010097419586828951000000), + COEF_CONST(0.00000000000000000000000000005048709793414475600000), + COEF_CONST(0.00000000000000000000000000002524354896707237800000), + COEF_CONST(0.00000000000000000000000000001262177448353618900000), + COEF_CONST(0.00000000000000000000000000000631088724176809440000), + COEF_CONST(0.00000000000000000000000000000315544362088404720000), + COEF_CONST(0.00000000000000000000000000000157772181044202360000), + COEF_CONST(0.00000000000000000000000000000078886090522101181000), + COEF_CONST(0.00000000000000000000000000000039443045261050590000), + COEF_CONST(0.00000000000000000000000000000019721522630525295000), + COEF_CONST(0.00000000000000000000000000000009860761315262647600), + COEF_CONST(0.00000000000000000000000000000004930380657631323800), + COEF_CONST(0.00000000000000000000000000000002465190328815661900), + COEF_CONST(0.00000000000000000000000000000001232595164407830900), + COEF_CONST(0.00000000000000000000000000000000616297582203915470), + COEF_CONST(0.00000000000000000000000000000000308148791101957740), + COEF_CONST(0.00000000000000000000000000000000154074395550978870), + COEF_CONST(0.00000000000000000000000000000000077037197775489434), + COEF_CONST(0.00000000000000000000000000000000038518598887744717), + COEF_CONST(0.00000000000000000000000000000000019259299443872359), + COEF_CONST(0.00000000000000000000000000000000009629649721936179), + COEF_CONST(0.00000000000000000000000000000000004814824860968090), + COEF_CONST(0.00000000000000000000000000000000002407412430484045), + COEF_CONST(0.00000000000000000000000000000000001203706215242022), + COEF_CONST(0.00000000000000000000000000000000000601853107621011), + COEF_CONST(0.00000000000000000000000000000000000300926553810506), + COEF_CONST(0.00000000000000000000000000000000000150463276905253), + COEF_CONST(0.00000000000000000000000000000000000075231638452626), + COEF_CONST(0.00000000000000000000000000000000000037615819226313), + COEF_CONST(0.00000000000000000000000000000000000018807909613157), + COEF_CONST(0.00000000000000000000000000000000000009403954806578), + COEF_CONST(0.00000000000000000000000000000000000004701977403289), + COEF_CONST(0.00000000000000000000000000000000000002350988701645), + COEF_CONST(0.00000000000000000000000000000000000001175494350822), + COEF_CONST(0.0 /* 0000000000000000000000000000000000000587747175411 "floating point underflow" */), + COEF_CONST(0.0)}; +#endif /* MAIN_DEC */ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +static const real_t pow2sf_tab[] = {2.9802322387695313E-008, + 5.9604644775390625E-008, + 1.1920928955078125E-007, + 2.384185791015625E-007, + 4.76837158203125E-007, + 9.5367431640625E-007, + 1.9073486328125E-006, + 3.814697265625E-006, + 7.62939453125E-006, + 1.52587890625E-005, + 3.0517578125E-005, + 6.103515625E-005, + 0.0001220703125, + 0.000244140625, + 0.00048828125, + 0.0009765625, + 0.001953125, + 0.00390625, + 0.0078125, + 0.015625, + 0.03125, + 0.0625, + 0.125, + 0.25, + 0.5, + 1.0, + 2.0, + 4.0, + 8.0, + 16.0, + 32.0, + 64.0, + 128.0, + 256.0, + 512.0, + 1024.0, + 2048.0, + 4096.0, + 8192.0, + 16384.0, + 32768.0, + 65536.0, + 131072.0, + 262144.0, + 524288.0, + 1048576.0, + 2097152.0, + 4194304.0, + 8388608.0, + 16777216.0, + 33554432.0, + 67108864.0, + 134217728.0, + 268435456.0, + 536870912.0, + 1073741824.0, + 2147483648.0, + 4294967296.0, + 8589934592.0, + 17179869184.0, + 34359738368.0, + 68719476736.0, + 137438953472.0, + 274877906944.0}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LD_DEC +static const uint8_t num_swb_512_window[] = {0, 0, 0, 36, 36, 37, 31, 31, 0, 0, 0, 0}; +static const uint8_t num_swb_480_window[] = {0, 0, 0, 35, 35, 37, 30, 30, 0, 0, 0, 0}; +#endif +static const uint8_t num_swb_960_window[] = {40, 40, 45, 49, 49, 49, 46, 46, 42, 42, 42, 40}; +static const uint8_t num_swb_1024_window[] = {41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40}; +static const uint8_t num_swb_128_window[] = {12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15}; +static const uint16_t swb_offset_1024_96[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 108, + 120, 132, 144, 156, 172, 188, 212, 240, 276, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024}; +static const uint16_t swb_offset_128_96[] = {0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128}; +static const uint16_t swb_offset_1024_64[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 100, 112, 124, 140, 156, + 172, 192, 216, 240, 268, 304, 344, 384, 424, 464, 504, 544, 584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024}; +static const uint16_t swb_offset_128_64[] = {0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128}; +static const uint16_t swb_offset_1024_48[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, + 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 1024}; +#ifdef LD_DEC +static const uint16_t swb_offset_512_48[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 68, 76, 84, + 92, 100, 112, 124, 136, 148, 164, 184, 208, 236, 268, 300, 332, 364, 396, 428, 460, 512}; +static const uint16_t swb_offset_480_48[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, + 88, 96, 108, 120, 132, 144, 156, 172, 188, 212, 240, 272, 304, 336, 368, 400, 432, 480}; +#endif +static const uint16_t swb_offset_128_48[] = {0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 128}; +static const uint16_t swb_offset_1024_32[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, + 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 960, 992, 1024}; +#ifdef LD_DEC +static const uint16_t swb_offset_512_32[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, + 96, 108, 120, 132, 144, 160, 176, 192, 212, 236, 260, 288, 320, 352, 384, 416, 448, 480, 512}; +static const uint16_t swb_offset_480_32[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, + 88, 96, 104, 112, 124, 136, 148, 164, 180, 200, 224, 256, 288, 320, 352, 384, 416, 448, 480}; +#endif +static const uint16_t swb_offset_1024_24[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 136, 148, + 160, 172, 188, 204, 220, 240, 260, 284, 308, 336, 364, 396, 432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024}; +#ifdef LD_DEC +static const uint16_t swb_offset_512_24[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480, 512}; +static const uint16_t swb_offset_480_24[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480}; +#endif +static const uint16_t swb_offset_128_24[] = {0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 128}; +static const uint16_t swb_offset_1024_16[] = {0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 212, + 228, 244, 260, 280, 300, 320, 344, 368, 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, 832, 896, 960, 1024}; +static const uint16_t swb_offset_128_16[] = {0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 128}; +static const uint16_t swb_offset_1024_8[] = {0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 172, 188, 204, 220, 236, 252, 268, + 288, 308, 328, 348, 372, 396, 420, 448, 476, 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, 1024}; +static const uint16_t swb_offset_128_8[] = {0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 128}; +static const uint16_t* swb_offset_1024_window[] = { + swb_offset_1024_96, /* 96000 */ + swb_offset_1024_96, /* 88200 */ + swb_offset_1024_64, /* 64000 */ + swb_offset_1024_48, /* 48000 */ + swb_offset_1024_48, /* 44100 */ + swb_offset_1024_32, /* 32000 */ + swb_offset_1024_24, /* 24000 */ + swb_offset_1024_24, /* 22050 */ + swb_offset_1024_16, /* 16000 */ + swb_offset_1024_16, /* 12000 */ + swb_offset_1024_16, /* 11025 */ + swb_offset_1024_8 /* 8000 */ +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +static const real_t iq_table[IQ_TABLE_SIZE] = {0, + 1, + 2.5198420997897464, + 4.3267487109222245, + 6.3496042078727974, + 8.5498797333834844, + 10.902723556992836, + 13.390518279406722, + 15.999999999999998, + 18.720754407467133, + 21.544346900318832, + 24.463780996262464, + 27.47314182127996, + 30.567350940369842, + 33.741991698453212, + 36.993181114957046, + 40.317473596635935, + 43.711787041189993, + 47.173345095760126, + 50.699631325716943, + 54.288352331898118, + 57.937407704003519, + 61.6448652744185, + 65.408940536585988, + 69.227979374755591, + 73.100443455321638, + 77.024897778591622, + 80.999999999999986, + 85.024491212518527, + 89.097187944889555, + 93.216975178615741, + 97.382800224133163, + 101.59366732596474, + 105.84863288986224, + 110.14680124343441, + 114.4873208566006, + 118.86938096020653, + 123.29220851090024, + 127.75506545836058, + 132.25724627755247, + 136.79807573413572, + 141.37690685569191, + 145.99311908523086, + 150.6461165966291, + 155.33532675434674, + 160.06019870205279, + 164.82020206673349, + 169.61482576651861, + 174.44357691188537, + 179.30597979112557, + 184.20157493201927, + 189.12991823257562, + 194.09058015449685, + 199.08314497371677, + 204.1072100829694, + 209.16238534187647, + 214.24829247050752, + 219.36456448277784, + 224.51084515641216, + 229.6867885365223, + 234.89205847013176, + 240.12632816923249, + 245.38927980018505, + 250.68060409747261, + 255.99999999999991, + 261.34717430828869, + 266.72184136106449, + 272.12372272986045, + 277.55254693037961, + 283.0080491494619, + 288.48997098659891, + 293.99806020902247, + 299.53207051947408, + 305.0917613358298, + 310.67689758182206, + 316.28724948815585, + 321.92259240337177, + 327.58270661385535, + 333.26737717243742, + 338.97639373507025, + 344.70955040510125, + 350.46664558470013, + 356.24748183302603, + 362.05186573075139, + 367.87960775058258, + 373.73052213344511, + 379.60442677002078, + 385.50114308734607, + 391.42049594019937, + 397.36231350702371, + 403.32642719014467, + 409.31267152006262, + 415.32088406360799, + 421.35090533576471, + 427.40257871497619, + 433.4757503617617, + 439.5702691404793, + 445.68598654408271, + 451.82275662172759, + 457.98043590909128, + 464.15888336127773, + 470.35796028818726, + 476.5775302922363, + 482.81745920832043, + 489.07761504591741, + 495.35786793323581, + 501.65809006331688, + 507.97815564200368, + 514.31794083769648, + 520.67732373281672, + 527.05618427690604, + 533.45440424129174, + 539.87186717525128, + 546.30845836361505, + 552.76406478574609, + 559.23857507584194, + 565.73187948450413, + 572.24386984152341, + 578.77443951983378, + 585.32348340058843, + 591.89089783931263, + 598.47658063309257, + 605.08043098876044, + 611.70234949203643, + 618.3422380775919, + 624.99999999999977, + 631.67553980553748, + 638.36876330481164, + 645.07957754617485, + 651.80789078990415, + 658.55361248311499, + 665.31665323538357, + 672.09692479505225, + 678.8943400261943, + 685.70881288621433, + 692.540258404062, + 699.38859265903977, + 706.25373276018058, + 713.13559682617972, + 720.03410396586037, + 726.94917425915435, + 733.88072873858209, + 740.82868937121543, + 747.79297904110535, + 754.77352153216191, + 761.77024151147043, + 768.78306451302956, + 775.81191692189896, + 782.85672595874246, + 789.91741966475445, + 796.99392688695798, + 804.08617726386274, + 811.19410121147098, + 818.31762990962227, + 825.45669528866563, + 832.61123001644864, + 839.78116748561604, + 846.96644180120552, + 854.16698776853514, + 861.38274088137143, + 868.61363731036977, + 875.85961389178203, + 883.12060811641959, + 890.39655811886757, + 897.68740266694181, + 904.99308115138172, + 912.31353357577188, + 919.64870054668756, + 926.99852326405619, + 934.36294351172899, + 941.74190364825859, + 949.13534659787422, + 956.54321584165211, + 963.96545540887348, + 971.40200986856541, + 978.85282432122176, + 986.31784439069588, + 993.7970162162635, + 1001.29028644485, + 1008.797602223418, + 1016.3189111915103, + 1023.8541614739464, + 1031.4033016736653, + 1038.9662808647138, + 1046.5430485853758, + 1054.1335548314366, + 1061.7377500495838, + 1069.3555851309357, + 1076.9870114046978, + 1084.6319806319441, + 1092.2904449995174, + 1099.9623571140482, + 1107.6476699960892, + 1115.3463370743607, + 1123.058312180106, + 1130.7835495415541, + 1138.5220037784854, + 1146.273629896901, + 1154.0383832837879, + 1161.816219701986, + 1169.607095285146, + 1177.4109665327808, + 1185.2277903054078, + 1193.0575238197798, + 1200.9001246442001, + 1208.7555506939248, + 1216.6237602266442, + 1224.5047118380478, + 1232.3983644574657, + 1240.3046773435874, + 1248.2236100802568, + 1256.1551225723395, + 1264.099175041662, + 1272.0557280230228, + 1280.0247423602691, + 1288.0061792024444, + 1295.9999999999995, + 1304.006166501068, + 1312.0246407478062, + 1320.0553850727929, + 1328.0983620954903, + 1336.1535347187651, + 1344.2208661254647, + 1352.3003197750522, + 1360.3918594002962, + 1368.4954490040145, + 1376.6110528558709, + 1384.7386354892244, + 1392.8781616980295, + 1401.0295965337855, + 1409.1929053025353, + 1417.3680535619119, + 1425.5550071182327, + 1433.7537320236374, + 1441.9641945732744, + 1450.1863613025282, + 1458.4201989842913, + 1466.6656746262797, + 1474.9227554683875, + 1483.1914089800841, + 1491.4716028578516, + 1499.7633050226596, + 1508.0664836174794, + 1516.3811070048375, + 1524.7071437644029, + 1533.0445626906128, + 1541.3933327903342, + 1549.7534232805581, + 1558.1248035861302, + 1566.507443337515, + 1574.9013123685909, + 1583.3063807144795, + 1591.7226186094069, + 1600.1499964845941, + 1608.58848496618, + 1617.0380548731737, + 1625.4986772154357, + 1633.9703231916887, + 1642.4529641875577, + 1650.9465717736346, + 1659.4511177035752, + 1667.9665739122186, + 1676.4929125137353, + 1685.030105799801, + 1693.5781262377957, + 1702.136946469027, + 1710.7065393069795, + 1719.2868777355877, + 1727.8779349075323, + 1736.4796841425596, + 1745.092098925825, + 1753.7151529062583, + 1762.3488198949503, + 1770.9930738635628, + 1779.6478889427597, + 1788.3132394206564, + 1796.9890997412947, + 1805.6754445031333, + 1814.3722484575621, + 1823.0794865074322, + 1831.7971337056094, + 1840.5251652535437, + 1849.2635564998579, + 1858.0122829389563, + 1866.7713202096493, + 1875.5406440937966, + 1884.3202305149687, + 1893.110055537124, + 1901.9100953633042, + 1910.7203263343454, + 1919.5407249276057, + 1928.3712677557098, + 1937.2119315653083, + 1946.0626932358525, + 1954.923529778386, + 1963.79441833435, + 1972.6753361744036, + 1981.5662606972594, + 1990.467169428533, + 1999.3780400196069, + 2008.2988502465078, + 2017.2295780087982, + 2026.1702013284819, + 2035.1206983489212, + 2044.0810473337688, + 2053.0512266659125, + 2062.0312148464309, + 2071.0209904935646, + 2080.0205323416958, + 2089.0298192403443, + 2098.0488301531714, + 2107.0775441569995, + 2116.115940440839, + 2125.1639983049317, + 2134.2216971597995, + 2143.2890165253098, + 2152.3659360297484, + 2161.4524354089031, + 2170.5484945051617, + 2179.6540932666144, + 2188.7692117461711, + 2197.8938301006888, + 2207.0279285901042, + 2216.1714875765838, + 2225.324487523676, + 2234.4869089954782, + 2243.6587326558101, + 2252.8399392673982, + 2262.0305096910702, + 2271.2304248849537, + 2280.4396659036897, + 2289.6582138976523, + 2298.8860501121762, + 2308.1231558867926, + 2317.3695126544767, + 2326.6251019409005, + 2335.8899053636933, + 2345.1639046317132, + 2354.4470815443233, + 2363.7394179906792, + 2373.0408959490205, + 2382.3514974859731, + 2391.6712047558558, + 2400.9999999999991, + 2410.3378655460651, + 2419.6847838073813, + 2429.0407372822747, + 2438.4057085534191, + 2447.7796802871858, + 2457.1626352330004, + 2466.5545562227112, + 2475.9554261699564, + 2485.3652280695474, + 2494.7839449968492, + 2504.2115601071737, + 2513.6480566351788, + 2523.0934178942675, + 2532.5476272760025, + 2542.0106682495189, + 2551.482524360948, + 2560.9631792328441, + 2570.4526165636184, + 2579.9508201269791, + 2589.4577737713744, + 2598.9734614194458, + 2608.4978670674823, + 2618.0309747848837, + 2627.5727687136259, + 2637.1232330677353, + 2646.6823521327647, + 2656.2501102652768, + 2665.8264918923328, + 2675.4114815109842, + 2685.0050636877722, + 2694.6072230582295, + 2704.2179443263894, + 2713.8372122642972, + 2723.4650117115279, + 2733.1013275747096, + 2742.7461448270483, + 2752.3994485078601, + 2762.0612237221085, + 2771.7314556399419, + 2781.4101294962406, + 2791.0972305901655, + 2800.7927442847094, + 2810.4966560062589, + 2820.2089512441521, + 2829.9296155502466, + 2839.6586345384894, + 2849.3959938844923, + 2859.1416793251065, + 2868.8956766580086, + 2878.6579717412847, + 2888.4285504930212, + 2898.2073988908974, + 2907.9945029717837, + 2917.789848831344, + 2927.5934226236377, + 2937.4052105607311, + 2947.2251989123079, + 2957.0533740052865, + 2966.8897222234368, + 2976.734230007005, + 2986.5868838523397, + 2996.4476703115197, + 3006.3165759919889, + 3016.1935875561908, + 3026.0786917212095, + 3035.9718752584108, + 3045.8731249930906, + 3055.7824278041207, + 3065.6997706236039, + 3075.625140436528, + 3085.5585242804245, + 3095.4999092450298, + 3105.4492824719491, + 3115.4066311543256, + 3125.3719425365089, + 3135.3452039137287, + 3145.3264026317715, + 3155.3155260866592, + 3165.3125617243295, + 3175.3174970403229, + 3185.3303195794679, + 3195.35101693557, + 3205.3795767511078, + 3215.4159867169251, + 3225.460234571929, + 3235.5123081027928, + 3245.5721951436558, + 3255.63988357583, + 3265.7153613275095, + 3275.7986163734795, + 3285.8896367348289, + 3295.9884104786665, + 3306.0949257178395, + 3316.2091706106517, + 3326.331133360588, + 3336.4608022160378, + 3346.5981654700231, + 3356.7432114599264, + 3366.8959285672249, + 3377.0563052172211, + 3387.2243298787821, + 3397.3999910640764, + 3407.5832773283128, + 3417.7741772694862, + 3427.9726795281199, + 3438.1787727870123, + 3448.3924457709873, + 3458.6136872466445, + 3468.8424860221107, + 3479.0788309467976, + 3489.3227109111554, + 3499.5741148464344, + 3509.8330317244445, + 3520.0994505573185, + 3530.3733603972751, + 3540.6547503363886, + 3550.9436095063534, + 3561.239927078258, + 3571.5436922623535, + 3581.8548943078308, + 3592.1735225025936, + 3602.4995661730372, + 3612.8330146838275, + 3623.1738574376814, + 3633.5220838751502, + 3643.8776834744031, + 3654.2406457510142, + 3664.6109602577494, + 3674.9886165843564, + 3685.3736043573545, + 3695.7659132398294, + 3706.1655329312248, + 3716.5724531671399, + 3726.9866637191262, + 3737.4081543944876, + 3747.8369150360782, + 3758.2729355221072, + 3768.7162057659411, + 3779.1667157159077, + 3789.6244553551055, + 3800.0894147012082, + 3810.5615838062768, + 3821.0409527565694, + 3831.5275116723533, + 3842.0212507077194, + 3852.522160050396, + 3863.0302299215673, + 3873.5454505756893, + 3884.0678123003108, + 3894.5973054158922, + 3905.1339202756285, + 3915.6776472652732, + 3926.2284768029604, + 3936.7863993390338, + 3947.3514053558706, + 3957.9234853677135, + 3968.5026299204969, + 3979.0888295916798, + 3989.6820749900776, + 4000.2823567556948, + 4010.8896655595613, + 4021.5039921035655, + 4032.1253271202945, + 4042.7536613728694, + 4053.3889856547858, + 4064.0312907897551, + 4074.6805676315448, + 4085.3368070638221, + 4095.9999999999982, + 4106.6701373830711, + 4117.347210185475, + 4128.0312094089259, + 4138.722126084268, + 4149.4199512713267, + 4160.1246760587583, + 4170.8362915638982, + 4181.5547889326181, + 4192.2801593391769, + 4203.0123939860741, + 4213.7514841039101, + 4224.4974209512384, + 4235.2501958144258, + 4246.0098000075095, + 4256.7762248720574, + 4267.549461777031, + 4278.3295021186423, + 4289.1163373202198, + 4299.9099588320714, + 4310.7103581313495, + 4321.5175267219138, + 4332.3314561342004, + 4343.152137925088, + 4353.9795636777671, + 4364.8137250016052, + 4375.6546135320223, + 4386.5022209303588, + 4397.3565388837469, + 4408.2175591049827, + 4419.0852733324018, + 4429.9596733297531, + 4440.8407508860728, + 4451.7284978155603, + 4462.6229059574571, + 4473.5239671759227, + 4484.4316733599126, + 4495.3460164230582, + 4506.2669883035496, + 4517.1945809640119, + 4528.1287863913894, + 4539.069596596828, + 4550.0170036155587, + 4560.9709995067806, + 4571.931576353546, + 4582.898726262647, + 4593.8724413645004, + 4604.8527138130348, + 4615.8395357855816, + 4626.8328994827571, + 4637.8327971283588, + 4648.8392209692511, + 4659.8521632752563, + 4670.8716163390473, + 4681.8975724760394, + 4692.9300240242837, + 4703.9689633443595, + 4715.0143828192668, + 4726.0662748543255, + 4737.1246318770682, + 4748.1894463371373, + 4759.2607107061804, + 4770.3384174777493, + 4781.4225591671993, + 4792.5131283115852, + 4803.6101174695614, + 4814.7135192212854, + 4825.8233261683154, + 4836.9395309335096, + 4848.0621261609349, + 4859.1911045157631, + 4870.3264586841779, + 4881.4681813732768, + 4892.6162653109768, + 4903.7707032459193, + 4914.931487947375, + 4926.0986122051509, + 4937.2720688294967, + 4948.4518506510112, + 4959.637950520555, + 4970.8303613091521, + 4982.0290759079044, + 4993.2340872278974, + 5004.4453882001153, + 5015.6629717753467, + 5026.8868309241007, + 5038.1169586365131, + 5049.353347922266, + 5060.5959918104927, + 5071.8448833496996, + 5083.1000156076734, + 5094.3613816713996, + 5105.6289746469747, + 5116.9027876595246, + 5128.18281385312, + 5139.4690463906918, + 5150.7614784539473, + 5162.0601032432933, + 5173.3649139777472, + 5184.6759038948594, + 5195.9930662506322, + 5207.3163943194386, + 5218.6458813939435, + 5229.9815207850224, + 5241.3233058216847, + 5252.6712298509919, + 5264.025286237983, + 5275.3854683655954, + 5286.7517696345885, + 5298.1241834634639, + 5309.5027032883945, + 5320.887322563146, + 5332.2780347589978, + 5343.6748333646756, + 5355.0777118862716, + 5366.4866638471722, + 5377.901682787985, + 5389.3227622664635, + 5400.749895857437, + 5412.1830771527357, + 5423.622299761123, + 5435.067557308219, + 5446.5188434364318, + 5457.9761518048872, + 5469.4394760893592, + 5480.9088099821975, + 5492.3841471922606, + 5503.8654814448455, + 5515.3528064816201, + 5526.846116060552, + 5538.3454039558474, + 5549.8506639578736, + 5561.3618898731029, + 5572.8790755240361, + 5584.4022147491451, + 5595.9313014027975, + 5607.4663293552012, + 5619.0072924923297, + 5630.5541847158656, + 5642.1069999431284, + 5653.665732107017, + 5665.230375155943, + 5676.8009230537655, + 5688.3773697797333, + 5699.9597093284156, + 5711.5479357096474, + 5723.1420429484588, + 5734.7420250850209, + 5746.347876174581, + 5757.9595902874016, + 5769.5771615087006, + 5781.2005839385911, + 5792.8298516920213, + 5804.4649588987149, + 5816.1058997031105, + 5827.7526682643065, + 5839.4052587559972, + 5851.0636653664196, + 5862.7278822982908, + 5874.3979037687541, + 5886.0737240093204, + 5897.7553372658094, + 5909.4427377982956, + 5921.1359198810505, + 5932.8348778024874, + 5944.5396058651031, + 5956.2500983854261, + 5967.9663496939575, + 5979.6883541351208, + 5991.4161060672022, + 6003.1495998623004, + 6014.8888299062692, + 6026.6337905986684, + 6038.3844763527022, + 6050.1408815951781, + 6061.9030007664414, + 6073.6708283203316, + 6085.4443587241267, + 6097.2235864584891, + 6109.0085060174197, + 6120.7991119081998, + 6132.595398651345, + 6144.3973607805519, + 6156.2049928426459, + 6168.0182893975361, + 6179.8372450181578, + 6191.6618542904307, + 6203.4921118132024, + 6215.3280121982016, + 6227.1695500699925, + 6239.0167200659189, + 6250.8695168360628, + 6262.7279350431891, + 6274.5919693627056, + 6286.4616144826068, + 6298.3368651034316, + 6310.2177159382172, + 6322.1041617124456, + 6333.9961971640032, + 6345.8938170431311, + 6357.7970161123785, + 6369.7057891465583, + 6381.6201309327007, + 6393.5400362700075, + 6405.4654999698032, + 6417.3965168554978, + 6429.3330817625329, + 6441.2751895383453, + 6453.2228350423138, + 6465.176013145724, + 6477.134718731716, + 6489.0989466952469, + 6501.0686919430445, + 6513.0439493935628, + 6525.0247139769417, + 6537.010980634961, + 6549.002744321001, + 6560.9999999999973, + 6573.0027426483985, + 6585.0109672541284, + 6597.0246688165371, + 6609.0438423463656, + 6621.0684828657004, + 6633.0985854079354, + 6645.134145017727, + 6657.1751567509573, + 6669.2216156746908, + 6681.2735168671343, + 6693.3308554176001, + 6705.3936264264594, + 6717.461825005108, + 6729.535446275926, + 6741.6144853722335, + 6753.6989374382601, + 6765.7887976290967, + 6777.8840611106634, + 6789.9847230596661, + 6802.0907786635626, + 6814.2022231205201, + 6826.3190516393797, + 6838.4412594396181, + 6850.5688417513074, + 6862.701793815083, + 6874.840110882099, + 6886.9837882139991, + 6899.1328210828724, + 6911.2872047712199, + 6923.4469345719199, + 6935.6120057881863, + 6947.7824137335365, + 6959.9581537317536, + 6972.1392211168532, + 6984.3256112330409, + 6996.5173194346862, + 7008.7143410862773, + 7020.9166715623942, + 7033.1243062476678, + 7045.3372405367481, + 7057.5554698342685, + 7069.7789895548103, + 7082.0077951228714, + 7094.2418819728273, + 7106.4812455489018, + 7118.7258813051285, + 7130.9757847053224, + 7143.2309512230404, + 7155.4913763415516, + 7167.7570555538041, + 7180.0279843623894, + 7192.3041582795131, + 7204.5855728269571, + 7216.8722235360519, + 7229.1641059476406, + 7241.4612156120484, + 7253.7635480890503, + 7266.0710989478375, + 7278.3838637669869, + 7290.7018381344296, + 7303.0250176474174, + 7315.3533979124932, + 7327.6869745454596, + 7340.0257431713462, + 7352.3696994243801, + 7364.7188389479543, + 7377.0731573945968, + 7389.4326504259407, + 7401.7973137126937, + 7414.1671429346061, + 7426.5421337804428, + 7438.922281947951, + 7451.3075831438346, + 7463.6980330837177, + 7476.0936274921214, + 7488.4943621024304, + 7500.9002326568652, + 7513.3112349064522, + 7525.7273646109943, + 7538.1486175390446, + 7550.5749894678729, + 7563.0064761834419, + 7575.4430734803736, + 7587.8847771619248, + 7600.3315830399597, + 7612.7834869349153, + 7625.24048467578, + 7637.7025721000637, + 7650.1697450537677, + 7662.6419993913596, + 7675.1193309757446, + 7687.6017356782404, + 7700.0892093785433, + 7712.5817479647112, + 7725.079347333125, + 7737.5820033884729, + 7750.0897120437139, + 7762.6024692200581, + 7775.1202708469355, + 7787.6431128619733, + 7800.1709912109645, + 7812.7039018478481, + 7825.2418407346768, + 7837.7848038415968, + 7850.3327871468155, + 7862.8857866365806, + 7875.4437983051539, + 7888.006818154784, + 7900.5748421956796, + 7913.1478664459901, + 7925.725886931772, + 7938.3088996869719, + 7950.8969007533951, + 7963.4898861806851, + 7976.0878520262959, + 7988.6907943554688, + 8001.2987092412086, + 8013.911592764257, + 8026.5294410130691, + 8039.1522500837891, + 8051.7800160802271, + 8064.412735113835, + 8077.0504033036796, + 8089.6930167764222, + 8102.3405716662946, + 8114.9930641150731, + 8127.6504902720571, + 8140.3128462940449, + 8152.9801283453098, + 8165.6523325975786, + 8178.3294552300049, + 8191.0114924291529, + 8203.6984403889655, + 8216.3902953107463, + 8229.0870534031419, + 8241.7887108821069, + 8254.4952639708936, + 8267.2067089000211, + 8279.9230419072574, + 8292.6442592375952, + 8305.3703571432306, + 8318.101331883543, + 8330.8371797250657, + 8343.577896941475, + 8356.3234798135582, + 8369.0739246291978, + 8381.8292276833508, + 8394.5893852780209, + 8407.3543937222421, + 8420.1242493320569, + 8432.8989484304948, + 8445.6784873475499, + 8458.4628624201578, + 8471.2520699921806, + 8484.0461064143838, + 8496.8449680444082, + 8509.6486512467636, + 8522.4571523927953, + 8535.270467860666, + 8548.0885940353437, + 8560.9115273085663, + 8573.7392640788403, + 8586.5718007514006, + 8599.4091337382069, + 8612.2512594579148, + 8625.0981743358552, + 8637.9498748040205, + 8650.8063573010386, + 8663.6676182721567, + 8676.533654169225, + 8689.4044614506638, + 8702.2800365814601, + 8715.1603760331418, + 8728.0454762837508, + 8740.9353338178389, + 8753.8299451264356, + 8766.7293067070332, + 8779.6334150635721, + 8792.5422667064158, + 8805.4558581523324, + 8818.3741859244819, + 8831.2972465523908, + 8844.2250365719356, + 8857.1575525253265, + 8870.0947909610859, + 8883.0367484340295, + 8895.9834215052524, + 8908.934806742107, + 8921.8909007181846, + 8934.8517000132997, + 8947.817201213471, + 8960.7874009109, + 8973.7622957039603, + 8986.7418821971733, + 8999.7261570011924, + 9012.7151167327884, + 9025.7087580148236, + 9038.7070774762469, + 9051.7100717520643, + 9064.7177374833282, + 9077.7300713171153, + 9090.7470699065179, + 9103.7687299106146, + 9116.7950479944648, + 9129.8260208290812, + 9142.8616450914233, + 9155.9019174643727, + 9168.9468346367157, + 9181.9963933031358, + 9195.0505901641845, + 9208.1094219262741, + 9221.1728853016557, + 9234.240977008405, + 9247.3136937704076, + 9260.3910323173386, + 9273.472989384647, + 9286.5595617135423, + 9299.6507460509747, + 9312.7465391496207, + 9325.8469377678684, + 9338.9519386698012, + 9352.0615386251757, + 9365.1757344094131, + 9378.2945228035842, + 9391.4179005943843, + 9404.5458645741273, + 9417.6784115407263, + 9430.8155382976747, + 9443.9572416540359, + 9457.1035184244265, + 9470.2543654290002, + 9483.4097794934296, + 9496.5697574488931, + 9509.7342961320664, + 9522.9033923850911, + 9536.0770430555804, + 9549.2552449965824, + 9562.4379950665825, + 9575.6252901294793, + 9588.8171270545736, + 9602.0135027165488, + 9615.2144139954635, + 9628.4198577767274, + 9641.629830951093, + 9654.844330414644, + 9668.0633530687719, + 9681.286895820167, + 9694.5149555808002, + 9707.7475292679192, + 9720.9846138040157, + 9734.2262061168276, + 9747.4723031393187, + 9760.7229018096641, + 9773.9779990712323, + 9787.2375918725811, + 9800.5016771674327, + 9813.7702519146696, + 9827.0433130783094, + 9840.3208576275028, + 9853.602882536512, + 9866.8893847846994, + 9880.1803613565116, + 9893.4758092414686, + 9906.7757254341523, + 9920.0801069341851, + 9933.3889507462245, + 9946.7022538799429, + 9960.0200133500221, + 9973.3422261761298, + 9986.6688893829159, + 9999.9999999999945, + 10013.335555061929, + 10026.675551608221, + 10040.019986683301, + 10053.368857336509, + 10066.722160622081, + 10080.079893599144, + 10093.442053331697, + 10106.808636888598, + 10120.179641343551, + 10133.555063775095, + 10146.934901266595, + 10160.31915090622, + 10173.707809786936, + 10187.100875006496, + 10200.498343667417, + 10213.900212876984, + 10227.306479747222, + 10240.717141394889, + 10254.132194941467, + 10267.551637513146, + 10280.975466240814, + 10294.40367826004, + 10307.836270711066, + 10321.273240738796, + 10334.71458549278, + 10348.160302127204, + 10361.610387800878, + 10375.064839677221, + 10388.523654924258, + 10401.986830714593, + 10415.454364225412, + 10428.926252638465, + 10442.402493140049, + 10455.883082921007, + 10469.368019176709, + 10482.85729910704, + 10496.350919916393, + 10509.848878813653, + 10523.351173012188, + 10536.857799729838, + 10550.3687561889, + 10563.884039616123, + 10577.403647242685, + 10590.927576304197, + 10604.455824040679, + 10617.988387696556, + 10631.525264520642, + 10645.066451766135, + 10658.611946690598, + 10672.161746555956, + 10685.715848628475, + 10699.274250178762, + 10712.836948481747, + 10726.403940816675, + 10739.975224467091, + 10753.550796720834, + 10767.130654870027, + 10780.714796211059, + 10794.303218044579, + 10807.895917675487, + 10821.492892412922, + 10835.094139570248, + 10848.699656465047, + 10862.309440419107, + 10875.923488758415, + 10889.541798813138, + 10903.16436791762, + 10916.791193410372, + 10930.422272634056, + 10944.05760293548, + 10957.697181665582, + 10971.341006179427, + 10984.98907383619, + 10998.641381999149, + 11012.297928035676, + 11025.958709317223, + 11039.623723219316, + 11053.292967121541, + 11066.966438407539, + 11080.64413446499, + 11094.326052685608, + 11108.012190465128, + 11121.702545203296, + 11135.397114303863, + 11149.095895174571, + 11162.798885227143, + 11176.506081877278, + 11190.217482544635, + 11203.933084652828, + 11217.652885629415, + 11231.376882905886, + 11245.105073917659, + 11258.837456104062, + 11272.574026908333, + 11286.314783777601, + 11300.059724162888, + 11313.808845519083, + 11327.562145304952, + 11341.319620983111, + 11355.081270020033, + 11368.847089886023, + 11382.617078055218, + 11396.391232005579, + 11410.169549218874, + 11423.952027180676, + 11437.738663380349, + 11451.529455311042, + 11465.324400469679, + 11479.123496356951, + 11492.926740477304, + 11506.734130338931, + 11520.545663453764, + 11534.361337337466, + 11548.181149509423, + 11562.005097492724, + 11575.83317881417, + 11589.665391004253, + 11603.501731597149, + 11617.342198130715, + 11631.186788146468, + 11645.035499189589, + 11658.888328808911, + 11672.745274556904, + 11686.606333989675, + 11700.471504666955, + 11714.340784152086, + 11728.214170012021, + 11742.091659817312, + 11755.973251142101, + 11769.858941564111, + 11783.748728664636, + 11797.642610028539, + 11811.540583244237, + 11825.442645903697, + 11839.34879560242, + 11853.259029939445, + 11867.173346517333, + 11881.091742942155, + 11895.014216823492, + 11908.940765774427, + 11922.871387411526, + 11936.806079354839, + 11950.744839227897, + 11964.687664657684, + 11978.634553274653, + 11992.585502712702, + 12006.540510609168, + 12020.499574604828, + 12034.462692343877, + 12048.429861473938, + 12062.401079646032, + 12076.376344514589, + 12090.355653737433, + 12104.339004975769, + 12118.326395894188, + 12132.317824160644, + 12146.313287446457, + 12160.312783426305, + 12174.316309778205, + 12188.323864183525, + 12202.335444326955, + 12216.351047896511, + 12230.370672583531, + 12244.394316082657, + 12258.421976091831, + 12272.453650312296, + 12286.489336448574, + 12300.529032208471, + 12314.572735303058, + 12328.620443446678, + 12342.672154356922, + 12356.727865754638, + 12370.787575363909, + 12384.851280912055, + 12398.918980129623, + 12412.990670750381, + 12427.066350511306, + 12441.146017152583, + 12455.229668417589, + 12469.317302052901, + 12483.40891580827, + 12497.50450743663, + 12511.604074694078, + 12525.707615339878, + 12539.815127136444, + 12553.926607849342, + 12568.042055247275, + 12582.161467102082, + 12596.284841188726, + 12610.41217528529, + 12624.543467172971, + 12638.678714636069, + 12652.817915461985, + 12666.961067441209, + 12681.108168367316, + 12695.259216036962, + 12709.414208249869, + 12723.573142808827, + 12737.736017519681, + 12751.902830191326, + 12766.073578635704, + 12780.248260667788, + 12794.426874105588, + 12808.609416770132, + 12822.795886485468, + 12836.986281078653, + 12851.180598379744, + 12865.378836221802, + 12879.580992440871, + 12893.787064875984, + 12907.997051369144, + 12922.210949765335, + 12936.428757912496, + 12950.650473661524, + 12964.876094866273, + 12979.105619383534, + 12993.339045073039, + 13007.576369797454, + 13021.817591422368, + 13036.062707816285, + 13050.311716850629, + 13064.564616399723, + 13078.821404340792, + 13093.082078553954, + 13107.346636922217, + 13121.615077331464, + 13135.887397670458, + 13150.163595830827, + 13164.44366970706, + 13178.727617196502, + 13193.015436199352, + 13207.307124618648, + 13221.602680360265, + 13235.902101332911, + 13250.205385448118, + 13264.512530620239, + 13278.823534766434, + 13293.138395806676, + 13307.457111663734, + 13321.779680263176, + 13336.106099533356, + 13350.436367405409, + 13364.77048181325, + 13379.108440693562, + 13393.450241985796, + 13407.795883632158, + 13422.145363577607, + 13436.498679769853, + 13450.855830159346, + 13465.216812699266, + 13479.581625345529, + 13493.950266056772, + 13508.32273279435, + 13522.699023522329, + 13537.079136207483, + 13551.463068819286, + 13565.850819329906, + 13580.2423857142, + 13594.63776594971, + 13609.036958016657, + 13623.439959897927, + 13637.846769579081, + 13652.257385048335, + 13666.67180429656, + 13681.090025317284, + 13695.512046106669, + 13709.937864663521, + 13724.367478989278, + 13738.800887088004, + 13753.238086966385, + 13767.679076633727, + 13782.123854101939, + 13796.572417385545, + 13811.024764501659, + 13825.480893469998, + 13839.94080231286, + 13854.404489055134, + 13868.871951724283, + 13883.34318835034, + 13897.818196965914, + 13912.296975606168, + 13926.779522308825, + 13941.26583511416, + 13955.755912064991, + 13970.249751206682, + 13984.747350587126, + 13999.248708256751, + 14013.753822268511, + 14028.262690677873, + 14042.775311542828, + 14057.291682923867, + 14071.811802883994, + 14086.335669488704, + 14100.863280805994, + 14115.394634906341, + 14129.92972986271, + 14144.468563750548, + 14159.01113464777, + 14173.55744063476, + 14188.107479794369, + 14202.661250211901, + 14217.218749975118, + 14231.779977174227, + 14246.344929901879, + 14260.913606253163, + 14275.486004325601, + 14290.062122219146, + 14304.641958036171, + 14319.225509881464, + 14333.812775862236, + 14348.403754088098, + 14362.998442671067, + 14377.59683972556, + 14392.198943368388, + 14406.804751718748, + 14421.414262898223, + 14436.027475030774, + 14450.64438624274, + 14465.264994662828, + 14479.889298422106, + 14494.517295654005, + 14509.148984494313, + 14523.784363081166, + 14538.423429555049, + 14553.066182058781, + 14567.712618737527, + 14582.362737738777, + 14597.016537212348, + 14611.674015310382, + 14626.33517018734, + 14640.999999999993, + 14655.668502907418, + 14670.340677071003, + 14685.016520654426, + 14699.696031823671, + 14714.379208746999, + 14729.066049594967, + 14743.756552540408, + 14758.45071575843, + 14773.148537426418, + 14787.850015724018, + 14802.555148833142, + 14817.263934937961, + 14831.976372224897, + 14846.692458882624, + 14861.41219310206, + 14876.135573076363, + 14890.862597000923, + 14905.593263073371, + 14920.327569493558, + 14935.065514463557, + 14949.807096187662, + 14964.552312872382, + 14979.301162726431, + 14994.053643960735, + 15008.809754788414, + 15023.569493424788, + 15038.332858087369, + 15053.099846995858, + 15067.870458372134, + 15082.644690440264, + 15097.422541426484, + 15112.204009559202, + 15126.989093068994, + 15141.777790188597, + 15156.570099152905, + 15171.366018198967, + 15186.165545565986, + 15200.968679495301, + 15215.775418230402, + 15230.585760016909, + 15245.399703102579, + 15260.217245737298, + 15275.038386173073, + 15289.863122664035, + 15304.691453466432, + 15319.523376838621, + 15334.358891041069, + 15349.197994336346, + 15364.040684989128, + 15378.886961266177, + 15393.736821436356, + 15408.590263770609, + 15423.447286541972, + 15438.307888025554, + 15453.172066498542, + 15468.039820240196, + 15482.91114753184, + 15497.786046656869, + 15512.664515900733, + 15527.546553550939, + 15542.432157897045, + 15557.32132723066, + 15572.214059845435, + 15587.110354037064, + 15602.010208103273, + 15616.913620343823, + 15631.820589060506, + 15646.731112557136, + 15661.645189139546, + 15676.562817115593, + 15691.483994795139, + 15706.408720490062, + 15721.336992514242, + 15736.268809183561, + 15751.204168815901, + 15766.143069731135, + 15781.085510251132, + 15796.03148869974, + 15810.981003402798, + 15825.934052688119, + 15840.890634885489, + 15855.850748326673, + 15870.814391345401, + 15885.781562277361, + 15900.752259460214, + 15915.726481233565, + 15930.704225938984, + 15945.685491919978, + 15960.670277522009, + 15975.658581092481, + 15990.65040098073, + 16005.645735538035, + 16020.644583117599, + 16035.646942074556, + 16050.652810765967, + 16065.662187550806, + 16080.675070789974, + 16095.691458846273, + 16110.711350084424, + 16125.734742871053, + 16140.761635574685, + 16155.792026565747, + 16170.825914216561, + 16185.863296901338, + 16200.904172996183, + 16215.948540879079, + 16230.996398929899, + 16246.047745530386, + 16261.102579064163, + 16276.160897916721, + 16291.22270047542, + 16306.287985129484, + 16321.356750269995, + 16336.428994289896, + 16351.504715583982, + 16366.5839125489, + 16381.666583583141, + 16396.752727087041, + 16411.842341462776, + 16426.935425114363, + 16442.031976447644, + 16457.131993870298, + 16472.235475791829, + 16487.342420623561, + 16502.452826778641, + 16517.566692672033, + 16532.684016720516, + 16547.804797342676, + 16562.929032958902, + 16578.056721991394, + 16593.18786286415, + 16608.322454002962, + 16623.460493835417, + 16638.601980790896, + 16653.746913300558, + 16668.895289797354, + 16684.047108716015, + 16699.202368493046, + 16714.361067566726, + 16729.523204377107, + 16744.688777366009, + 16759.857784977012, + 16775.030225655464, + 16790.206097848466, + 16805.385400004874, + 16820.568130575302, + 16835.754288012104, + 16850.943870769381, + 16866.136877302983, + 16881.333306070494, + 16896.53315553123, + 16911.736424146249, + 16926.943110378332, + 16942.153212691992, + 16957.366729553454, + 16972.583659430682, + 16987.804000793338, + 17003.027752112816, + 17018.254911862205, + 17033.485478516312, + 17048.719450551645, + 17063.956826446421, + 17079.197604680547, + 17094.44178373563, + 17109.689362094967, + 17124.940338243552, + 17140.194710668064, + 17155.452477856852, + 17170.713638299967, + 17185.978190489128, + 17201.246132917724, + 17216.517464080825, + 17231.792182475165, + 17247.070286599141, + 17262.351774952826, + 17277.636646037936, + 17292.924898357855, + 17308.216530417623, + 17323.511540723921, + 17338.809927785089, + 17354.111690111105, + 17369.416826213594, + 17384.725334605821, + 17400.037213802683, + 17415.352462320716, + 17430.67107867809, + 17445.993061394587, + 17461.318408991636, + 17476.647119992274, + 17491.979192921168, + 17507.314626304586, + 17522.653418670423, + 17537.995568548187, + 17553.341074468986, + 17568.689934965536, + 17584.042148572156, + 17599.397713824768, + 17614.75662926089, + 17630.118893419625, + 17645.484504841683, + 17660.853462069354, + 17676.225763646511, + 17691.601408118619, + 17706.980394032718, + 17722.362719937424, + 17737.748384382936, + 17753.137385921014, + 17768.529723104999, + 17783.92539448979, + 17799.324398631856, + 17814.726734089225, + 17830.13239942148, + 17845.541393189767, + 17860.95371395678, + 17876.369360286772, + 17891.788330745527, + 17907.210623900395, + 17922.636238320254, + 17938.065172575527, + 17953.497425238176, + 17968.932994881692, + 17984.371880081104, + 17999.814079412972, + 18015.259591455371, + 18030.708414787914, + 18046.160547991731, + 18061.615989649465, + 18077.074738345284, + 18092.536792664861, + 18108.002151195393, + 18123.470812525571, + 18138.942775245599, + 18154.418037947191, + 18169.896599223546, + 18185.37845766938, + 18200.863611880886, + 18216.352060455767, + 18231.843801993204, + 18247.338835093873, + 18262.837158359936, + 18278.338770395032, + 18293.84366980429, + 18309.351855194309, + 18324.863325173166, + 18340.378078350412, + 18355.896113337069, + 18371.417428745623, + 18386.942023190033, + 18402.469895285718, + 18418.00104364955, + 18433.53546689987, + 18449.073163656474, + 18464.614132540602, + 18480.158372174956, + 18495.705881183676, + 18511.256658192357, + 18526.810701828035, + 18542.368010719183, + 18557.928583495715, + 18573.492418788985, + 18589.059515231773, + 18604.629871458303, + 18620.203486104212, + 18635.78035780658, + 18651.360485203899, + 18666.943866936086, + 18682.53050164448, + 18698.120387971841, + 18713.713524562332, + 18729.30991006154, + 18744.909543116457, + 18760.512422375479, + 18776.118546488418, + 18791.727914106479, + 18807.340523882274, + 18822.95637446981, + 18838.575464524489, + 18854.197792703111, + 18869.823357663863, + 18885.452158066328, + 18901.08419257147, + 18916.719459841639, + 18932.357958540564, + 18947.999687333362, + 18963.644644886521, + 18979.292829867907, + 18994.944240946759, + 19010.598876793687, + 19026.256736080668, + 19041.917817481048, + 19057.582119669532, + 19073.2496413222, + 19088.920381116473, + 19104.594337731145, + 19120.271509846356, + 19135.951896143604, + 19151.635495305738, + 19167.322306016948, + 19183.012326962784, + 19198.705556830122, + 19214.401994307198, + 19230.101638083579, + 19245.804486850167, + 19261.510539299208, + 19277.219794124274, + 19292.932250020265, + 19308.647905683421, + 19324.366759811302, + 19340.088811102793, + 19355.8140582581, + 19371.542499978754, + 19387.2741349676, + 19403.008961928797, + 19418.746979567823, + 19434.488186591469, + 19450.232581707827, + 19465.980163626304, + 19481.730931057613, + 19497.484882713761, + 19513.242017308068, + 19529.002333555141, + 19544.765830170898, + 19560.532505872539, + 19576.302359378566, + 19592.075389408761, + 19607.851594684209, + 19623.630973927269, + 19639.41352586159, + 19655.199249212103, + 19670.988142705017, + 19686.780205067826, + 19702.575435029288, + 19718.373831319448, + 19734.175392669615, + 19749.980117812371, + 19765.788005481569, + 19781.599054412323, + 19797.413263341008, + 19813.230631005274, + 19829.051156144014, + 19844.874837497395, + 19860.701673806827, + 19876.531663814985, + 19892.364806265789, + 19908.201099904403, + 19924.040543477258, + 19939.883135732012, + 19955.728875417579, + 19971.577761284105, + 19987.429792082985, + 20003.284966566847, + 20019.14328348956, + 20035.004741606219, + 20050.869339673161, + 20066.737076447946, + 20082.607950689362, + 20098.481961157428, + 20114.359106613385, + 20130.239385819699, + 20146.122797540058, + 20162.009340539353, + 20177.899013583716, + 20193.791815440476, + 20209.687744878182, + 20225.586800666591, + 20241.488981576669, + 20257.394286380597, + 20273.302713851754, + 20289.214262764715, + 20305.128931895277, + 20321.046720020415, + 20336.967625918318, + 20352.891648368361, + 20368.818786151114, + 20384.749038048347, + 20400.682402843009, + 20416.618879319249, + 20432.558466262391, + 20448.501162458953, + 20464.446966696629, + 20480.395877764302, + 20496.347894452025, + 20512.303015551031, + 20528.261239853735, + 20544.22256615372, + 20560.186993245738, + 20576.15451992572, + 20592.125144990758, + 20608.098867239107, + 20624.075685470198, + 20640.055598484618, + 20656.038605084115, + 20672.024704071595, + 20688.013894251126, + 20704.006174427926, + 20720.001543408373, + 20735.999999999989, + 20752.001543011454, + 20768.006171252597, + 20784.013883534382, + 20800.024678668931, + 20816.038555469506, + 20832.055512750507, + 20848.075549327474, + 20864.098664017085, + 20880.124855637161, + 20896.154123006647, + 20912.186464945626, + 20928.221880275312, + 20944.260367818049, + 20960.301926397311, + 20976.346554837684, + 20992.394251964895, + 21008.445016605787, + 21024.498847588318, + 21040.555743741574, + 21056.615703895754, + 21072.678726882168, + 21088.744811533252, + 21104.813956682538, + 21120.886161164683, + 21136.961423815443, + 21153.039743471683, + 21169.121118971379, + 21185.205549153605, + 21201.293032858535, + 21217.383568927453, + 21233.477156202731, + 21249.573793527841, + 21265.673479747358, + 21281.776213706937, + 21297.881994253334, + 21313.990820234398, + 21330.102690499054, + 21346.21760389733, + 21362.335559280327, + 21378.456555500241, + 21394.580591410333, + 21410.707665864964, + 21426.83777771956, + 21442.970925830628, + 21459.107109055756, + 21475.246326253604, + 21491.388576283895, + 21507.533858007431, + 21523.682170286087, + 21539.833511982797, + 21555.987881961566, + 21572.145279087465, + 21588.305702226615, + 21604.469150246216, + 21620.635622014521, + 21636.805116400832, + 21652.977632275521, + 21669.153168510009, + 21685.331723976764, + 21701.513297549318, + 21717.697888102244, + 21733.885494511167, + 21750.076115652759, + 21766.269750404736, + 21782.466397645861, + 21798.666056255934, + 21814.868725115801, + 21831.074403107345, + 21847.283089113484, + 21863.494782018177, + 21879.709480706417, + 21895.927184064229, + 21912.147890978667, + 21928.371600337818, + 21944.598311030797, + 21960.828021947746, + 21977.060731979829, + 21993.296440019243, + 22009.535144959198, + 22025.77684569393, + 22042.021541118691, + 22058.269230129757, + 22074.519911624411, + 22090.773584500959, + 22107.030247658717, + 22123.289899998013, + 22139.552540420187, + 22155.818167827587, + 22172.086781123569, + 22188.358379212495, + 22204.632960999726, + 22220.910525391639, + 22237.191071295601, + 22253.474597619981, + 22269.761103274148, + 22286.050587168469, + 22302.343048214312, + 22318.638485324027, + 22334.936897410968, + 22351.23828338947, + 22367.542642174871, + 22383.849972683485, + 22400.160273832618, + 22416.473544540564, + 22432.789783726603, + 22449.108990310986, + 22465.431163214958, + 22481.75630136074, + 22498.084403671528, + 22514.415469071497, + 22530.749496485802, + 22547.086484840562, + 22563.426433062879, + 22579.769340080824, + 22596.115204823436, + 22612.464026220721, + 22628.815803203655, + 22645.170534704179, + 22661.5282196552, + 22677.888856990587, + 22694.252445645168, + 22710.618984554734, + 22726.988472656034, + 22743.360908886778, + 22759.736292185622, + 22776.114621492186, + 22792.495895747044, + 22808.880113891719, + 22825.267274868678, + 22841.657377621348, + 22858.050421094096, + 22874.446404232243, + 22890.845325982053, + 22907.247185290722, + 22923.651981106406, + 22940.059712378195, + 22956.470378056114, + 22972.883977091129, + 22989.300508435153, + 23005.719971041017, + 23022.142363862498, + 23038.567685854305, + 23054.995935972078, + 23071.427113172387, + 23087.86121641273, + 23104.298244651531, + 23120.738196848146, + 23137.181071962848, + 23153.626868956846, + 23170.075586792263, + 23186.527224432142, + 23202.981780840448, + 23219.439254982066, + 23235.899645822796, + 23252.362952329357, + 23268.829173469378, + 23285.298308211408, + 23301.770355524899, + 23318.245314380223, + 23334.723183748658, + 23351.203962602387, + 23367.687649914504, + 23384.174244659007, + 23400.663745810798, + 23417.15615234568, + 23433.651463240367, + 23450.149677472462, + 23466.650794020472, + 23483.154811863806, + 23499.661729982763, + 23516.171547358543, + 23532.684262973235, + 23549.199875809823, + 23565.718384852185, + 23582.239789085092, + 23598.764087494197, + 23615.291279066041, + 23631.821362788058, + 23648.354337648565, + 23664.890202636761, + 23681.428956742733, + 23697.970598957443, + 23714.515128272738, + 23731.062543681343, + 23747.612844176863, + 23764.166028753778, + 23780.72209640744, + 23797.281046134085, + 23813.842876930816, + 23830.407587795606, + 23846.975177727301, + 23863.545645725622, + 23880.11899079115, + 23896.695211925336, + 23913.274308130498, + 23929.856278409821, + 23946.441121767348, + 23963.028837207989, + 23979.619423737513, + 23996.212880362549, + 24012.809206090584, + 24029.408399929966, + 24046.010460889898, + 24062.615387980433, + 24079.223180212492, + 24095.833836597827, + 24112.447356149063, + 24129.063737879667, + 24145.682980803951, + 24162.305083937081, + 24178.930046295067, + 24195.557866894767, + 24212.188544753884, + 24228.822078890964, + 24245.458468325389, + 24262.097712077397, + 24278.739809168052, + 24295.384758619261, + 24312.032559453768, + 24328.683210695162, + 24345.336711367858, + 24361.993060497109, + 24378.652257108995, + 24395.314300230442, + 24411.979188889192, + 24428.646922113825, + 24445.317498933746, + 24461.990918379193, + 24478.667179481225, + 24495.346281271726, + 24512.028222783407, + 24528.713003049801, + 24545.400621105266, + 24562.091075984976, + 24578.784366724925, + 24595.480492361927, + 24612.179451933614, + 24628.881244478438, + 24645.585869035654, + 24662.293324645343, + 24679.003610348394, + 24695.716725186514, + 24712.432668202211, + 24729.151438438807, + 24745.873034940436, + 24762.597456752032, + 24779.324702919344, + 24796.054772488926, + 24812.787664508123, + 24829.5233780251, + 24846.261912088819, + 24863.003265749034, + 24879.747438056307, + 24896.494428062004, + 24913.244234818278, + 24929.996857378079, + 24946.752294795166, + 24963.510546124078, + 24980.271610420157, + 24997.035486739525, + 25013.802174139113, + 25030.571671676629, + 25047.343978410572, + 25064.119093400237, + 25080.897015705697, + 25097.677744387816, + 25114.461278508239, + 25131.2476171294, + 25148.036759314517, + 25164.828704127583, + 25181.623450633375, + 25198.42099789745, + 25215.221344986145, + 25232.024490966574, + 25248.830434906627, + 25265.639175874974, + 25282.450712941049, + 25299.265045175071, + 25316.082171648024, + 25332.902091431668, + 25349.724803598532, + 25366.550307221914, + 25383.378601375884, + 25400.209685135269, + 25417.043557575678, + 25433.880217773472, + 25450.719664805783, + 25467.561897750507, + 25484.406915686297, + 25501.254717692573, + 25518.105302849512, + 25534.958670238051, + 25551.814818939893, + 25568.67374803748, + 25585.535456614027, + 25602.399943753502, + 25619.267208540619, + 25636.137250060852, + 25653.010067400432, + 25669.885659646327, + 25686.76402588627, + 25703.645165208734, + 25720.529076702944, + 25737.415759458876, + 25754.305212567244, + 25771.197435119517, + 25788.092426207899, + 25804.990184925344, + 25821.890710365547, + 25838.794001622944, + 25855.700057792714, + 25872.608877970775, + 25889.520461253778, + 25906.434806739118, + 25923.351913524923, + 25940.271780710063, + 25957.194407394138, + 25974.11979267748, + 25991.047935661154, + 26007.978835446964, + 26024.912491137442, + 26041.848901835841, + 26058.788066646157, + 26075.729984673108, + 26092.674655022136, + 26109.622076799409, + 26126.572249111829, + 26143.525171067016, + 26160.480841773315, + 26177.43926033979, + 26194.400425876229, + 26211.364337493149, + 26228.330994301767, + 26245.30039541404, + 26262.272539942627, + 26279.247427000919, + 26296.225055703002, + 26313.205425163702, + 26330.188534498539, + 26347.174382823756, + 26364.162969256304, + 26381.154292913852, + 26398.148352914774, + 26415.145148378149, + 26432.144678423778, + 26449.146942172156, + 26466.151938744493, + 26483.159667262702, + 26500.170126849403, + 26517.183316627921, + 26534.199235722277, + 26551.217883257199, + 26568.239258358124, + 26585.263360151173, + 26602.290187763181, + 26619.319740321676, + 26636.352016954883, + 26653.387016791727, + 26670.424738961825, + 26687.465182595493, + 26704.508346823739, + 26721.554230778267, + 26738.602833591467, + 26755.65415439643, + 26772.708192326929, + 26789.764946517433, + 26806.824416103096, + 26823.886600219761, + 26840.95149800396, + 26858.019108592915, + 26875.089431124517, + 26892.162464737365, + 26909.238208570721, + 26926.316661764544, + 26943.397823459472, + 26960.481692796813, + 26977.568268918571, + 26994.657550967422, + 27011.749538086722, + 27028.844229420498, + 27045.941624113464, + 27063.041721311005, + 27080.144520159181, + 27097.250019804727, + 27114.35821939505, + 27131.469118078236, + 27148.582715003027, + 27165.699009318858, + 27182.818000175819, + 27199.939686724665, + 27217.064068116837, + 27234.191143504428, + 27251.320912040203, + 27268.453372877593, + 27285.588525170693, + 27302.726368074269, + 27319.866900743735, + 27337.010122335181, + 27354.156032005358, + 27371.304628911668, + 27388.455912212183, + 27405.609881065626, + 27422.766534631384, + 27439.925872069507, + 27457.087892540683, + 27474.252595206275, + 27491.419979228293, + 27508.5900437694, + 27525.762787992917, + 27542.93821106281, + 27560.116312143706, + 27577.297090400876, + 27594.480545000242, + 27611.666675108383, + 27628.855479892518, + 27646.046958520514, + 27663.241110160889, + 27680.437933982801, + 27697.637429156068, + 27714.839594851132, + 27732.04443023909, + 27749.251934491687, + 27766.462106781299, + 27783.674946280949, + 27800.890452164302, + 27818.108623605654, + 27835.329459779954, + 27852.55295986278, + 27869.779123030345, + 27887.007948459504, + 27904.239435327745, + 27921.473582813196, + 27938.710390094613, + 27955.949856351392, + 27973.19198076355, + 27990.436762511745, + 28007.684200777272, + 28024.934294742041, + 28042.187043588601, + 28059.442446500128, + 28076.700502660427, + 28093.961211253929, + 28111.224571465693, + 28128.490582481401, + 28145.759243487362, + 28163.030553670509, + 28180.304512218394, + 28197.581118319198, + 28214.860371161725, + 28232.14226993539, + 28249.42681383024, + 28266.71400203693, + 28284.003833746745, + 28301.296308151585, + 28318.591424443959, + 28335.889181817001, + 28353.189579464462, + 28370.492616580705, + 28387.798292360701, + 28405.106606000048, + 28422.417556694945, + 28439.731143642206, + 28457.047366039264, + 28474.366223084147, + 28491.687713975512, + 28509.011837912611, + 28526.338594095305, + 28543.667981724069, + 28560.999999999982, + 28578.334648124732, + 28595.671925300605, + 28613.011830730498, + 28630.354363617909, + 28647.699523166943, + 28665.0473085823, + 28682.397719069289, + 28699.750753833818, + 28717.10641208239, + 28734.464693022121, + 28751.825595860708, + 28769.189119806462, + 28786.55526406828, + 28803.924027855664, + 28821.295410378701, + 28838.669410848088, + 28856.046028475103, + 28873.425262471628, + 28890.80711205013, + 28908.191576423673, + 28925.578654805915, + 28942.968346411097, + 28960.360650454055, + 28977.755566150216, + 28995.153092715591, + 29012.553229366786, + 29029.955975320987, + 29047.361329795975, + 29064.769292010107, + 29082.179861182336, + 29099.593036532187, + 29117.00881727978, + 29134.427202645813, + 29151.848191851568, + 29169.271784118911, + 29186.697978670283, + 29204.126774728706, + 29221.55817151779, + 29238.992168261717, + 29256.42876418525, + 29273.867958513725, + 29291.309750473058, + 29308.754139289747, + 29326.201124190855, + 29343.65070440403, + 29361.102879157483, + 29378.557647680012, + 29396.015009200975, + 29413.474962950309, + 29430.937508158524, + 29448.402644056692, + 29465.870369876469, + 29483.340684850071, + 29500.81358821028, + 29518.289079190454, + 29535.767157024511, + 29553.247820946945, + 29570.731070192807, + 29588.216903997723, + 29605.70532159787, + 29623.19632223, + 29640.689905131429, + 29658.186069540028, + 29675.684814694236, + 29693.186139833047, + 29710.690044196028, + 29728.196527023298, + 29745.705587555527, + 29763.217225033964, + 29780.731438700397, + 29798.248227797183, + 29815.76759156723, + 29833.289529254005, + 29850.81404010153, + 29868.341123354381, + 29885.870778257693, + 29903.403004057145, + 29920.937799998974, + 29938.475165329975, + 29956.015099297485, + 29973.557601149394, + 29991.102670134147, + 30008.650305500738, + 30026.200506498706, + 30043.753272378144, + 30061.308602389683, + 30078.866495784507, + 30096.426951814352, + 30113.989969731494, + 30131.55554878875, + 30149.123688239491, + 30166.694387337629, + 30184.267645337608, + 30201.843461494434, + 30219.42183506364, + 30237.002765301309, + 30254.586251464058, + 30272.172292809046, + 30289.760888593977, + 30307.35203807709, + 30324.94574051716, + 30342.541995173502, + 30360.140801305966, + 30377.742158174944, + 30395.346065041358, + 30412.952521166666, + 30430.561525812864, + 30448.173078242475, + 30465.787177718561, + 30483.403823504719, + 30501.02301486507, + 30518.644751064272, + 30536.269031367516, + 30553.895855040515, + 30571.525221349519, + 30589.157129561307, + 30606.791578943175, + 30624.428568762964, + 30642.06809828903, + 30659.710166790261, + 30677.35477353607, + 30695.001917796391, + 30712.651598841687, + 30730.303815942945, + 30747.958568371676, + 30765.615855399912, + 30783.275676300211, + 30800.938030345646, + 30818.602916809814, + 30836.270334966837, + 30853.940284091354, + 30871.612763458521, + 30889.287772344011, + 30906.965310024025, + 30924.645375775272, + 30942.327968874983, + 30960.013088600903, + 30977.700734231294, + 30995.390905044929, + 31013.083600321101, + 31030.778819339619, + 31048.476561380798, + 31066.17682572547, + 31083.879611654978, + 31101.584918451179, + 31119.29274539644, + 31137.003091773637, + 31154.715956866155, + 31172.431339957893, + 31190.14924033326, + 31207.869657277162, + 31225.592590075023, + 31243.318038012771, + 31261.046000376838, + 31278.776476454172, + 31296.50946553221, + 31314.24496689891, + 31331.98297984272, + 31349.7235036526, + 31367.466537618013, + 31385.212081028923, + 31402.960133175795, + 31420.710693349596, + 31438.463760841791, + 31456.219334944351, + 31473.977414949743, + 31491.738000150934, + 31509.501089841389, + 31527.266683315069, + 31545.034779866437, + 31562.80537879045, + 31580.578479382562, + 31598.35408093872, + 31616.132182755369, + 31633.91278412945, + 31651.695884358396, + 31669.481482740131, + 31687.269578573076, + 31705.060171156143, + 31722.853259788735, + 31740.648843770748, + 31758.446922402567, + 31776.247494985066, + 31794.050560819614, + 31811.85611920806, + 31829.664169452753, + 31847.474710856521, + 31865.287742722685, + 31883.103264355046, + 31900.921275057899, + 31918.741774136019, + 31936.564760894671, + 31954.390234639599, + 31972.21819467704, + 31990.048640313704, + 32007.881570856793, + 32025.716985613984, + 32043.554883893445, + 32061.395265003815, + 32079.238128254223, + 32097.083472954269, + 32114.931298414049, + 32132.781603944117, + 32150.634388855524, + 32168.48965245979, + 32186.347394068915, + 32204.207612995371, + 32222.07030855212, + 32239.935480052583, + 32257.803126810672, + 32275.673248140767, + 32293.545843357719, + 32311.420911776862, + 32329.298452713996, + 32347.178465485395, + 32365.060949407813, + 32382.945903798463, + 32400.83332797504, + 32418.723221255706, + 32436.615582959093, + 32454.510412404306, + 32472.407708910916, + 32490.307471798966, + 32508.209700388961, + 32526.114394001877, + 32544.021551959166, + 32561.931173582732, + 32579.843258194956, + 32597.757805118679, + 32615.674813677211, + 32633.594283194328, + 32651.516212994258, + 32669.440602401712, + 32687.367450741847, + 32705.296757340297, + 32723.228521523146, + 32741.162742616943, + 32759.099419948703, + 32777.038552845901, + 32794.980140636464, + 32812.924182648792, + 32830.87067821173, + 32848.819626654593, + 32866.77102730715, + 32884.724879499619, + 32902.681182562686, + 32920.639935827494, + 32938.601138625643, + 32956.56479028918, + 32974.530890150607, + 32992.499437542894, + 33010.470431799447, + 33028.443872254145, + 33046.419758241311, + 33064.39808909571, + 33082.378864152583, + 33100.36208274759, + 33118.347744216881, + 33136.335847897026, + 33154.326393125062, + 33172.31937923847, + 33190.314805575174, + 33208.312671473555, + 33226.312976272442, + 33244.315719311111, + 33262.320899929284, + 33280.328517467125, + 33298.33857126526, + 33316.351060664747, + 33334.365985007091, + 33352.383343634239, + 33370.403135888591, + 33388.42536111299, + 33406.450018650721, + 33424.477107845501, + 33442.506628041512, + 33460.53857858335, + 33478.572958816083, + 33496.609768085189, + 33514.649005736617, + 33532.690671116739, + 33550.734763572356, + 33568.781282450735, + 33586.830227099563, + 33604.881596866973, + 33622.935391101528, + 33640.991609152239, + 33659.050250368542, + 33677.111314100322, + 33695.174799697881, + 33713.240706511984, + 33731.309033893805, + 33749.37978119497, + 33767.452947767531, + 33785.528532963974, + 33803.606536137209, + 33821.686956640602, + 33839.769793827938, + 33857.855047053425, + 33875.942715671707, + 33894.032799037872, + 33912.125296507431, + 33930.220207436316, + 33948.317531180888, + 33966.417267097961, + 33984.519414544746, + 34002.623972878901, + 34020.730941458511, + 34038.840319642077, + 34056.952106788536, + 34075.066302257255, + 34093.182905408015, + 34111.301915601027, + 34129.42333219693, + 34147.547154556785, + 34165.673382042078, + 34183.80201401472, + 34201.933049837033, + 34220.06648887178, + 34238.202330482141, + 34256.340574031703, + 34274.481218884495, + 34292.624264404949, + 34310.769709957938, + 34328.91755490873, + 34347.067798623029, + 34365.220440466954, + 34383.375479807051, + 34401.532916010263, + 34419.692748443973, + 34437.854976475966, + 34456.01959947445, + 34474.18661680806, + 34492.356027845817, + 34510.527831957188, + 34528.702028512052, + 34546.878616880676, + 34565.05759643377, + 34583.238966542449, + 34601.422726578232, + 34619.608875913065, + 34637.797413919296, + 34655.988339969692, + 34674.181653437423, + 34692.37735369608, + 34710.575440119668, + 34728.775912082579, + 34746.978768959649, + 34765.184010126082, + 34783.391634957537, + 34801.60164283005, + 34819.814033120063, + 34838.028805204456, + 34856.24595846048, + 34874.465492265823, + 34892.687405998557, + 34910.911699037177, + 34929.138370760564, + 34947.367420548027, + 34965.598847779271, + 34983.832651834389, + 35002.068832093908, + 35020.307387938738, + 35038.548318750189, + 35056.79162390998, + 35075.03730280025, + 35093.285354803513, + 35111.535779302685, + 35129.788575681116, + 35148.043743322516, + 35166.301281611013, + 35184.561189931141, + 35202.823467667826, + 35221.088114206388, + 35239.355128932555, + 35257.624511232447, + 35275.896260492584, + 35294.170376099886, + 35312.446857441668, + 35330.725703905628, + 35349.006914879887, + 35367.290489752944, + 35385.576427913686, + 35403.864728751418, + 35422.155391655811, + 35440.448416016967, + 35458.743801225341, + 35477.041546671804, + 35495.341651747622, + 35513.644115844436, + 35531.948938354304, + 35550.256118669655, + 35568.565656183309, + 35586.877550288496, + 35605.191800378816, + 35623.508405848268, + 35641.827366091238, + 35660.148680502505, + 35678.472348477233, + 35696.798369410979, + 35715.126742699678, + 35733.457467739659, + 35751.790543927644, + 35770.125970660738, + 35788.46374733642, + 35806.803873352568, + 35825.146348107453, + 35843.49117099971, + 35861.838341428367, + 35880.187858792851, + 35898.539722492955, + 35916.893931928862, + 35935.250486501129, + 35953.609385610718, + 35971.970628658957, + 35990.334215047558, + 36008.700144178612, + 36027.068415454596, + 36045.439028278372, + 36063.811982053165, + 36082.187276182609, + 36100.564910070694, + 36118.944883121789, + 36137.327194740654, + 36155.711844332429, + 36174.098831302617, + 36192.488155057115, + 36210.87981500219, + 36229.273810544473, + 36247.670141091003, + 36266.068806049167, + 36284.469804826738, + 36302.873136831862, + 36321.278801473069, + 36339.686798159251, + 36358.097126299683, + 36376.509785304013, + 36394.924774582258, + 36413.342093544816, + 36431.761741602444, + 36450.183718166292, + 36468.608022647859, + 36487.034654459028, + 36505.463613012063, + 36523.894897719583, + 36542.328507994578, + 36560.764443250409, + 36579.202702900831, + 36597.643286359926, + 36616.086193042182, + 36634.531422362437, + 36652.978973735895, + 36671.428846578143, + 36689.881040305125, + 36708.335554333149, + 36726.792388078902, + 36745.251540959427, + 36763.713012392138, + 36782.176801794812, + 36800.642908585593, + 36819.111332182983, + 36837.582072005869, + 36856.055127473483, + 36874.530498005421, + 36893.008183021651, + 36911.488181942506, + 36929.970494188674, + 36948.455119181206, + 36966.942056341519, + 36985.431305091392, + 37003.922864852961, + 37022.416735048733, + 37040.912915101559, + 37059.411404434657, + 37077.91220247162, + 37096.415308636388, + 37114.920722353243, + 37133.428443046862, + 37151.938470142253, + 37170.450803064785, + 37188.965441240209, + 37207.482384094597, + 37226.001631054402, + 37244.523181546429, + 37263.047034997842, + 37281.573190836149, + 37300.101648489224, + 37318.632407385296, + 37337.165466952945, + 37355.700826621112, + 37374.238485819085, + 37392.778443976509, + 37411.320700523385, + 37429.865254890057, + 37448.412106507232, + 37466.961254805974, + 37485.512699217681, + 37504.066439174116, + 37522.622474107404, + 37541.180803449992, + 37559.741426634704, + 37578.304343094693, + 37596.869552263488, + 37615.43705357494, + 37634.006846463279, + 37652.578930363044, + 37671.153304709165, + 37689.729968936896, + 37708.308922481847, + 37726.890164779965, + 37745.473695267559, + 37764.059513381275, + 37782.647618558112, + 37801.238010235415, + 37819.830687850859, + 37838.425650842495, + 37857.022898648691, + 37875.622430708172, + 37894.224246460013, + 37912.828345343616, + 37931.434726798747, + 37950.043390265506, + 37968.654335184328, + 37987.267560995999, + 38005.883067141665, + 38024.500853062775, + 38043.120918201159, + 38061.743261998963, + 38080.367883898682, + 38098.994783343158, + 38117.623959775563, + 38136.255412639417, + 38154.889141378575, + 38173.525145437234, + 38192.163424259939, + 38210.803977291551, + 38229.446803977284, + 38248.091903762703, + 38266.739276093685, + 38285.388920416466, + 38304.040836177606, + 38322.695022824002, + 38341.351479802899, + 38360.010206561863, + 38378.671202548816, + 38397.334467211993, + 38415.999999999978, + 38434.667800361683, + 38453.33786774637, + 38472.010201603611, + 38490.684801383337, + 38509.361666535784, + 38528.040796511552, + 38546.722190761553, + 38565.405848737035, + 38584.091769889594, + 38602.779953671132, + 38621.470399533908, + 38640.163106930493, + 38658.858075313794, + 38677.555304137059, + 38696.254792853862, + 38714.956540918094, + 38733.660547783991, + 38752.366812906112, + 38771.075335739348, + 38789.78611573892, + 38808.499152360368, + 38827.214445059573, + 38845.931993292739, + 38864.651796516388, + 38883.373854187383, + 38902.098165762916, + 38920.824730700486, + 38939.553548457938, + 38958.284618493431, + 38977.017940265461, + 38995.753513232834, + 39014.491336854699, + 39033.231410590517, + 39051.973733900079, + 39070.718306243485, + 39089.465127081188, + 39108.214195873945, + 39126.965512082832, + 39145.719075169261, + 39164.474884594965, + 39183.232939821988, + 39201.99324031271, + 39220.755785529815, + 39239.52057493633, + 39258.287607995589, + 39277.056884171245, + 39295.828402927284, + 39314.602163728006, + 39333.378166038019, + 39352.15640932227, + 39370.936893046004, + 39389.719616674811, + 39408.504579674584, + 39427.291781511522, + 39446.081221652174, + 39464.872899563372, + 39483.666814712291, + 39502.462966566411, + 39521.261354593538, + 39540.06197826178, + 39558.864837039568, + 39577.669930395656, + 39596.47725779911, + 39615.286818719302, + 39634.098612625923, + 39652.912638988993, + 39671.728897278823, + 39690.547386966064, + 39709.368107521652, + 39728.191058416858, + 39747.016239123259, + 39765.84364911275, + 39784.673287857528, + 39803.505154830105, + 39822.339249503319, + 39841.175571350293, + 39860.014119844491, + 39878.854894459677, + 39897.697894669909, + 39916.54311994958, + 39935.390569773372, + 39954.240243616303, + 39973.092140953675, + 39991.946261261117, + 40010.802604014549, + 40029.661168690225, + 40048.521954764678, + 40067.384961714779, + 40086.250189017679, + 40105.117636150855, + 40123.98730259209, + 40142.859187819471, + 40161.733291311379, + 40180.609612546526, + 40199.488151003912, + 40218.368906162854, + 40237.25187750296, + 40256.137064504153, + 40275.024466646668, + 40293.914083411029, + 40312.805914278084, + 40331.699958728961, + 40350.596216245103, + 40369.494686308273, + 40388.39536840051, + 40407.298262004173, + 40426.20336660192, + 40445.110681676706, + 40464.020206711793, + 40482.931941190756, + 40501.845884597446, + 40520.762036416032, + 40539.680396130985, + 40558.600963227072, + 40577.523737189367, + 40596.448717503234, + 40615.375903654342, + 40634.305295128659, + 40653.236891412453, + 40672.170691992294, + 40691.106696355047, + 40710.044903987873, + 40728.985314378238, + 40747.927927013901, + 40766.872741382918, + 40785.819756973651, + 40804.768973274746, + 40823.720389775161, + 40842.674005964131, + 40861.629821331211, + 40880.587835366234, + 40899.548047559321, + 40918.510457400931, + 40937.475064381761, + 40956.441867992849, + 40975.410867725499, + 40994.382063071331, + 41013.355453522236, + 41032.331038570417, + 41051.308817708363, + 41070.288790428858, + 41089.270956224987, + 41108.255314590111, + 41127.241865017888, + 41146.23060700229, + 41165.221540037543, + 41184.214663618193, + 41203.209977239079, + 41222.207480395307, + 41241.207172582297, + 41260.209053295752, + 41279.213122031659, + 41298.219378286303, + 41317.227821556255, + 41336.23845133838, + 41355.251267129832, + 41374.266268428037, + 41393.283454730743, + 41412.302825535953, + 41431.324380341983, + 41450.348118647416, + 41469.374039951144, + 41488.402143752326, + 41507.432429550427, + 41526.464896845187, + 41545.499545136627, + 41564.536373925075, + 41583.575382711126, + 41602.616570995662, + 41621.659938279874, + 41640.705484065205, + 41659.753207853406, + 41678.803109146495, + 41697.855187446803, + 41716.909442256911, + 41735.965873079709, + 41755.02447941836, + 41774.085260776315, + 41793.148216657297, + 41812.213346565331, + 41831.280650004708, + 41850.350126480014, + 41869.421775496106, + 41888.495596558132, + 41907.571589171515, + 41926.649752841957, + 41945.730087075463, + 41964.812591378286, + 41983.897265256979, + 42002.984108218378, + 42022.073119769593, + 42041.164299418015, + 42060.257646671307, + 42079.353161037419, + 42098.450842024591, + 42117.550689141324, + 42136.652701896404, + 42155.756879798893, + 42174.863222358137, + 42193.971729083758, + 42213.082399485655, + 42232.195233074002, + 42251.310229359246, + 42270.427387852127, + 42289.546708063644, + 42308.668189505079, + 42327.791831687995, + 42346.917634124227, + 42366.045596325886, + 42385.175717805352, + 42404.307998075295, + 42423.442436648642, + 42442.579033038608, + 42461.717786758672, + 42480.858697322597, + 42500.001764244422, + 42519.146987038446, + 42538.294365219248, + 42557.443898301688, + 42576.595585800882, + 42595.749427232236, + 42614.90542211142, + 42634.063569954378, + 42653.223870277317, + 42672.386322596729, + 42691.55092642938, + 42710.717681292292, + 42729.886586702756, + 42749.057642178363, + 42768.23084723694, + 42787.406201396603, + 42806.58370417574, + 42825.76335509299, + 42844.945153667286, + 42864.129099417805, + 42883.315191864014, + 42902.503430525649, + 42921.693814922692, + 42940.88634457541, + 42960.081019004348, + 42979.277837730297, + 42998.476800274322, + 43017.677906157769, + 43036.881154902228, + 43056.086546029583, + 43075.294079061961, + 43094.503753521763, + 43113.715568931671, + 43132.929524814601, + 43152.145620693766, + 43171.363856092619, + 43190.584230534907, + 43209.806743544621, + 43229.031394646016, + 43248.258183363621, + 43267.487109222224, + 43286.718171746885, + 43305.951370462906, + 43325.186704895881, + 43344.42417457165, + 43363.663779016322, + 43382.905517756262, + 43402.149390318104, + 43421.395396228749, + 43440.643535015348, + 43459.89380620532, + 43479.146209326354, + 43498.400743906379, + 43517.657409473606, + 43536.916205556496, + 43556.177131683784, + 43575.44018738444, + 43594.705372187724, + 43613.972685623135, + 43633.242127220445, + 43652.513696509668, + 43671.787393021099, + 43691.063216285271, + 43710.341165833001, + 43729.621241195346, + 43748.903441903625, + 43768.187767489413, + 43787.474217484552, + 43806.762791421126, + 43826.053488831501, + 43845.346309248278, + 43864.641252204325, + 43883.938317232765, + 43903.237503866971, + 43922.538811640596, + 43941.842240087513, + 43961.147788741881, + 43980.455457138101, + 43999.765244810835, + 44019.077151295001, + 44038.391176125755, + 44057.70731883854, + 44077.02557896902, + 44096.345956053141, + 44115.668449627083, + 44134.993059227287, + 44154.319784390456, + 44173.648624653535, + 44192.979579553728, + 44212.312648628489, + 44231.647831415532, + 44250.985127452805, + 44270.324536278538, + 44289.666057431183, + 44309.009690449464, + 44328.355434872348, + 44347.703290239064, + 44367.053256089079, + 44386.405331962109, + 44405.759517398139, + 44425.115811937387, + 44444.474215120332, + 44463.834726487694, + 44483.197345580462, + 44502.562071939843, + 44521.928905107328, + 44541.297844624634, + 44560.668890033732, + 44580.042040876848, + 44599.417296696454, + 44618.794657035272, + 44638.174121436256, + 44657.555689442641, + 44676.939360597877, + 44696.325134445673, + 44715.713010530002, + 44735.102988395054, + 44754.495067585296, + 44773.88924764542, + 44793.285528120374, + 44812.683908555344, + 44832.084388495779, + 44851.486967487363, + 44870.891645076015, + 44890.298420807922, + 44909.707294229491, + 44929.118264887409, + 44948.531332328566, + 44967.946496100136, + 44987.363755749502, + 45006.783110824319, + 45026.204560872473, + 45045.628105442098, + 45065.053744081561, + 45084.48147633949, + 45103.911301764747, + 45123.343219906426, + 45142.777230313885, + 45162.21333253671, + 45181.651526124733, + 45201.091810628037, + 45220.534185596924, + 45239.978650581965, + 45259.425205133957, + 45278.873848803938, + 45298.324581143192, + 45317.777401703235, + 45337.232310035848, + 45356.68930569302, + 45376.148388226997, + 45395.60955719027, + 45415.072812135557, + 45434.538152615823, + 45454.005578184282, + 45473.475088394356, + 45492.946682799746, + 45512.420360954362, + 45531.896122412363, + 45551.373966728155, + 45570.853893456362, + 45590.33590215187, + 45609.819992369776, + 45629.306163665438, + 45648.794415594442, + 45668.284747712612, + 45687.777159576006, + 45707.27165074092, + 45726.768220763894, + 45746.266869201696, + 45765.767595611323, + 45785.270399550034, + 45804.775280575297, + 45824.282238244828, + 45843.79127211657, + 45863.302381748719, + 45882.815566699683, + 45902.33082652813, + 45921.848160792935, + 45941.367569053225, + 45960.889050868354, + 45980.41260579793, + 45999.938233401757, + 46019.465933239902, + 46038.995704872657, + 46058.527547860547, + 46078.06146176433, + 46097.597446144995, + 46117.135500563774, + 46136.675624582109, + 46156.217817761702, + 46175.762079664462, + 46195.308409852543, + 46214.856807888333, + 46234.407273334444, + 46253.959805753715, + 46273.51440470924, + 46293.071069764315, + 46312.629800482478, + 46332.190596427499, + 46351.753457163381, + 46371.318382254351, + 46390.885371264863, + 46410.45442375962, + 46430.025539303526, + 46449.598717461733, + 46469.17395779962, + 46488.751259882782, + 46508.33062327707, + 46527.912047548532, + 46547.495532263471, + 46567.081076988397, + 46586.668681290059, + 46606.258344735434, + 46625.850066891719, + 46645.443847326351, + 46665.039685606986, + 46684.637581301497, + 46704.237533978005, + 46723.839543204842, + 46743.443608550573, + 46763.049729583989, + 46782.657905874104, + 46802.268136990162, + 46821.880422501628, + 46841.494761978196, + 46861.111154989776, + 46880.729601106526, + 46900.350099898795, + 46919.97265093719, + 46939.597253792526, + 46959.223908035841, + 46978.852613238392, + 46998.483368971691, + 47018.11617480743, + 47037.751030317551, + 47057.387935074221, + 47077.026888649809, + 47096.66789061694, + 47116.310940548428, + 47135.956038017328, + 47155.603182596918, + 47175.252373860698, + 47194.903611382375, + 47214.556894735892, + 47234.212223495422, + 47253.869597235338, + 47273.52901553025, + 47293.19047795498, + 47312.853984084577, + 47332.519533494306, + 47352.187125759658, + 47371.856760456343, + 47391.528437160297, + 47411.202155447652, + 47430.877914894787, + 47450.555715078299, + 47470.235555574982, + 47489.917435961863, + 47509.601355816201, + 47529.287314715453, + 47548.975312237308, + 47568.665347959672, + 47588.357421460656, + 47608.051532318605, + 47627.747680112072, + 47647.445864419846, + 47667.14608482091, + 47686.848340894474, + 47706.552632219973, + 47726.258958377046, + 47745.967318945557, + 47765.677713505589, + 47785.390141637428, + 47805.104602921601, + 47824.821096938824, + 47844.539623270044, + 47864.260181496429, + 47883.982771199349, + 47903.707391960394, + 47923.434043361369, + 47943.162724984308, + 47962.893436411439, + 47982.626177225218, + 48002.36094700831, + 48022.097745343599, + 48041.836571814172, + 48061.57742600335, + 48081.32030749465, + 48101.065215871815, + 48120.81215071879, + 48140.56111161974, + 48160.312098159047, + 48180.065109921306, + 48199.820146491307, + 48219.577207454073, + 48239.336292394844, + 48259.097400899045, + 48278.860532552339, + 48298.625686940592, + 48318.392863649875, + 48338.162062266485, + 48357.933282376915, + 48377.706523567889, + 48397.481785426316, + 48417.259067539344, + 48437.038369494308, + 48456.819690878765, + 48476.603031280487, + 48496.388390287451, + 48516.175767487839, + 48535.965162470042, + 48555.756574822684, + 48575.550004134566, + 48595.345449994718, + 48615.142911992378, + 48634.942389716991, + 48654.743882758201, + 48674.547390705877, + 48694.352913150084, + 48714.160449681112, + 48733.969999889443, + 48753.781563365759, + 48773.595139700978, + 48793.410728486211, + 48813.228329312769, + 48833.047941772187, + 48852.869565456189, + 48872.693199956717, + 48892.518844865925, + 48912.346499776155, + 48932.176164279976, + 48952.007837970152, + 48971.841520439666, + 48991.677211281676, + 49011.514910089587, + 49031.354616456978, + 49051.196329977654, + 49071.04005024561, + 49090.885776855059, + 49110.733509400408, + 49130.583247476279, + 49150.434990677488, + 49170.288738599062, + 49190.144490836232, + 49210.002246984441, + 49229.86200663932, + 49249.723769396718, + 49269.587534852675, + 49289.453302603448, + 49309.32107224549, + 49329.190843375451, + 49349.062615590192, + 49368.936388486785, + 49388.812161662492, + 49408.689934714785, + 49428.569707241324, + 49448.45147883999, + 49468.335249108866, + 49488.22101764621, + 49508.108784050521, + 49527.99854792047, + 49547.890308854934, + 49567.784066453009, + 49587.679820313977, + 49607.57757003732, + 49627.477315222721, + 49647.379055470075, + 49667.28279037946, + 49687.188519551179, + 49707.096242585707, + 49727.005959083741, + 49746.917668646165, + 49766.831370874068, + 49786.747065368734, + 49806.66475173166, + 49826.584429564515, + 49846.506098469203, + 49866.429758047794, + 49886.355407902578, + 49906.283047636032, + 49926.212676850846, + 49946.144295149883, + 49966.077902136225, + 49986.013497413151, + 50005.951080584135, + 50025.890651252834, + 50045.832209023123, + 50065.775753499074, + 50085.721284284933, + 50105.668800985164, + 50125.618303204428, + 50145.569790547575, + 50165.523262619652, + 50185.478719025901, + 50205.436159371769, + 50225.395583262893, + 50245.356990305103, + 50265.320380104429, + 50285.285752267104, + 50305.253106399534, + 50325.222442108337, + 50345.193759000336, + 50365.16705668252, + 50385.142334762102, + 50405.119592846473, + 50425.098830543218, + 50445.080047460127, + 50465.063243205179, + 50485.048417386541, + 50505.035569612577, + 50525.024699491856, + 50545.015806633128, + 50565.008890645338, + 50585.003951137631, + 50605.00098771933, + 50624.999999999971, + 50645.000987589265, + 50665.003950097132, + 50685.008887133677, + 50705.015798309192, + 50725.024683234165, + 50745.035541519283, + 50765.048372775411, + 50785.063176613621, + 50805.079952645159, + 50825.098700481489, + 50845.119419734241, + 50865.142110015244, + 50885.166770936521, + 50905.193402110279, + 50925.222003148934, + 50945.252573665071, + 50965.285113271471, + 50985.319621581119, + 51005.356098207172, + 51025.394542762981, + 51045.434954862096, + 51065.477334118244, + 51085.521680145357, + 51105.567992557546, + 51125.616270969113, + 51145.66651499454, + 51165.718724248516, + 51185.772898345916, + 51205.829036901778, + 51225.887139531362, + 51245.947205850105, + 51266.009235473619, + 51286.073228017718, + 51306.139183098399, + 51326.207100331856, + 51346.276979334456, + 51366.348819722756, + 51386.42262111351, + 51406.498383123653, + 51426.57610537031, + 51446.655787470787, + 51466.737429042587, + 51486.82102970338, + 51506.906589071048, + 51526.994106763632, + 51547.083582399391, + 51567.175015596738, + 51587.268405974297, + 51607.363753150858, + 51627.461056745415, + 51647.56031637713, + 51667.661531665362, + 51687.764702229651, + 51707.869827689727, + 51727.976907665499, + 51748.085941777055, + 51768.196929644677, + 51788.309870888836, + 51808.42476513017, + 51828.541611989524, + 51848.660411087905, + 51868.781162046515, + 51888.90386448674, + 51909.028518030143, + 51929.155122298485, + 51949.283676913685, + 51969.414181497872, + 51989.546635673345, + 52009.681039062583, + 52029.817391288263, + 52049.955691973213, + 52070.095940740481, + 52090.238137213273, + 52110.382281014987, + 52130.5283717692, + 52150.676409099666, + 52170.826392630333, + 52190.97832198532, + 52211.132196788931, + 52231.288016665654, + 52251.445781240145, + 52271.60549013727, + 52291.76714298204, + 52311.930739399664, + 52332.096279015546, + 52352.263761455244, + 52372.433186344519, + 52392.604553309284, + 52412.777861975665, + 52432.953111969946, + 52453.130302918595, + 52473.309434448267, + 52493.490506185793, + 52513.67351775818, + 52533.858468792605, + 52554.045358916446, + 52574.234187757254, + 52594.42495494274, + 52614.617660100812, + 52634.812302859558, + 52655.008882847229, + 52675.20739969227, + 52695.407853023295, + 52715.610242469098, + 52735.814567658657, + 52756.02082822111, + 52776.229023785803, + 52796.439153982225, + 52816.651218440056, + 52836.865216789171, + 52857.081148659599, + 52877.29901368155, + 52897.518811485425, + 52917.740541701773, + 52937.964203961354, + 52958.18979789508, + 52978.417323134046, + 52998.646779309529, + 53018.878166052978, + 53039.111482996006, + 53059.346729770419, + 53079.583906008193, + 53099.823011341483, + 53120.0640454026, + 53140.307007824063, + 53160.551898238533, + 53180.79871627887, + 53201.047461578091, + 53221.2981337694, + 53241.550732486176, + 53261.805257361964, + 53282.061708030487, + 53302.32008412564, + 53322.580385281493, + 53342.842611132299, + 53363.106761312469, + 53383.372835456597, + 53403.640833199453, + 53423.910754175973, + 53444.18259802126, + 53464.456364370613, + 53484.732052859479, + 53505.009663123499, + 53525.289194798468, + 53545.570647520362, + 53565.854020925333, + 53586.139314649699, + 53606.426528329954, + 53626.715661602764, + 53647.006714104959, + 53667.299685473547, + 53687.59457534572, + 53707.891383358816, + 53728.190109150361, + 53748.490752358055, + 53768.793312619753, + 53789.09778957349, + 53809.404182857485, + 53829.712492110106, + 53850.022716969899, + 53870.334857075584, + 53890.648912066055, + 53910.964881580367, + 53931.28276525774, + 53951.602562737586, + 53971.924273659461, + 53992.24789766311, + 54012.57343438844, + 54032.90088347553, + 54053.23024456462, + 54073.561517296133, + 54093.894701310644, + 54114.22979624891, + 54134.566801751855, + 54154.90571746057, + 54175.246543016314, + 54195.589278060506, + 54215.933922234755, + 54236.280475180814, + 54256.628936540626, + 54276.97930595628, + 54297.331583070045, + 54317.685767524359, + 54338.041858961828, + 54358.399857025215, + 54378.759761357462, + 54399.121571601667, + 54419.485287401105, + 54439.850908399218, + 54460.218434239614, + 54480.587864566056, + 54500.95919902248, + 54521.332437252997, + 54541.707578901878, + 54562.084623613555, + 54582.46357103264, + 54602.844420803893, + 54623.227172572246, + 54643.611825982807, + 54663.998380680838, + 54684.386836311773, + 54704.777192521207, + 54725.169448954897, + 54745.563605258772, + 54765.959661078923, + 54786.357616061614, + 54806.757469853255, + 54827.159222100439, + 54847.562872449904, + 54867.968420548583, + 54888.375866043534, + 54908.785208582012, + 54929.196447811417, + 54949.609583379322, + 54970.024614933463, + 54990.441542121727, + 55010.86036459219, + 55031.28108199306, + 55051.703693972733, + 55072.128200179759, + 55092.554600262847, + 55112.982893870874, + 55133.413080652877, + 55153.845160258061, + 55174.279132335789, + 55194.714996535586, + 55215.152752507143, + 55235.592399900306, + 55256.033938365079, + 55276.477367551655, + 55296.92268711036, + 55317.369896691685, + 55337.818995946305, + 55358.269984525024, + 55378.72286207883, + 55399.177628258869, + 55419.634282716441, + 55440.092825103013, + 55460.553255070205, + 55481.015572269804, + 55501.479776353764, + 55521.945866974187, + 55542.413843783339, + 55562.883706433655, + 55583.355454577715, + 55603.82908786826, + 55624.304605958219, + 55644.782008500639, + 55665.261295148754, + 55685.742465555952, + 55706.225519375774, + 55726.710456261928, + 55747.197275868275, + 55767.685977848843, + 55788.176561857814, + 55808.669027549528, + 55829.163374578478, + 55849.659602599328, + 55870.157711266889, + 55890.657700236145, + 55911.159569162221, + 55931.663317700411, + 55952.168945506164, + 55972.676452235086, + 55993.185837542944, + 56013.697101085651, + 56034.210242519301, + 56054.72526150012, + 56075.242157684508, + 56095.760930729011, + 56116.281580290342, + 56136.804106025367, + 56157.328507591104, + 56177.85478464474, + 56198.382936843598, + 56218.912963845185, + 56239.444865307138, + 56259.978640887268, + 56280.514290243525, + 56301.051813034042, + 56321.591208917082, + 56342.13247755108, + 56362.675618594607, + 56383.220631706419, + 56403.767516545398, + 56424.316272770608, + 56444.866900041241, + 56465.419398016667, + 56485.973766356394, + 56506.530004720102, + 56527.088112767611, + 56547.648090158902, + 56568.209936554107, + 56588.773651613519, + 56609.339234997584, + 56629.9066863669, + 56650.47600538221, + 56671.04719170442, + 56691.620244994599, + 56712.195164913959, + 56732.771951123868, + 56753.350603285835, + 56773.931121061541, + 56794.513504112823, + 56815.097752101647, + 56835.683864690152, + 56856.271841540627, + 56876.86168231551, + 56897.453386677393, + 56918.046954289028, + 56938.642384813298, + 56959.239677913261, + 56979.838833252121, + 57000.439850493225, + 57021.04272930009, + 57041.647469336371, + 57062.254070265873, + 57082.862531752558, + 57103.472853460553, + 57124.085035054108, + 57144.699076197649, + 57165.314976555739, + 57185.932735793103, + 57206.552353574611, + 57227.173829565276, + 57247.797163430281, + 57268.42235483494, + 57289.049403444733, + 57309.678308925286, + 57330.30907094237, + 57350.941689161911, + 57371.576163249985, + 57392.212492872815, + 57412.850677696784, + 57433.490717388406, + 57454.132611614368, + 57474.776360041491, + 57495.421962336746, + 57516.069418167266, + 57536.718727200314, + 57557.36988910332, + 57578.022903543861, + 57598.677770189643, + 57619.334488708548, + 57639.993058768589, + 57660.653480037938, + 57681.315752184906, + 57701.979874877965, + 57722.64584778573, + 57743.31367057695, + 57763.983342920546, + 57784.654864485572, + 57805.328234941233, + 57826.003453956881, + 57846.680521202026, + 57867.359436346305, + 57888.040199059527, + 57908.722809011633, + 57929.407265872709, + 57950.093569313001, + 57970.781719002895, + 57991.471714612911, + 58012.16355581375, + 58032.857242276223, + 58053.552773671312, + 58074.25014967013, + 58094.949369943948, + 58115.650434164185, + 58136.353342002389, + 58157.058093130276, + 58177.764687219693, + 58198.47312394264, + 58219.183402971255, + 58239.895523977837, + 58260.609486634821, + 58281.325290614775, + 58302.042935590434, + 58322.762421234678, + 58343.483747220511, + 58364.206913221096, + 58384.931918909751, + 58405.658763959924, + 58426.3874480452, + 58447.117970839339, + 58467.85033201622, + 58488.584531249864, + 58509.320568214462, + 58530.058442584334, + 58550.798154033931, + 58571.539702237875, + 58592.283086870906, + 58613.028307607929, + 58633.775364123983, + 58654.52425609425, + 58675.274983194053, + 58696.027545098877, + 58716.781941484325, + 58737.538172026158, + 58758.296236400274, + 58779.056134282728, + 58799.817865349694, + 58820.581429277503, + 58841.346825742643, + 58862.114054421712, + 58882.883114991484, + 58903.654007128847, + 58924.426730510851, + 58945.201284814684, + 58965.977669717664, + 58986.755884897269, + 59007.535930031117, + 59028.317804796949, + 59049.101508872664, + 59069.887041936301, + 59090.674403666046, + 59111.463593740213, + 59132.254611837263, + 59153.047457635803, + 59173.84213081457, + 59194.638631052461, + 59215.436958028506, + 59236.237111421855, + 59257.039090911829, + 59277.842896177877, + 59298.648526899589, + 59319.455982756685, + 59340.26526342905, + 59361.076368596696, + 59381.889297939757, + 59402.704051138542, + 59423.520627873484, + 59444.339027825139, + 59465.159250674224, + 59485.9812961016, + 59506.805163788253, + 59527.630853415307, + 59548.458364664046, + 59569.287697215863, + 59590.118850752311, + 59610.951824955089, + 59631.786619506012, + 59652.623234087048, + 59673.461668380311, + 59694.301922068029, + 59715.143994832593, + 59735.987886356525, + 59756.833596322482, + 59777.681124413255, + 59798.530470311794, + 59819.381633701159, + 59840.234614264569, + 59861.089411685381, + 59881.94602564707, + 59902.804455833269, + 59923.664701927737, + 59944.526763614384, + 59965.390640577243, + 59986.256332500488, + 60007.123839068438, + 60027.993159965539, + 60048.864294876381, + 60069.737243485688, + 60090.612005478324, + 60111.488580539284, + 60132.366968353708, + 60153.247168606867, + 60174.129180984164, + 60195.013005171153, + 60215.898640853513, + 60236.786087717061, + 60257.675345447751, + 60278.566413731671, + 60299.459292255044, + 60320.353980704247, + 60341.25047876576, + 60362.148786126229, + 60383.048902472423, + 60403.950827491237, + 60424.854560869717, + 60445.76010229504, + 60466.667451454516, + 60487.57660803559, + 60508.487571725847, + 60529.400342212997, + 60550.314919184893, + 60571.231302329521, + 60592.149491335003, + 60613.069485889588, + 60633.991285681674, + 60654.914890399785, + 60675.840299732568, + 60696.767513368832, + 60717.696530997484, + 60738.627352307602, + 60759.55997698837, + 60780.494404729128, + 60801.430635219323, + 60822.368668148556, + 60843.308503206565, + 60864.250140083204, + 60885.193578468468, + 60906.138818052495, + 60927.085858525541, + 60948.034699578006, + 60968.985340900421, + 60989.937782183442, + 61010.892023117864, + 61031.848063394616, + 61052.805902704764, + 61073.765540739492, + 61094.726977190134, + 61115.690211748137, + 61136.655244105103, + 61157.622073952742, + 61178.590700982917, + 61199.561124887616, + 61220.533345358948, + 61241.507362089171, + 61262.483174770663, + 61283.460783095943, + 61304.440186757645, + 61325.421385448557, + 61346.404378861582, + 61367.389166689762, + 61388.375748626262, + 61409.364124364387, + 61430.354293597571, + 61451.346256019373, + 61472.340011323497, + 61493.335559203762, + 61514.332899354122, + 61535.332031468672, + 61556.332955241618, + 61577.335670367313, + 61598.340176540238, + 61619.346473454993, + 61640.354560806329, + 61661.3644382891, + 61682.376105598312, + 61703.389562429089, + 61724.404808476691, + 61745.42184343651, + 61766.440667004063, + 61787.461278874987, + 61808.483678745069, + 61829.507866310203, + 61850.533841266435, + 61871.561603309929, + 61892.591152136971, + 61913.622487443987, + 61934.655608927525, + 61955.690516284267, + 61976.727209211022, + 61997.765687404724, + 62018.805950562448, + 62039.847998381381, + 62060.891830558845, + 62081.93744679229, + 62102.984846779298, + 62124.034030217575, + 62145.084996804966, + 62166.137746239416, + 62187.19227821903, + 62208.248592442025, + 62229.306688606739, + 62250.366566411656, + 62271.428225555377, + 62292.491665736627, + 62313.556886654267, + 62334.623888007271, + 62355.692669494762, + 62376.763230815974, + 62397.835571670272, + 62418.909691757144, + 62439.98559077621, + 62461.063268427228, + 62482.142724410049, + 62503.223958424685, + 62524.306970171267, + 62545.39175935003, + 62566.478325661366, + 62587.566668805768, + 62608.656788483881, + 62629.748684396451, + 62650.842356244357, + 62671.937803728622, + 62693.035026550366, + 62714.134024410858, + 62735.234797011479, + 62756.337344053733, + 62777.441665239276, + 62798.547760269852, + 62819.655628847358, + 62840.765270673801, + 62861.876685451323, + 62882.989872882186, + 62904.104832668774, + 62925.221564513602, + 62946.340068119309, + 62967.460343188657, + 62988.582389424526, + 63009.70620652994, + 63030.831794208025, + 63051.959152162039, + 63073.08828009537, + 63094.219177711529, + 63115.351844714154, + 63136.486280806988, + 63157.622485693922, + 63178.760459078956, + 63199.900200666219, + 63221.041710159967, + 63242.184987264569, + 63263.330031684534, + 63284.476843124474, + 63305.625421289144, + 63326.775765883409, + 63347.927876612259, + 63369.081753180813, + 63390.237395294316, + 63411.39480265812, + 63432.553974977716, + 63453.714911958712, + 63474.877613306839, + 63496.042078727944, + 63517.208307927998, + 63538.376300613119, + 63559.546056489504, + 63580.717575263516, + 63601.890856641607, + 63623.065900330374, + 63644.242706036515, + 63665.421273466869, + 63686.601602328381, + 63707.783692328136, + 63728.967543173334, + 63750.153154571279, + 63771.340526229418, + 63792.529657855317, + 63813.720549156649, + 63834.913199841227, + 63856.107609616978, + 63877.303778191941, + 63898.501705274284, + 63919.7013905723, + 63940.902833794404, + 63962.106034649114, + 63983.310992845094, + 64004.517708091109, + 64025.726180096048, + 64046.936408568938, + 64068.1483932189, + 64089.362133755196, + 64110.577629887193, + 64131.794881324393, + 64153.013887776404, + 64174.234648952966, + 64195.457164563937, + 64216.681434319289, + 64237.907457929112, + 64259.135235103626, + 64280.36476555316, + 64301.596048988169, + 64322.829085119236, + 64344.06387365704, + 64365.300414312398, + 64386.538706796251, + 64407.778750819634, + 64429.020546093721, + 64450.26409232981, + 64471.509389239291, + 64492.756436533709, + 64514.005233924705, + 64535.255781124033, + 64556.50807784358, + 64577.762123795357, + 64599.017918691468, + 64620.275462244172, + 64641.534754165805, + 64662.795794168844, + 64684.058581965895, + 64705.323117269661, + 64726.589399792974, + 64747.857429248776, + 64769.127205350138, + 64790.398727810236, + 64811.671996342375, + 64832.947010659969, + 64854.223770476558, + 64875.502275505794, + 64896.782525461451, + 64918.064520057414, + 64939.348259007682, + 64960.633742026388, + 64981.920968827762, + 65003.209939126165, + 65024.500652636067, + 65045.793109072067, + 65067.087308148861, + 65088.383249581282, + 65109.680933084259, + 65130.980358372864, + 65152.28152516226, + 65173.584433167736, + 65194.889082104703, + 65216.195471688683, + 65237.503601635319, + 65258.813471660353, + 65280.125081479666, + 65301.438430809241, + 65322.753519365178, + 65344.070346863708, + 65365.388913021146, + 65386.709217553958, + 65408.031260178701, + 65429.355040612056, + 65450.680558570821, + 65472.00781377191, + 65493.336805932355, + 65514.66753476928, + 65535.999999999956, + 65557.334201341757, + 65578.670138512171, + 65600.007811228788, + 65621.347219209332, + 65642.688362171626, + 65664.031239833639, + 65685.375851913413, + 65706.722198129137, + 65728.070278199084, + 65749.420091841661, + 65770.771638775404, + 65792.124918718939, + 65813.479931391004, + 65834.836676510458, + 65856.195153796303, + 65877.5553629676, + 65898.917303743554, + 65920.280975843489, + 65941.646378986843, + 65963.013512893158, + 65984.382377282076, + 66005.752971873386, + 66027.125296386963, + 66048.499350542799, + 66069.875134061018, + 66091.252646661844, + 66112.631888065618, + 66134.01285799277, + 66155.395556163887, + 66176.779982299631, + 66198.166136120795, + 66219.554017348273, + 66240.943625703105, + 66262.334960906388, + 66283.728022679396, + 66305.122810743444, + 66326.519324820023, + 66347.917564630698, + 66369.317529897162, + 66390.719220341227, + 66412.122635684791, + 66433.527775649884, + 66454.934639958636, + 66476.343228333324, + 66497.753540496284, + 66519.165576169995, + 66540.57933507704, + 66561.994816940118, + 66583.412021482043, + 66604.830948425733, + 66626.251597494222, + 66647.673968410629, + 66669.098060898235, + 66690.523874680381, + 66711.951409480564, + 66733.380665022371, + 66754.811641029475, + 66776.244337225711, + 66797.678753334985, + 66819.11488908132, + 66840.552744188884, + 66861.992318381905, + 66883.433611384738, + 66904.876622921889, + 66926.321352717903, + 66947.767800497502, + 66969.215965985466, + 66990.665848906734, + 67012.117448986304, + 67033.570765949335, + 67055.025799521056, + 67076.482549426815, + 67097.941015392076, + 67119.401197142433, + 67140.863094403554, + 67162.326706901222, + 67183.792034361351, + 67205.259076509959, + 67226.72783307315, + 67248.198303777172, + 67269.670488348347, + 67291.144386513144, + 67312.619997998088, + 67334.09732252988, + 67355.576359835293, + 67377.057109641188, + 67398.53957167457, + 67420.023745662547, + 67441.50963133233, + 67462.99722841123, + 67484.486536626689, + 67505.977555706224, + 67527.470285377494, + 67548.964725368263, + 67570.460875406367, + 67591.9587352198, + 67613.458304536631, + 67634.95958308503, + 67656.462570593329, + 67677.967266789899, + 67699.473671403248, + 67720.981784162024, + 67742.491604794923, + 67764.003133030797, + 67785.516368598575, + 67807.031311227314, + 67828.547960646174, + 67850.066316584402, + 67871.58637877139, + 67893.108146936589, + 67914.63162080961, + 67936.156800120138, + 67957.683684597971, + 67979.212273973011, + 68000.742567975263, + 68022.274566334876, + 68043.808268782057, + 68065.343675047145, + 68086.880784860579, + 68108.419597952918, + 68129.960114054789, + 68151.502332896969, + 68173.04625421032, + 68194.591877725834, + 68216.139203174564, + 68237.688230287706, + 68259.238958796544, + 68280.791388432481, + 68302.345518927032, + 68323.901350011787, + 68345.458881418483, + 68367.018112878912, + 68388.579044125028, + 68410.141674888844, + 68431.706004902502, + 68453.272033898262, + 68474.839761608455, + 68496.409187765545, + 68517.980312102081, + 68539.553134350732, + 68561.127654244279, + 68582.70387151558, + 68604.281785897634, + 68625.861397123503, + 68647.44270492639, + 68669.025709039604, + 68690.610409196524, + 68712.196805130661, + 68733.784896575627, + 68755.374683265123, + 68776.966164932994, + 68798.559341313128, + 68820.154212139591, + 68841.750777146473, + 68863.349036068044, + 68884.948988638629, + 68906.550634592684, + 68928.153973664739, + 68949.75900558944, + 68971.365730101577, + 68992.974146935987, + 69014.584255827634, + 69036.196056511588, + 69057.809548723017, + 69079.424732197207, + 69101.041606669532, + 69122.660171875468, + 69144.280427550606, + 69165.902373430625, + 69187.526009251334, + 69209.151334748618, + 69230.778349658474, + 69252.40705371699, + 69274.037446660412, + 69295.669528225, + 69317.303298147192, + 69338.938756163494, + 69360.575902010532, + 69382.214735425005, + 69403.855256143754, + 69425.497463903681, + 69447.141358441833, + 69468.78693949533, + 69490.434206801394, + 69512.083160097391, + 69533.733799120717, + 69555.386123608929, + 69577.04013329967, + 69598.695827930685, + 69620.353207239794, + 69642.012270964973, + 69663.67301884426, + 69685.335450615792, + 69706.999566017839, + 69728.665364788743, + 69750.332846666963, + 69772.002011391058, + 69793.672858699691, + 69815.345388331611, + 69837.019600025669, + 69858.695493520849, + 69880.373068556204, + 69902.052324870907, + 69923.733262204216, + 69945.415880295492, + 69967.100178884211, + 69988.786157709939, + 70010.473816512356, + 70032.163155031216, + 70053.854173006403, + 70075.546870177874, + 70097.241246285717, + 70118.937301070109, + 70140.635034271298, + 70162.334445629691, + 70184.035534885741, + 70205.738301780017, + 70227.442746053217, + 70249.1488674461, + 70270.856665699539, + 70292.566140554511, + 70314.277291752107, + 70335.990119033493, + 70357.704622139936, + 70379.420800812819, + 70401.138654793613, + 70422.85818382389, + 70444.579387645339, + 70466.302265999722, + 70488.026818628918, + 70509.753045274876, + 70531.480945679708, + 70553.210519585555, + 70574.941766734701, + 70596.674686869505, + 70618.409279732456, + 70640.145545066101, + 70661.883482613106, + 70683.623092116264, + 70705.364373318414, + 70727.107325962526, + 70748.851949791671, + 70770.598244549008, + 70792.346209977783, + 70814.095845821372, + 70835.847151823225, + 70857.600127726895, + 70879.354773276034, + 70901.111088214413, + 70922.869072285859, + 70944.628725234332, + 70966.390046803877, + 70988.153036738629, + 71009.917694782853, + 71031.684020680885, + 71053.45201417715, + 71075.221675016204, + 71096.993002942661, + 71118.765997701266, + 71140.540659036851, + 71162.316986694335, + 71184.09498041874, + 71205.874639955218, + 71227.655965048951, + 71249.438955445294, + 71271.223610889632, + 71293.009931127483, + 71314.797915904477, + 71336.587564966307, + 71358.378878058764, + 71380.171854927772, + 71401.966495319313, + 71423.762798979486, + 71445.560765654489, + 71467.360395090596, + 71489.161687034211, + 71510.964641231811, + 71532.769257429973, + 71554.575535375348, + 71576.383474814749, + 71598.19307549503, + 71620.004337163133, + 71641.817259566145, + 71663.631842451214, + 71685.4480855656, + 71707.26598865664, + 71729.085551471784, + 71750.906773758586, + 71772.729655264673, + 71794.554195737772, + 71816.380394925713, + 71838.208252576442, + 71860.037768437964, + 71881.868942258385, + 71903.701773785942, + 71925.536262768932, + 71947.372408955751, + 71969.210212094898, + 71991.049671934976, + 72012.890788224686, + 72034.73356071279, + 72056.577989148165, + 72078.424073279821, + 72100.271812856794, + 72122.121207628254, + 72143.97225734347, + 72165.824961751801, + 72187.679320602692, + 72209.53533364569, + 72231.393000630429, + 72253.252321306645, + 72275.113295424177, + 72296.975922732949, + 72318.840202982959, + 72340.706135924338, + 72362.573721307272, + 72384.442958882093, + 72406.313848399179, + 72428.186389609036, + 72450.060582262216, + 72471.936426109431, + 72493.813920901433, + 72515.693066389096, + 72537.573862323392, + 72559.456308455352, + 72581.340404536139, + 72603.226150316987, + 72625.113545549248, + 72647.002589984331, + 72668.893283373764, + 72690.785625469172, + 72712.679616022273, + 72734.575254784853, + 72756.472541508803, + 72778.371475946144, + 72800.272057848939, + 72822.174286969355, + 72844.07816305969, + 72865.983685872285, + 72887.890855159596, + 72909.799670674183, + 72931.710132168693, + 72953.622239395845, + 72975.535992108475, + 72997.451390059519, + 73019.368433001961, + 73041.287120688925, + 73063.207452873612, + 73085.129429309294, + 73107.053049749389, + 73128.978313947344, + 73150.905221656736, + 73172.833772631217, + 73194.763966624567, + 73216.695803390612, + 73238.62928268328, + 73260.564404256627, + 73282.501167864757, + 73304.439573261901, + 73326.379620202337, + 73348.321308440485, + 73370.264637730841, + 73392.209607827957, + 73414.156218486532, + 73436.104469461323, + 73458.054360507173, + 73480.005891379056, + 73501.959061831993, + 73523.913871621116, + 73545.870320501665, + 73567.828408228932, + 73589.78813455833, + 73611.749499245358, + 73633.712502045615, + 73655.677142714747, + 73677.643421008557, + 73699.611336682879, + 73721.580889493693, + 73743.552079197019, + 73765.524905548999, + 73787.499368305856, + 73809.475467223907, + 73831.453202059551, + 73853.432572569291, + 73875.413578509717, + 73897.396219637507, + 73919.380495709411, + 73941.36640648231, + 73963.353951713143, + 73985.343131158952, + 74007.333944576865, + 74029.326391724098, + 74051.320472357969, + 74073.316186235883, + 74095.313533115303, + 74117.312512753837, + 74139.313124909138, + 74161.315369338976, + 74183.319245801191, + 74205.324754053727, + 74227.331893854629, + 74249.340664961986, + 74271.351067134034, + 74293.363100129049, + 74315.376763705441, + 74337.392057621662, + 74359.408981636298, + 74381.427535508003, + 74403.447718995507, + 74425.469531857671, + 74447.492973853383, + 74469.518044741693, + 74491.54474428168, + 74513.573072232539, + 74535.603028353551, + 74557.634612404087, + 74579.667824143602, + 74601.702663331642, + 74623.739129727837, + 74645.777223091936, + 74667.816943183716, + 74689.858289763113, + 74711.901262590094, + 74733.945861424741, + 74755.992086027225, + 74778.039936157802, + 74800.089411576817, + 74822.140512044702, + 74844.193237321961, + 74866.24758716923, + 74888.303561347187, + 74910.36115961663, + 74932.420381738411, + 74954.481227473516, + 74976.543696582972, + 74998.607788827925, + 75020.673503969607, + 75042.740841769322, + 75064.809801988464, + 75086.88038438854, + 75108.952588731103, + 75131.026414777836, + 75153.101862290467, + 75175.178931030852, + 75197.257620760924, + 75219.33793124267, + 75241.419862238225, + 75263.503413509738, + 75285.588584819503, + 75307.675375929874, + 75329.763786603318, + 75351.853816602365, + 75373.945465689612, + 75396.038733627807, + 75418.133620179724, + 75440.230125108254, + 75462.32824817636, + 75484.427989147109, + 75506.529347783653, + 75528.63232384919, + 75550.736917107075, + 75572.843127320695, + 75594.950954253538, + 75617.060397669193, + 75639.171457331307, + 75661.284133003646, + 75683.398424450032, + 75705.514331434402, + 75727.631853720741, + 75749.750991073175, + 75771.871743255862, + 75793.994110033076, + 75816.118091169177, + 75838.243686428585, + 75860.370895575848, + 75882.499718375562, + 75904.630154592422, + 75926.762203991224, + 75948.895866336825, + 75971.031141394182, + 75993.168028928325, + 76015.306528704401, + 76037.4466404876, + 76059.588364043215, + 76081.731699136653, + 76103.876645533353, + 76126.023202998884, + 76148.171371298871, + 76170.321150199044, + 76192.472539465205, + 76214.625538863256, + 76236.780148159174, + 76258.936367119008, + 76281.094195508922, + 76303.253633095141, + 76325.414679643975, + 76347.577334921851, + 76369.741598695226, + 76391.907470730686, + 76414.074950794879, + 76436.244038654564, + 76458.414734076548, + 76480.587036827754, + 76502.760946675175, + 76524.936463385893, + 76547.11358672705, + 76569.292316465915, + 76591.472652369819, + 76613.654594206164, + 76635.838141742468, + 76658.023294746308, + 76680.210052985349, + 76702.398416227341, + 76724.588384240138, + 76746.779956791637, + 76768.973133649866, + 76791.167914582897, + 76813.364299358902, + 76835.562287746157, + 76857.761879512967, + 76879.963074427797, + 76902.165872259109, + 76924.37027277553, + 76946.576275745727, + 76968.783880938441, + 76990.993088122515, + 77013.203897066895, + 77035.416307540567, + 77057.630319312622, + 77079.845932152239, + 77102.063145828695, + 77124.281960111301, + 77146.50237476948, + 77168.724389572759, + 77190.948004290723, + 77213.173218693031, + 77235.400032549442, + 77257.628445629802, + 77279.858457704031, + 77302.090068542122, + 77324.323277914169, + 77346.558085590339, + 77368.794491340886, + 77391.032494936138, + 77413.272096146524, + 77435.51329474253, + 77457.756090494731, + 77480.000483173804, + 77502.246472550498, + 77524.494058395634, + 77546.743240480107, + 77568.994018574944, + 77591.246392451198, + 77613.500361880026, + 77635.755926632657, + 77658.013086480438, + 77680.271841194757, + 77702.532190547092, + 77724.794134309021, + 77747.057672252195, + 77769.322804148323, + 77791.589529769248, + 77813.857848886837, + 77836.127761273063, + 77858.399266699998, + 77880.67236493979, + 77902.947055764627, + 77925.223338946831, + 77947.50121425878, + 77969.780681472927, + 77992.061740361838, + 78014.344390698127, + 78036.628632254491, + 78058.914464803747, + 78081.201888118725, + 78103.490901972415, + 78125.781506137821, + 78148.073700388064, + 78170.367484496339, + 78192.662858235926, + 78214.959821380166, + 78237.258373702498, + 78259.558514976452, + 78281.860244975614, + 78304.163563473659, + 78326.468470244363, + 78348.77496506153, + 78371.083047699125, + 78393.392717931114, + 78415.703975531578, + 78438.016820274701, + 78460.331251934695, + 78482.647270285903, + 78504.964875102727, + 78527.284066159627, + 78549.604843231195, + 78571.927206092048, + 78594.251154516911, + 78616.576688280606, + 78638.903807157985, + 78661.232510924034, + 78683.562799353778, + 78705.894672222363, + 78728.228129304945, + 78750.563170376859, + 78772.899795213423, + 78795.238003590101, + 78817.577795282399, + 78839.919170065928, + 78862.262127716356, + 78884.606668009452, + 78906.952790721043, + 78929.300495627045, + 78951.64978250346, + 78974.000651126378, + 78996.353101271932, + 79018.707132716358, + 79041.062745235977, + 79063.41993860717, + 79085.778712606436, + 79108.139067010285, + 79130.501001595389, + 79152.864516138419, + 79175.22961041618, + 79197.596284205531, + 79219.96453728342, + 79242.33436942687, + 79264.705780412987, + 79287.078770018954, + 79309.453338022009, + 79331.829484199508, + 79354.207208328866, + 79376.586510187582, + 79398.967389553218, + 79421.349846203433, + 79443.733879915948, + 79466.119490468584, + 79488.50667763922, + 79510.895441205823, + 79533.285780946433, + 79555.677696639163, + 79578.071188062226, + 79600.466254993895, + 79622.862897212515, + 79645.261114496549, + 79667.660906624471, + 79690.062273374875, + 79712.465214526455, + 79734.869729857935, + 79757.275819148126, + 79779.683482175955, + 79802.092718720378, + 79824.503528560454, + 79846.915911475327, + 79869.329867244203, + 79891.745395646343, + 79914.162496461155, + 79936.581169468045, + 79959.001414446553, + 79981.423231176261, + 80003.846619436852, + 80026.271579008084, + 80048.698109669771, + 80071.12621120183, + 80093.555883384237, + 80115.987125997053, + 80138.419938820414, + 80160.854321634528, + 80183.290274219689, + 80205.727796356281, + 80228.166887824715, + 80250.607548405547, + 80273.049777879336, + 80295.493576026798, + 80317.938942628651, + 80340.385877465727, + 80362.834380318949, + 80385.28445096928, + 80407.736089197788, + 80430.189294785596, + 80452.644067513917, + 80475.100407164035, + 80497.558313517322, + 80520.017786355209, + 80542.478825459213, + 80564.941430610925, + 80587.405601592007, + 80609.871338184195, + 80632.338640169342, + 80654.8075073293, + 80677.277939446067, + 80699.749936301683, + 80722.223497678278, + 80744.698623358039, + 80767.17531312324, + 80789.653566756242, + 80812.133384039465, + 80834.614764755403, + 80857.097708686648, + 80879.582215615854, + 80902.068285325731, + 80924.555917599093, + 80947.045112218824, + 80969.535868967869, + 80992.028187629272, + 81014.522067986123, + 81037.017509821613, + 81059.514512919006, + 81082.013077061609, + 81104.513202032831, + 81127.014887616184, + 81149.518133595193, + 81172.022939753486, + 81194.529305874807, + 81217.037231742899, + 81239.546717141639, + 81262.057761854958, + 81284.570365666848, + 81307.084528361403, + 81329.600249722775, + 81352.117529535186, + 81374.636367582949, + 81397.156763650448, + 81419.678717522125, + 81442.202228982511, + 81464.727297816222, + 81487.253923807933, + 81509.782106742379, + 81532.311846404409, + 81554.843142578902, + 81577.375995050839, + 81599.910403605274, + 81622.446368027333, + 81644.983888102215, + 81667.522963615178, + 81690.063594351581, + 81712.605780096841, + 81735.149520636449, + 81757.694815755967, + 81780.241665241047, + 81802.79006887741, + 81825.340026450824, + 81847.891537747171, + 81870.444602552379, + 81892.999220652477, + 81915.555391833506, + 81938.113115881672, + 81960.672392583176, + 81983.233221724338, + 82005.795603091537, + 82028.359536471224, + 82050.925021649906, + 82073.492058414209, + 82096.060646550788, + 82118.630785846399, + 82141.202476087841, + 82163.775717062032, + 82186.35050855593, + 82208.926850356569, + 82231.504742251054, + 82254.084184026578, + 82276.665175470393, + 82299.24771636985, + 82321.831806512317, + 82344.417445685307, + 82367.004633676348, + 82389.593370273054, + 82412.183655263143, + 82434.775488434374, + 82457.368869574595, + 82479.963798471697, + 82502.560274913689, + 82525.158298688606, + 82547.757869584602, + 82570.35898738986, + 82592.961651892678, + 82615.565862881398, + 82638.171620144421, + 82660.778923470265, + 82683.387772647475, + 82705.998167464713, + 82728.610107710658, + 82751.223593174116, + 82773.83862364394, + 82796.45519890904, + 82819.073318758441, + 82841.692982981185, + 82864.314191366429, + 82886.936943703375, + 82909.561239781324, + 82932.187079389638, + 82954.814462317736, + 82977.443388355125, + 83000.073857291369, + 83022.70586891612, + 83045.339423019104, + 83067.974519390089, + 83090.611157818959, + 83113.249338095629, + 83135.8890600101, + 83158.530323352461, + 83181.173127912858, + 83203.817473481497, + 83226.463359848669, + 83249.11078680474, + 83271.759754140134, + 83294.410261645375, + 83317.062309111003, + 83339.715896327703, + 83362.371023086147, + 83385.027689177165, + 83407.685894391587, + 83430.345638520361, + 83453.006921354478, + 83475.669742685001, + 83498.334102303095, + 83520.999999999942, + 83543.667435566866, + 83566.336408795192, + 83589.006919476349, + 83611.678967401851, + 83634.352552363242, + 83657.027674152167, + 83679.704332560359, + 83702.382527379552, + 83725.062258401638, + 83747.743525418511, + 83770.42632822218, + 83793.110666604684, + 83815.796540358162, + 83838.483949274829, + 83861.172893146941, + 83883.863371766842, + 83906.555384926964, + 83929.248932419752, + 83951.944014037799, + 83974.640629573696, + 83997.338778820151, + 84020.038461569929, + 84042.739677615857, + 84065.442426750829, + 84088.146708767847, + 84110.852523459922, + 84133.559870620171, + 84156.268750041796, + 84178.979161518029, + 84201.691104842204, + 84224.404579807713, + 84247.119586208006, + 84269.83612383662, + 84292.55419248715, + 84315.273791953281, + 84337.994922028738, + 84360.717582507335, + 84383.441773182945, + 84406.167493849513, + 84428.894744301069, + 84451.623524331691, + 84474.353833735542, + 84497.085672306828, + 84519.819039839858, + 84542.553936128999, + 84565.290360968676, + 84588.028314153402, + 84610.767795477717, + 84633.508804736295, + 84656.251341723822, + 84678.995406235073, + 84701.740998064924, + 84724.488117008252, + 84747.236762860062, + 84769.986935415407, + 84792.73863446941, + 84815.491859817252, + 84838.246611254188, + 84861.002888575575, + 84883.760691576768, + 84906.520020053256, + 84929.28087380057, + 84952.043252614312, + 84974.807156290146, + 84997.572584623806, + 85020.339537411113, + 85043.108014447949, + 85065.878015530237, + 85088.649540453989, + 85111.422589015303, + 85134.197161010321, + 85156.973256235244, + 85179.750874486374, + 85202.530015560071, + 85225.310679252725, + 85248.092865360857, + 85270.876573681016, + 85293.661804009811, + 85316.448556143951, + 85339.236829880188, + 85362.026625015351, + 85384.817941346351, + 85407.610778670132, + 85430.405136783724, + 85453.201015484257, + 85475.998414568865, + 85498.797333834795, + 85521.597773079353, + 85544.399732099904, + 85567.203210693886, + 85590.008208658808, + 85612.814725792239, + 85635.62276189182, + 85658.432316755265, + 85681.243390180331, + 85704.055981964877, + 85726.870091906807, + 85749.685719804082, + 85772.502865454764, + 85795.321528656961, + 85818.141709208852, + 85840.963406908675, + 85863.78662155474, + 85886.611352945445, + 85909.437600879217, + 85932.26536515457, + 85955.094645570091, + 85977.92544192441, + 86000.757754016275, + 86023.591581644432, + 86046.426924607746, + 86069.263782705122, + 86092.102155735556, + 86114.942043498071, + 86137.783445791807, + 86160.626362415918, + 86183.470793169676, + 86206.316737852379, + 86229.164196263402, + 86252.013168202204, + 86274.863653468303, + 86297.715651861261, + 86320.569163180728, + 86343.424187226425, + 86366.280723798132, + 86389.138772695675, + 86411.998333718977, + 86434.859406668009, + 86457.721991342827, + 86480.586087543532, + 86503.451695070296, + 86526.318813723352, + 86549.187443303032, + 86572.057583609683, + 86594.929234443756, + 86617.802395605773, + 86640.677066896271, + 86663.553248115903, + 86686.43093906538, + 86709.310139545443, + 86732.190849356964, + 86755.073068300815, + 86777.956796177954, + 86800.842032789442, + 86823.728777936354, + 86846.617031419853, + 86869.506793041175, + 86892.398062601613, + 86915.290839902518, + 86938.185124745316, + 86961.080916931489, + 86983.978216262592, + 87006.87702254027, + 87029.777335566177, + 87052.67915514209, + 87075.582481069796, + 87098.487313151185, + 87121.39365118822, + 87144.301494982894, + 87167.210844337285, + 87190.121699053532, + 87213.034058933845, + 87235.947923780506, + 87258.863293395829, + 87281.780167582241, + 87304.698546142172, + 87327.618428878181, + 87350.539815592856, + 87373.462706088845, + 87396.387100168897, + 87419.312997635774, + 87442.240398292357, + 87465.16930194154, + 87488.099708386319, + 87511.031617429733, + 87533.965028874911, + 87556.899942525008, + 87579.836358183282, + 87602.774275653021, + 87625.713694737613, + 87648.654615240492, + 87671.597036965148, + 87694.540959715145, + 87717.486383294105, + 87740.433307505737, + 87763.381732153779, + 87786.331657042057, + 87809.283081974456, + 87832.236006754916, + 87855.190431187453, + 87878.146355076155, + 87901.103778225151, + 87924.062700438633, + 87947.023121520891, + 87969.985041276246, + 87992.948459509105, + 88015.913376023906, + 88038.879790625171, + 88061.847703117513, + 88084.817113305573, + 88107.788020994049, + 88130.760425987726, + 88153.734328091465, + 88176.709727110137, + 88199.686622848749, + 88222.665015112303, + 88245.644903705906, + 88268.626288434709, + 88291.609169103947, + 88314.593545518903, + 88337.579417484914, + 88360.566784807408, + 88383.555647291854, + 88406.546004743795, + 88429.537856968818, + 88452.531203772611, + 88475.52604496089, + 88498.522380339447, + 88521.52020971413, + 88544.519532890874, + 88567.520349675644, + 88590.522659874507, + 88613.526463293543, + 88636.531759738922, + 88659.538549016899, + 88682.546830933745, + 88705.556605295846, + 88728.567871909589, + 88751.580630581491, + 88774.594881118086, + 88797.610623325963, + 88820.62785701183, + 88843.646581982393, + 88866.666798044462, + 88889.688505004888, + 88912.711702670611, + 88935.7363908486, + 88958.762569345898, + 88981.790237969632, + 89004.81939652696, + 89027.850044825114, + 89050.882182671412, + 89073.9158098732, + 89096.950926237885, + 89119.987531572973, + 89143.025625686001, + 89166.065208384563, + 89189.106279476357, + 89212.148838769106, + 89235.192886070581, + 89258.238421188667, + 89281.285443931265, + 89304.333954106376, + 89327.383951522017, + 89350.435435986306, + 89373.488407307406, + 89396.542865293537, + 89419.598809753006, + 89442.656240494165, + 89465.715157325409, + 89488.775560055219, + 89511.837448492137, + 89534.900822444746, + 89557.965681721733, + 89581.032026131812, + 89604.099855483742, + 89627.169169586399, + 89650.239968248672, + 89673.312251279538, + 89696.386018488018, + 89719.461269683205, + 89742.53800467425, + 89765.616223270365, + 89788.69592528083, + 89811.777110514988, + 89834.859778782207, + 89857.943929891975, + 89881.029563653807, + 89904.116679877261, + 89927.205278372014, + 89950.29535894774, + 89973.386921414218, + 89996.479965581268, + 90019.574491258769, + 90042.670498256688, + 90065.767986385021, + 90088.866955453836, + 90111.967405273259, + 90135.069335653476, + 90158.172746404758, + 90181.277637337407, + 90204.384008261797, + 90227.49185898836, + 90250.601189327586, + 90273.711999090039, + 90296.824288086325, + 90319.938056127125, + 90343.053303023189, + 90366.170028585286, + 90389.288232624298, + 90412.407914951138, + 90435.529075376777, + 90458.651713712257, + 90481.775829768681, + 90504.901423357209, + 90528.028494289058, + 90551.157042375504, + 90574.287067427911, + 90597.418569257643, + 90620.551547676194, + 90643.686002495073, + 90666.821933525847, + 90689.959340580186, + 90713.098223469773, + 90736.238582006365, + 90759.380416001804, + 90782.523725267951, + 90805.668509616764, + 90828.814768860233, + 90851.962502810435, + 90875.11171127946, + 90898.262394079517, + 90921.414551022855, + 90944.568181921743, + 90967.72328658856, + 90990.879864835719, + 91014.037916475718, + 91037.19744132107, + 91060.358439184391, + 91083.520909878338, + 91106.684853215629, + 91129.850269009039, + 91153.017157071401, + 91176.185517215621, + 91199.355349254649, + 91222.526653001492, + 91245.699428269247, + 91268.873674871036, + 91292.049392620058, + 91315.226581329553, + 91338.405240812834, + 91361.585370883287, + 91384.766971354344, + 91407.950042039476, + 91431.134582752245, + 91454.320593306256, + 91477.508073515171, + 91500.697023192712, + 91523.887442152685, + 91547.07933020893, + 91570.272687175326, + 91593.467512865856, + 91616.663807094534, + 91639.861569675442, + 91663.060800422725, + 91686.261499150554, + 91709.463665673218, + 91732.66729980502, + 91755.872401360321, + 91779.078970153569, + 91802.287005999257, + 91825.49650871192, + 91848.707478106167, + 91871.91991399668, + 91895.133816198169, + 91918.349184525418, + 91941.566018793281, + 91964.784318816659, + 91988.004084410495, + 92011.22531538982, + 92034.448011569708, + 92057.672172765277, + 92080.897798791746, + 92104.124889464365, + 92127.353444598411, + 92150.58346400928, + 92173.814947512379, + 92197.04789492322, + 92220.282306057314, + 92243.518180730272, + 92266.755518757753, + 92289.994319955469, + 92313.234584139194, + 92336.476311124774, + 92359.719500728082, + 92382.964152765067, + 92406.210267051734, + 92429.457843404161, + 92452.706881638471, + 92475.957381570814, + 92499.209343017443, + 92522.462765794655, + 92545.717649718805, + 92568.973994606305, + 92592.231800273614, + 92615.491066537259, + 92638.751793213814, + 92662.01398011994, + 92685.277627072326, + 92708.54273388772, + 92731.809300382942, + 92755.077326374871, + 92778.346811680414, + 92801.617756116568, + 92824.890159500384, + 92848.164021648947, + 92871.439342379424, + 92894.716121509016, + 92917.994358855023, + 92941.274054234746, + 92964.555207465572, + 92987.837818364962, + 93011.121886750407, + 93034.407412439468, + 93057.694395249753, + 93080.982834998955, + 93104.272731504767, + 93127.564084584999, + 93150.856894057491, + 93174.15115974014, + 93197.446881450916, + 93220.744059007804, + 93244.04269222889, + 93267.342780932304, + 93290.644324936235, + 93313.947324058914, + 93337.251778118633, + 93360.557686933767, + 93383.865050322696, + 93407.173868103928, + 93430.484140095941, + 93453.795866117362, + 93477.109045986799, + 93500.423679522952, + 93523.739766544561, + 93547.057306870454, + 93570.376300319491, + 93593.696746710571, + 93617.018645862699, + 93640.341997594893, + 93663.666801726242, + 93686.993058075881, + 93710.320766463032, + 93733.64992670693, + 93756.980538626914, + 93780.312602042337, + 93803.646116772637, + 93826.981082637285, + 93850.317499455836, + 93873.655367047861, + 93896.994685233032, + 93920.335453831038, + 93943.677672661666, + 93967.021341544707, + 93990.366460300051, + 94013.713028747632, + 94037.061046707429, + 94060.410513999494, + 94083.761430443905, + 94107.113795860845, + 94130.467610070496, + 94153.822872893157, + 94177.179584149111, + 94200.537743658759, + 94223.897351242529, + 94247.25840672091, + 94270.620909914433, + 94293.98486064373, + 94317.350258729421, + 94340.71710399224, + 94364.085396252936, + 94387.455135332348, + 94410.82632105134, + 94434.198953230851, + 94457.573031691878, + 94480.948556255447, + 94504.325526742658, + 94527.70394297468, + 94551.083804772716, + 94574.465111958023, + 94597.847864351934, + 94621.232061775823, + 94644.617704051096, + 94668.004790999272, + 94691.393322441872, + 94714.783298200506, + 94738.174718096794, + 94761.567581952477, + 94784.961889589307, + 94808.357640829097, + 94831.754835493703, + 94855.153473405066, + 94878.553554385173, + 94901.955078256055, + 94925.358044839784, + 94948.762453958523, + 94972.168305434476, + 94995.575599089891, + 95018.984334747074, + 95042.394512228391, + 95065.806131356265, + 95089.219191953176, + 95112.633693841635, + 95136.04963684424, + 95159.467020783617, + 95182.885845482466, + 95206.306110763529, + 95229.727816449609, + 95253.150962363579, + 95276.575548328314, + 95300.001574166803, + 95323.429039702052, + 95346.857944757154, + 95370.288289155214, + 95393.720072719429, + 95417.153295273019, + 95440.587956639298, + 95464.024056641589, + 95487.461595103305, + 95510.900571847902, + 95534.340986698866, + 95557.782839479783, + 95581.226130014256, + 95604.670858125959, + 95628.117023638595, + 95651.564626375985, + 95675.013666161918, + 95698.464142820303, + 95721.916056175076, + 95745.369406050231, + 95768.824192269807, + 95792.280414657915, + 95815.738073038709, + 95839.197167236387, + 95862.657697075221, + 95886.11966237954, + 95909.583062973688, + 95933.047898682111, + 95956.514169329268, + 95979.981874739708, + 96003.451014738006, + 96026.921589148798, + 96050.393597796792, + 96073.867040506724, + 96097.341917103375, + 96120.818227411626, + 96144.295971256375, + 96167.775148462577, + 96191.255758855244, + 96214.737802259449, + 96238.221278500292, + 96261.70618740299, + 96285.192528792715, + 96308.680302494788, + 96332.169508334526, + 96355.660146137321, + 96379.152215728609, + 96402.645716933868, + 96426.14064957868, + 96449.637013488609, + 96473.134808489311, + 96496.63403440651, + 96520.134691065963, + 96543.636778293469, + 96567.140295914898, + 96590.645243756153, + 96614.151621643221, + 96637.659429402134, + 96661.168666858954, + 96684.679333839798, + 96708.191430170875, + 96731.70495567839, + 96755.219910188665, + 96778.736293528011, + 96802.254105522836, + 96825.77334599958, + 96849.29401478474, + 96872.816111704873, + 96896.339636586577, + 96919.864589256511, + 96943.390969541389, + 96966.918777267958, + 96990.448012263048, + 97013.978674353522, + 97037.510763366285, + 97061.044279128328, + 97084.579221466673, + 97108.115590208385, + 97131.653385180587, + 97155.19260621049, + 97178.733253125291, + 97202.2753257523, + 97225.81882391886, + 97249.363747452342, + 97272.910096180189, + 97296.457869929916, + 97320.007068529041, + 97343.557691805196, + 97367.109739586012, + 97390.663211699197, + 97414.218107972498, + 97437.774428233737, + 97461.332172310766, + 97484.891340031507, + 97508.451931223899, + 97532.013945715982, + 97555.577383335811, + 97579.142243911512, + 97602.708527271257, + 97626.276233243261, + 97649.845361655811, + 97673.415912337223, + 97696.987885115886, + 97720.561279820206, + 97744.1360962787, + 97767.712334319876, + 97791.289993772341, + 97814.869074464703, + 97838.449576225685, + 97862.031498883996, + 97885.614842268449, + 97909.199606207883, + 97932.785790531183, + 97956.37339506732, + 97979.962419645264, + 98003.552864094076, + 98027.144728242856, + 98050.738011920766, + 98074.332714956996, + 98097.928837180807, + 98121.526378421506, + 98145.125338508456, + 98168.725717271067, + 98192.327514538789, + 98215.930730141132, + 98239.535363907664, + 98263.141415668011, + 98286.748885251814, + 98310.357772488816, + 98333.968077208759, + 98357.579799241488, + 98381.192938416847, + 98404.807494564782, + 98428.42346751524, + 98452.040857098269, + 98475.659663143917, + 98499.27988548232, + 98522.901523943656, + 98546.524578358163, + 98570.149048556093, + 98593.774934367786, + 98617.402235623624, + 98641.030952154048, + 98664.661083789513, + 98688.292630360564, + 98711.925591697771, + 98735.559967631794, + 98759.195757993293, + 98782.832962613014, + 98806.471581321734, + 98830.111613950285, + 98853.753060329575, + 98877.39592029051, + 98901.040193664099, + 98924.68588028138, + 98948.33297997342, + 98971.981492571387, + 98995.63141790645, + 99019.282755809851, + 99042.935506112874, + 99066.589668646877, + 99090.245243243233, + 99113.902229733401, + 99137.560627948857, + 99161.220437721131, + 99184.881658881859, + 99208.544291262631, + 99232.208334695169, + 99255.87378901121, + 99279.540654042547, + 99303.208929621018, + 99326.878615578535, + 99350.549711746993, + 99374.222217958435, + 99397.896134044888, + 99421.571459838422, + 99445.248195171211, + 99468.926339875441, + 99492.605893783344, + 99516.286856727209, + 99539.969228539398, + 99563.653009052287, + 99587.338198098325, + 99611.024795510006, + 99634.712801119866, + 99658.402214760499, + 99682.093036264545, + 99705.785265464699, + 99729.478902193689, + 99753.173946284325, + 99776.870397569437, + 99800.56825588191, + 99824.267521054688, + 99847.968192920773, + 99871.670271313182, + 99895.373756065004, + 99919.078647009388, + 99942.78494397951, + 99966.492646808634, + 99990.20175533001, + 100013.91226937699, + 100037.62418878295, + 100061.33751338134, + 100085.05224300563, + 100108.76837748935, + 100132.4859166661, + 100156.2048603695, + 100179.92520843323, + 100203.64696069101, + 100227.37011697664, + 100251.09467712394, + 100274.82064096678, + 100298.54800833909, + 100322.27677907483, + 100346.00695300807, + 100369.73852997283, + 100393.47150980328, + 100417.20589233354, + 100440.94167739789, + 100464.67886483055, + 100488.41745446586, + 100512.1574461382, + 100535.89883968196, + 100559.64163493161, + 100583.38583172169, + 100607.13142988674, + 100630.87842926137, + 100654.62682968024, + 100678.37663097809, + 100702.12783298964, + 100725.88043554971, + 100749.63443849317, + 100773.38984165489, + 100797.14664486986, + 100820.90484797307, + 100844.66445079957, + 100868.42545318443, + 100892.18785496285, + 100915.95165596998, + 100939.71685604109, + 100963.48345501146, + 100987.25145271645, + 101011.02084899142, + 101034.79164367182, + 101058.56383659317, + 101082.33742759094, + 101106.11241650078, + 101129.88880315828, + 101153.66658739912, + 101177.44576905905, + 101201.22634797383, + 101225.00832397929, + 101248.7916969113, + 101272.57646660579, + 101296.36263289873, + 101320.15019562612, + 101343.93915462404, + 101367.7295097286, + 101391.52126077596, + 101415.31440760233, + 101439.10895004397, + 101462.9048879372, + 101486.70222111834, + 101510.50094942382, + 101534.30107269008, + 101558.10259075361, + 101581.90550345098, + 101605.70981061876, + 101629.5155120936, + 101653.32260771218, + 101677.13109731126, + 101700.9409807276, + 101724.75225779804, + 101748.56492835947, + 101772.37899224881, + 101796.19444930303, + 101820.01129935916, + 101843.82954225427, + 101867.64917782549, + 101891.47020590997, + 101915.29262634492, + 101939.11643896763, + 101962.94164361537, + 101986.76824012553, + 102010.59622833549, + 102034.42560808272, + 102058.25637920471, + 102082.08854153901, + 102105.9220949232, + 102129.75703919494, + 102153.59337419191, + 102177.43109975185, + 102201.27021571253, + 102225.1107219118, + 102248.95261818753, + 102272.79590437764, + 102296.64058032009, + 102320.48664585294, + 102344.33410081422, + 102368.18294504205, + 102392.03317837461, + 102415.88480065008, + 102439.73781170673, + 102463.59221138287, + 102487.44799951684, + 102511.30517594704, + 102535.1637405119, + 102559.02369304992, + 102582.88503339965, + 102606.74776139967, + 102630.61187688859, + 102654.4773797051, + 102678.34426968795, + 102702.21254667587, + 102726.08221050771, + 102749.95326102231, + 102773.8256980586, + 102797.69952145554, + 102821.57473105213, + 102845.45132668741, + 102869.32930820051, + 102893.20867543056, + 102917.08942821674, + 102940.97156639832, + 102964.85508981455, + 102988.73999830478, + 103012.6262917084, + 103036.51396986481, + 103060.40303261351, + 103084.293479794, + 103108.18531124585, + 103132.07852680866, + 103155.97312632212, + 103179.8691096259, + 103203.76647655977, + 103227.66522696352, + 103251.56536067701, + 103275.46687754011, + 103299.36977739276, + 103323.27406007495, + 103347.1797254267, + 103371.0867732881, + 103394.99520349925, + 103418.90501590034, + 103442.81621033157, + 103466.72878663319, + 103490.64274464553, + 103514.55808420894, + 103538.4748051638, + 103562.39290735057, + 103586.31239060973, + 103610.23325478184, + 103634.15549970744, + 103658.07912522719, + 103682.00413118176, + 103705.93051741188, + 103729.85828375829, + 103753.78743006183, + 103777.71795616332, + 103801.64986190372, + 103825.58314712394, + 103849.51781166498, + 103873.4538553679, + 103897.39127807376, + 103921.33007962372, + 103945.27025985894, + 103969.21181862066, + 103993.15475575015, + 104017.0990710887, + 104041.0447644777, + 104064.99183575854, + 104088.94028477269, + 104112.89011136163, + 104136.84131536692, + 104160.79389663014, + 104184.74785499295, + 104208.70319029699, + 104232.65990238401, + 104256.61799109577, + 104280.57745627411, + 104304.53829776087, + 104328.50051539797, + 104352.46410902737, + 104376.42907849104, + 104400.39542363105, + 104424.36314428948, + 104448.33224030846, + 104472.3027115302, + 104496.27455779689, + 104520.24777895081, + 104544.22237483428, + 104568.19834528965, + 104592.17569015936, + 104616.15440928582, + 104640.13450251156, + 104664.1159696791, + 104688.09881063103, + 104712.08302520998, + 104736.06861325864, + 104760.05557461972, + 104784.043909136, + 104808.03361665027, + 104832.0246970054, + 104856.01715004431, + 104880.01097560991, + 104904.00617354522, + 104928.00274369326, + 104952.00068589712, + 104975.99999999993, + 105000.00068584486, + 105024.00274327511, + 105048.00617213396, + 105072.0109722647, + 105096.0171435107, + 105120.02468571534, + 105144.03359872208, + 105168.04388237436, + 105192.05553651576, + 105216.06856098982, + 105240.08295564017, + 105264.09872031047, + 105288.11585484444, + 105312.13435908582, + 105336.1542328784, + 105360.17547606604, + 105384.19808849262, + 105408.22207000206, + 105432.24742043833, + 105456.27413964548, + 105480.30222746753, + 105504.33168374863, + 105528.36250833291, + 105552.39470106458, + 105576.42826178786, + 105600.46319034706, + 105624.49948658649, + 105648.53715035053, + 105672.5761814836, + 105696.61657983017, + 105720.65834523473, + 105744.70147754184, + 105768.7459765961, + 105792.79184224214, + 105816.83907432464, + 105840.88767268835, + 105864.93763717801, + 105888.98896763846, + 105913.04166391456, + 105937.09572585119, + 105961.15115329332, + 105985.20794608595, + 106009.26610407409, + 106033.32562710284, + 106057.38651501729, + 106081.44876766266, + 106105.51238488412, + 106129.57736652695, + 106153.64371243643, + 106177.71142245791, + 106201.78049643678, + 106225.85093421848, + 106249.92273564848, + 106273.99590057228, + 106298.07042883546, + 106322.14632028362, + 106346.22357476239, + 106370.30219211751, + 106394.38217219469, + 106418.46351483969, + 106442.54621989837, + 106466.63028721658, + 106490.71571664025, + 106514.80250801529, + 106538.89066118775, + 106562.98017600364, + 106587.07105230905, + 106611.16328995011, + 106635.25688877302, + 106659.35184862395, + 106683.44816934918, + 106707.54585079502, + 106731.64489280782, + 106755.74529523395, + 106779.84705791986, + 106803.95018071201, + 106828.05466345693, + 106852.16050600118, + 106876.26770819137, + 106900.37626987413, + 106924.48619089619, + 106948.59747110425, + 106972.71011034511, + 106996.82410846559, + 107020.93946531253, + 107045.05618073288, + 107069.17425457356, + 107093.29368668159, + 107117.41447690397, + 107141.53662508781, + 107165.66013108024, + 107189.7849947284, + 107213.91121587952, + 107238.03879438085, + 107262.16773007967, + 107286.29802282334, + 107310.42967245923, + 107334.56267883476, + 107358.69704179741, + 107382.83276119467, + 107406.96983687414, + 107431.10826868335, + 107455.24805646999, + 107479.38920008171, + 107503.53169936626, + 107527.67555417139, + 107551.82076434491, + 107575.96732973469, + 107600.11525018861, + 107624.26452555459, + 107648.41515568066, + 107672.56714041479, + 107696.72047960508, + 107720.87517309963, + 107745.03122074658, + 107769.18862239413, + 107793.34737789053, + 107817.50748708403, + 107841.66894982298, + 107865.83176595572, + 107889.99593533068, + 107914.16145779629, + 107938.32833320105, + 107962.49656139348, + 107986.66614222217, + 108010.83707553572, + 108035.00936118282, + 108059.18299901215, + 108083.35798887245, + 108107.53433061253, + 108131.71202408121, + 108155.89106912735, + 108180.07146559987, + 108204.25321334775, + 108228.43631221994, + 108252.62076206553, + 108276.80656273357, + 108300.99371407321, + 108325.18221593359, + 108349.37206816394, + 108373.56327061349, + 108397.75582313156, + 108421.94972556747, + 108446.1449777706, + 108470.34157959036, + 108494.53953087622, + 108518.73883147769, + 108542.93948124432, + 108567.14148002568, + 108591.34482767139, + 108615.54952403114, + 108639.75556895464, + 108663.96296229165, + 108688.17170389196, + 108712.38179360541, + 108736.59323128188, + 108760.80601677128, + 108785.02014992358, + 108809.23563058881, + 108833.45245861699, + 108857.67063385822, + 108881.89015616261, + 108906.11102538036, + 108930.33324136167, + 108954.55680395682, + 108978.78171301607, + 109003.00796838976, + 109027.23556992831, + 109051.46451748211, + 109075.69481090162, + 109099.92645003737, + 109124.15943473989, + 109148.39376485976, + 109172.62944024763, + 109196.86646075416, + 109221.10482623006, + 109245.34453652608, + 109269.58559149304, + 109293.82799098175, + 109318.07173484311, + 109342.31682292801, + 109366.56325508743, + 109390.81103117237, + 109415.06015103387, + 109439.31061452301, + 109463.56242149093, + 109487.8155717888, + 109512.07006526781, + 109536.3259017792, + 109560.58308117429, + 109584.8416033044, + 109609.1014680209, + 109633.36267517522, + 109657.62522461878, + 109681.88911620311, + 109706.15434977971, + 109730.4209252002, + 109754.68884231619, + 109778.95810097932, + 109803.22870104131, + 109827.50064235389, + 109851.77392476884, + 109876.04854813802, + 109900.32451231324, + 109924.60181714644, + 109948.88046248957, + 109973.1604481946, + 109997.44177411357, + 110021.72444009855, + 110046.00844600165, + 110070.29379167501, + 110094.58047697082, + 110118.86850174134, + 110143.15786583882, + 110167.44856911557, + 110191.74061142397, + 110216.03399261639, + 110240.32871254528, + 110264.62477106311, + 110288.9221680224, + 110313.22090327571, + 110337.52097667565, + 110361.82238807483, + 110386.12513732594, + 110410.42922428172, + 110434.73464879491, + 110459.04141071832, + 110483.34950990479, + 110507.6589462072, + 110531.96971947847, + 110556.28182957157, + 110580.5952763395, + 110604.91005963532, + 110629.22617931209, + 110653.54363522294, + 110677.86242722106, + 110702.18255515963, + 110726.50401889188, + 110750.82681827113, + 110775.1509531507, + 110799.47642338395, + 110823.80322882428, + 110848.13136932514, + 110872.46084474004, + 110896.79165492248, + 110921.12379972603, + 110945.4572790043, + 110969.79209261097, + 110994.12824039967, + 111018.46572222417, + 111042.80453793822, + 111067.14468739564, + 111091.48617045028, + 111115.82898695602, + 111140.1731367668, + 111164.51861973655, + 111188.86543571933, + 111213.21358456917, + 111237.56306614014, + 111261.91388028639, + 111286.26602686207, + 111310.61950572141, + 111334.97431671864, + 111359.33045970804, + 111383.68793454397, + 111408.04674108078, + 111432.40687917286, + 111456.76834867468, + 111481.13114944073, + 111505.49528132551, + 111529.86074418361, + 111554.22753786964, + 111578.59566223821, + 111602.96511714405, + 111627.33590244185, + 111651.7080179864, + 111676.08146363248, + 111700.45623923496, + 111724.8323446487, + 111749.20977972864, + 111773.58854432974, + 111797.96863830699, + 111822.35006151545, + 111846.73281381019, + 111871.11689504632, + 111895.50230507903, + 111919.8890437635, + 111944.27711095495, + 111968.6665065087, + 111993.05723028004, + 112017.44928212435, + 112041.842661897, + 112066.23736945343, + 112090.63340464912, + 112115.03076733962, + 112139.42945738042, + 112163.82947462716, + 112188.23081893545, + 112212.63349016097, + 112237.03748815943, + 112261.44281278658, + 112285.84946389822, + 112310.25744135017, + 112334.66674499828, + 112359.07737469849, + 112383.48933030672, + 112407.90261167898, + 112432.31721867126, + 112456.73315113965, + 112481.15040894024, + 112505.56899192919, + 112529.98889996267, + 112554.41013289688, + 112578.8326905881, + 112603.25657289263, + 112627.68177966679, + 112652.10831076698, + 112676.53616604958, + 112700.96534537108, + 112725.39584858794, + 112749.82767555672, + 112774.26082613398, + 112798.6953001763, + 112823.13109754038, + 112847.56821808286, + 112872.00666166049, + 112896.44642813003, + 112920.88751734827, + 112945.32992917208, + 112969.77366345831, + 112994.21872006389, + 113018.66509884578, + 113043.11279966099, + 113067.56182236652, + 113092.01216681948, + 113116.46383287695, + 113140.9168203961, + 113165.37112923413, + 113189.82675924824, + 113214.28371029573, + 113238.74198223387, + 113263.20157492002, + 113287.66248821157, + 113312.12472196593, + 113336.58827604055, + 113361.05315029295, + 113385.51934458067, + 113409.98685876124, + 113434.45569269233, + 113458.92584623155, + 113483.39731923661, + 113507.87011156522, + 113532.34422307517, + 113556.81965362425, + 113581.2964030703, + 113605.77447127122, + 113630.25385808491, + 113654.73456336933, + 113679.2165869825, + 113703.69992878241, + 113728.18458862718, + 113752.67056637487, + 113777.15786188368, + 113801.64647501177, + 113826.13640561736, + 113850.62765355874, + 113875.12021869418, + 113899.61410088204, + 113924.1092999807, + 113948.60581584855, + 113973.10364834407, + 113997.60279732574, + 114022.1032626521, + 114046.60504418171, + 114071.10814177318, + 114095.61255528514, + 114120.11828457628, + 114144.62532950533, + 114169.13368993104, + 114193.6433657122, + 114218.15435670764, + 114242.66666277625, + 114267.18028377694, + 114291.69521956862, + 114316.21147001031, + 114340.72903496103, + 114365.24791427983, + 114389.7681078258, + 114414.2896154581, + 114438.81243703589, + 114463.33657241837, + 114487.8620214648, + 114512.38878403447, + 114536.91685998671, + 114561.44624918087, + 114585.97695147636, + 114610.5089667326, + 114635.04229480909, + 114659.57693556532, + 114684.11288886084, + 114708.65015455526, + 114733.18873250818, + 114757.72862257928, + 114782.26982462825, + 114806.81233851484, + 114831.35616409882, + 114855.90130123998, + 114880.44774979822, + 114904.99550963337, + 114929.5445806054, + 114954.09496257425, + 114978.64665539992, + 115003.19965894247, + 115027.75397306195, + 115052.30959761847, + 115076.86653247218, + 115101.42477748329, + 115125.984332512, + 115150.54519741859, + 115175.10737206334, + 115199.67085630659, + 115224.23565000873, + 115248.80175303014, + 115273.3691652313, + 115297.93788647266, + 115322.50791661476, + 115347.07925551817, + 115371.65190304347, + 115396.22585905129, + 115420.80112340231, + 115445.37769595724, + 115469.95557657682, + 115494.53476512182, + 115519.11526145306, + 115543.69706543141, + 115568.28017691776, + 115592.86459577303, + 115617.4503218582, + 115642.03735503425, + 115666.62569516223, + 115691.21534210323, + 115715.80629571836, + 115740.39855586876, + 115764.99212241563, + 115789.58699522018, + 115814.18317414368, + 115838.78065904744, + 115863.37944979276, + 115887.97954624105, + 115912.5809482537, + 115937.18365569216, + 115961.78766841792, + 115986.39298629249, + 116010.99960917742, + 116035.60753693432, + 116060.21676942479, + 116084.82730651053, + 116109.43914805322, + 116134.0522939146, + 116158.66674395646, + 116183.2824980406, + 116207.89955602887, + 116232.51791778316, + 116257.13758316539, + 116281.75855203751, + 116306.38082426153, + 116331.00439969949, + 116355.62927821343, + 116380.25545966547, + 116404.88294391775, + 116429.51173083246, + 116454.14182027178, + 116478.77321209799, + 116503.40590617337, + 116528.03990236025, + 116552.67520052097, + 116577.31180051794, + 116601.94970221359, + 116626.5889054704, + 116651.22941015086, + 116675.87121611751, + 116700.51432323294, + 116725.15873135976, + 116749.8044403606, + 116774.45145009817, + 116799.0997604352, + 116823.74937123443, + 116848.40028235866, + 116873.05249367072, + 116897.70600503348, + 116922.36081630984, + 116947.01692736275, + 116971.67433805518, + 116996.33304825013, + 117020.99305781067, + 117045.65436659988, + 117070.31697448085, + 117094.98088131678, + 117119.64608697082, + 117144.31259130624, + 117168.98039418629, + 117193.64949547425, + 117218.31989503348, + 117242.99159272734, + 117267.66458841923, + 117292.33888197262, + 117317.01447325097, + 117341.6913621178, + 117366.36954843666, + 117391.04903207115, + 117415.72981288488, + 117440.41189074152, + 117465.09526550474, + 117489.77993703831, + 117514.46590520597, + 117539.15316987153, + 117563.84173089883, + 117588.53158815173, + 117613.22274149416, + 117637.91519079007, + 117662.60893590341, + 117687.30397669821, + 117712.00031303853, + 117736.69794478847, + 117761.39687181212, + 117786.09709397367, + 117810.7986111373, + 117835.50142316725, + 117860.20552992777, + 117884.91093128319, + 117909.6176270978, + 117934.32561723603, + 117959.03490156225, + 117983.74547994092, + 118008.45735223651, + 118033.17051831353, + 118057.88497803656, + 118082.60073127014, + 118107.31777787894, + 118132.03611772758, + 118156.75575068076, + 118181.47667660323, + 118206.19889535972, + 118230.92240681504, + 118255.64721083404, + 118280.37330728157, + 118305.10069602253, + 118329.82937692189, + 118354.55934984458, + 118379.29061465565, + 118404.02317122012, + 118428.75701940308, + 118453.49215906965, + 118478.22859008498, + 118502.96631231424, + 118527.70532562268, + 118552.44562987552, + 118577.18722493808, + 118601.93011067568, + 118626.67428695368, + 118651.41975363747, + 118676.16651059251, + 118700.91455768423, + 118725.66389477813, + 118750.41452173979, + 118775.16643843475, + 118799.91964472862, + 118824.67414048707, + 118849.42992557574, + 118874.18699986035, + 118898.94536320666, + 118923.70501548045, + 118948.46595654752, + 118973.22818627374, + 118997.99170452499, + 119022.7565111672, + 119047.52260606633, + 119072.28998908834, + 119097.0586600993, + 119121.82861896523, + 119146.59986555226, + 119171.3723997265, + 119196.14622135412, + 119220.92133030134, + 119245.69772643436, + 119270.47540961947, + 119295.25437972297, + 119320.03463661121, + 119344.81618015055, + 119369.5990102074, + 119394.38312664822, + 119419.16852933947, + 119443.95521814766, + 119468.74319293935, + 119493.53245358112, + 119518.32299993958, + 119543.11483188139, + 119567.90794927324, + 119592.70235198183, + 119617.49803987393, + 119642.29501281632, + 119667.09327067583, + 119691.89281331931, + 119716.69364061367, + 119741.49575242582, + 119766.29914862274, + 119791.10382907141, + 119815.90979363887, + 119840.71704219218, + 119865.52557459843, + 119890.33539072477, + 119915.14649043836, + 119939.95887360642, + 119964.77254009615, + 119989.58748977486, + 120014.40372250983, + 120039.22123816841, + 120064.04003661797, + 120088.86011772591, + 120113.6814813597, + 120138.5041273868, + 120163.3280556747, + 120188.15326609099, + 120212.97975850321, + 120237.807532779, + 120262.63658878599, + 120287.46692639188, + 120312.29854546436, + 120337.13144587121, + 120361.9656274802, + 120386.80109015915, + 120411.63783377589, + 120436.47585819835, + 120461.31516329442, + 120486.15574893207, + 120510.99761497928, + 120535.84076130406, + 120560.68518777451, + 120585.53089425867, + 120610.3778806247, + 120635.22614674074, + 120660.07569247499, + 120684.92651769568, + 120709.77862227106, + 120734.63200606944, + 120759.48666895913, + 120784.3426108085, + 120809.19983148595, + 120834.05833085992, + 120858.91810879884, + 120883.77916517125, + 120908.64149984565, + 120933.5051126906, + 120958.37000357473, + 120983.23617236665, + 121008.10361893504, + 121032.97234314861, + 121057.84234487606, + 121082.71362398617, + 121107.58618034775, + 121132.46001382964, + 121157.33512430069, + 121182.21151162982, + 121207.08917568595, + 121231.96811633807, + 121256.84833345517, + 121281.72982690629, + 121306.61259656049, + 121331.49664228689, + 121356.38196395461, + 121381.26856143285, + 121406.15643459078, + 121431.04558329767, + 121455.93600742276, + 121480.82770683538, + 121505.72068140487, + 121530.61493100057, + 121555.51045549192, + 121580.40725474835, + 121605.30532863933, + 121630.20467703436, + 121655.10529980299, + 121680.00719681478, + 121704.91036793934, + 121729.81481304632, + 121754.72053200539, + 121779.62752468624, + 121804.53579095862, + 121829.44533069231, + 121854.3561437571, + 121879.26823002285, + 121904.1815893594, + 121929.09622163669, + 121954.01212672464, + 121978.92930449323, + 122003.84775481246, + 122028.76747755238, + 122053.68847258303, + 122078.61073977455, + 122103.53427899707, + 122128.45909012076, + 122153.38517301581, + 122178.31252755247, + 122203.24115360099, + 122228.17105103172, + 122253.10221971494, + 122278.03465952107, + 122302.96837032049, + 122327.90335198362, + 122352.83960438096, + 122377.777127383, + 122402.71592086025, + 122427.65598468333, + 122452.59731872278, + 122477.53992284928, + 122502.48379693348, + 122527.42894084606, + 122552.37535445779, + 122577.32303763942, + 122602.27199026172, + 122627.22221219557, + 122652.17370331181, + 122677.12646348133, + 122702.08049257506, + 122727.03579046397, + 122751.99235701906, + 122776.95019211136, + 122801.9092956119, + 122826.8696673918, + 122851.83130732219, + 122876.79421527422, + 122901.75839111909, + 122926.72383472799, + 122951.69054597223, + 122976.65852472307, + 123001.62777085182, + 123026.59828422987, + 123051.57006472857, + 123076.54311221937, + 123101.5174265737, + 123126.49300766307, + 123151.46985535898, + 123176.44796953299, + 123201.42735005668, + 123226.40799680166, + 123251.38990963959, + 123276.37308844214, + 123301.35753308103, + 123326.343243428, + 123351.33021935483, + 123376.31846073334, + 123401.30796743535, + 123426.29873933276, + 123451.29077629748, + 123476.28407820144, + 123501.2786449166, + 123526.27447631498, + 123551.27157226863, + 123576.26993264959, + 123601.26955732999, + 123626.27044618195, + 123651.27259907764, + 123676.27601588926, + 123701.28069648903, + 123726.28664074924, + 123751.29384854218, + 123776.30231974016, + 123801.31205421555, + 123826.32305184075, + 123851.33531248817, + 123876.34883603029, + 123901.36362233957, + 123926.37967128855, + 123951.39698274979, + 123976.41555659588, + 124001.43539269941, + 124026.45649093305, + 124051.47885116948, + 124076.50247328142, + 124101.5273571416, + 124126.55350262282, + 124151.58090959788, + 124176.60957793961, + 124201.63950752091, + 124226.67069821467, + 124251.70314989384, + 124276.73686243138, + 124301.7718357003, + 124326.80806957364, + 124351.84556392446, + 124376.88431862585, + 124401.92433355095, + 124426.96560857294, + 124452.00814356498, + 124477.05193840031, + 124502.0969929522, + 124527.14330709392, + 124552.19088069882, + 124577.23971364023, + 124602.28980579154, + 124627.34115702618, + 124652.3937672176, + 124677.44763623926, + 124702.50276396469, + 124727.55915026742, + 124752.61679502104, + 124777.67569809916, + 124802.73585937542, + 124827.79727872348, + 124852.85995601704, + 124877.92389112986, + 124902.98908393568, + 124928.05553430831, + 124953.1232421216, + 124978.19220724938, + 125003.26242956554, + 125028.33390894404, + 125053.40664525882, + 125078.48063838384, + 125103.55588819318, + 125128.63239456083, + 125153.71015736091, + 125178.78917646752, + 125203.86945175481, + 125228.95098309696, + 125254.03377036817, + 125279.1178134427, + 125304.20311219479, + 125329.28966649878, + 125354.37747622898, + 125379.46654125977, + 125404.55686146552, + 125429.6484367207, + 125454.74126689974, + 125479.83535187715, + 125504.93069152744, + 125530.02728572517, + 125555.12513434493, + 125580.22423726133, + 125605.32459434902, + 125630.4262054827, + 125655.52907053704, + 125680.63318938682, + 125705.73856190679, + 125730.84518797178, + 125755.9530674566, + 125781.06220023613, + 125806.17258618528, + 125831.28422517896, + 125856.39711709213, + 125881.51126179981, + 125906.62665917698, + 125931.74330909875, + 125956.86121144016, + 125981.98036607634, + 126007.10077288245, + 126032.22243173365, + 126057.34534250517, + 126082.46950507225, + 126107.59491931014, + 126132.72158509417, + 126157.84950229966, + 126182.97867080198, + 126208.10909047653, + 126233.24076119871, + 126258.37368284403, + 126283.50785528794, + 126308.64327840599, + 126333.77995207369, + 126358.91787616667, + 126384.0570505605, + 126409.19747513086, + 126434.3391497534, + 126459.48207430386, + 126484.62624865794, + 126509.77167269142, + 126534.9183462801, + 126560.06626929982, + 126585.21544162642, + 126610.36586313581, + 126635.51753370393, + 126660.67045320668, + 126685.82462152008, + 126710.98003852014, + 126736.13670408291, + 126761.29461808444, + 126786.45378040087, + 126811.61419090834, + 126836.77584948298, + 126861.93875600102, + 126887.10291033868, + 126912.26831237224, + 126937.43496197795, + 126962.60285903217, + 126987.77200341123, + 127012.94239499152, + 127038.11403364947, + 127063.2869192615, + 127088.46105170409, + 127113.63643085376, + 127138.81305658702, + 127163.99092878048, + 127189.17004731069, + 127214.35041205429, + 127239.53202288797, + 127264.71487968838, + 127289.89898233226, + 127315.08433069635, + 127340.27092465744, + 127365.45876409234, + 127390.64784887788, + 127415.83817889093, + 127441.02975400841, + 127466.22257410725, + 127491.41663906439, + 127516.61194875685, + 127541.80850306165, + 127567.00630185583, + 127592.20534501647, + 127617.4056324207, + 127642.60716394568, + 127667.80993946856, + 127693.01395886653, + 127718.21922201688, + 127743.42572879682, + 127768.63347908368, + 127793.84247275478, + 127819.05270968749, + 127844.26418975917, + 127869.47691284724, + 127894.69087882918, + 127919.90608758242, + 127945.12253898452, + 127970.34023291297, + 127995.55916924537, + 128020.77934785932, + 128046.00076863244, + 128071.22343144237, + 128096.44733616684, + 128121.67248268353, + 128146.89887087021, + 128172.12650060465, + 128197.35537176467, + 128222.5854842281, + 128247.81683787282, + 128273.04943257671, + 128298.28326821771, + 128323.51834467379, + 128348.75466182294, + 128373.99221954317, + 128399.23101771252, + 128424.47105620909, + 128449.71233491098, + 128474.95485369631, + 128500.19861244329, + 128525.44361103009, + 128550.68984933494, + 128575.93732723613, + 128601.18604461191, + 128626.43600134061, + 128651.68719730059, + 128676.93963237021, + 128702.1933064279, + 128727.44821935208, + 128752.70437102125, + 128777.96176131385, + 128803.22039010846, + 128828.48025728362, + 128853.74136271792, + 128879.00370628996, + 128904.26728787841, + 128929.53210736193, + 128954.79816461923, + 128980.06545952905, + 129005.33399197015, + 129030.60376182134, + 129055.87476896142, + 129081.14701326926, + 129106.42049462376, + 129131.6952129038, + 129156.97116798835, + 129182.24835975636, + 129207.52678808685, + 129232.80645285884, + 129258.08735395141, + 129283.36949124365, + 129308.65286461466, + 129333.9374739436, + 129359.22331910966, + 129384.51039999202, + 129409.79871646997, + 129435.08826842274, + 129460.37905572963, + 129485.67107826998, + 129510.96433592314, + 129536.25882856851, + 129561.55455608548, + 129586.85151835352, + 129612.14971525209, + 129637.4491466607, + 129662.74981245887, + 129688.0517125262, + 129713.35484674224, + 129738.65921498663, + 129763.96481713903, + 129789.27165307909, + 129814.57972268655, + 129839.88902584116, + 129865.19956242264, + 129890.51133231082, + 129915.82433538554, + 129941.13857152662, + 129966.45404061397, + 129991.7707425275, + 130017.08867714716, + 130042.4078443529, + 130067.72824402474, + 130093.04987604271, + 130118.37274028687, + 130143.69683663732, + 130169.02216497416, + 130194.34872517755, + 130219.67651712766, + 130245.0055407047, + 130270.33579578891, + 130295.66728226055, + 130320.99999999991, + 130346.33394888733, + 130371.66912880314, + 130397.00553962773, + 130422.34318124152, + 130447.68205352494, + 130473.02215635845, + 130498.36348962256, + 130523.70605319779, + 130549.0498469647, + 130574.39487080388, + 130599.74112459592, + 130625.08860822149, + 130650.43732156123, + 130675.78726449587, + 130701.13843690613, + 130726.49083867275, + 130751.84446967654, + 130777.19932979831, + 130802.5554189189, + 130827.91273691918, + 130853.27128368006, + 130878.63105908247, + 130903.99206300738, + 130929.35429533575, + 130954.71775594862, + 130980.08244472703, + 131005.44836155206, + 131030.81550630482, + 131056.18387886642, + 131081.55347911804, + 131106.92430694087, + 131132.29636221612, + 131157.66964482504, + 131183.0441546489, + 131208.41989156904, + 131233.79685546676, + 131259.17504622342, + 131284.55446372041, + 131309.93510783918, + 131335.31697846117, + 131360.70007546784, + 131386.0843987407, + 131411.46994816128, + 131436.85672361116, + 131462.24472497194, + 131487.63395212521, + 131513.02440495262, + 131538.41608333588, + 131563.80898715663, + 131589.2031162967, + 131614.59847063778, + 131639.9950500617, + 131665.39285445024, + 131690.79188368531, + 131716.19213764873, + 131741.59361622241, + 131766.99631928833, + 131792.40024672839, + 131817.80539842462, + 131843.21177425905, + 131868.61937411371, + 131894.02819787065, + 131919.43824541202, + 131944.84951661993, + 131970.26201137656, + 131995.67572956407, + 132021.09067106468, + 132046.50683576067, + 132071.9242235343, + 132097.34283426782, + 132122.76266784366, + 132148.1837241441, + 132173.60600305157, + 132199.02950444847, + 132224.45422821722, + 132249.88017424036, + 132275.30734240031, + 132300.73573257966, + 132326.16534466096, + 132351.59617852676, + 132377.02823405969, + 132402.46151114244, + 132427.89600965759, + 132453.33172948789, + 132478.76867051609, + 132504.20683262491, + 132529.64621569714, + 132555.08681961559, + 132580.5286442631, + 132605.97168952253, + 132631.41595527678, + 132656.86144140881, + 132682.30814780149, + 132707.75607433787, + 132733.20522090094, + 132758.65558737374, + 132784.10717363929, + 132809.55997958075, + 132835.01400508118, + 132860.46925002377, + 132885.92571429166, + 132911.38339776811, + 132936.84230033628, + 132962.30242187946, + 132987.76376228096, + 133013.22632142407, + 133038.69009919214, + 133064.15509546854, + 133089.62131013666, + 133115.08874307995, + 133140.55739418184, + 133166.02726332581, + 133191.49835039541, + 133216.97065527414, + 133242.44417784561, + 133267.91891799335, + 133293.39487560102, + 133318.87205055228, + 133344.35044273079, + 133369.83005202023, + 133395.31087830439, + 133420.79292146701, + 133446.27618139185, + 133471.76065796276, + 133497.24635106357, + 133522.73326057816, + 133548.22138639039, + 133573.71072838426, + 133599.20128644365, + 133624.69306045261, + 133650.1860502951, + 133675.68025585517, + 133701.1756770169, + 133726.67231366437, + 133752.17016568172, + 133777.66923295305, + 133803.16951536259, + 133828.67101279454, + 133854.17372513309, + 133879.67765226253, + 133905.18279406714, + 133930.68915043125, + 133956.19672123916, + 133981.70550637526, + 134007.21550572399, + 134032.7267191697, + 134058.23914659687, + 134083.75278789, + 134109.26764293358, + 134134.78371161217, + 134160.30099381026, + 134185.8194894125, + 134211.33919830353, + 134236.8601203679, + 134262.38225549037, + 134287.90560355558, + 134313.43016444831, + 134338.95593805326, + 134364.48292425525, + 134390.01112293909, + 134415.54053398955, + 134441.07115729159, + 134466.60299273001, + 134492.1360401898, + 134517.67029955584, + 134543.20577071316, + 134568.74245354676, + 134594.28034794159, + 134619.81945378278, + 134645.35977095537, + 134670.90129934452, + 134696.4440388353, + 134721.98798931291, + 134747.53315066252, + 134773.07952276937, + 134798.62710551871, + 134824.17589879577, + 134849.72590248589, + 134875.27711647438, + 134900.82954064661, + 134926.38317488792, + 134951.93801908373, + 134977.49407311951, + 135003.05133688069, + 135028.60981025276, + 135054.16949312127, + 135079.73038537172, + 135105.29248688967, + 135130.85579756077, + 135156.42031727062, + 135181.98604590484, + 135207.55298334916, + 135233.12112948924, + 135258.69048421088, + 135284.26104739975, + 135309.83281894168, + 135335.4057987225, + 135360.97998662802, + 135386.55538254412, + 135412.13198635669, + 135437.70979795168, + 135463.28881721498, + 135488.86904403262, + 135514.45047829056, + 135540.03311987486, + 135565.61696867159, + 135591.20202456677, + 135616.78828744654, + 135642.37575719706, + 135667.96443370447, + 135693.55431685498, + 135719.14540653475, + 135744.73770263011, + 135770.33120502727, + 135795.92591361253, + 135821.52182827223, + 135847.11894889272, + 135872.7172753604, + 135898.31680756161, + 135923.91754538284, + 135949.51948871053, + 135975.12263743114, + 136000.72699143123, + 136026.33255059729, + 136051.93931481591, + 136077.54728397369, + 136103.15645795723, + 136128.76683665317, + 136154.37841994822, + 136179.99120772901, + 136205.60519988232, + 136231.2203962949, + 136256.83679685349, + 136282.45440144493, + 136308.07320995603, + 136333.69322227367, + 136359.31443828469, + 136384.93685787608, + 136410.56048093468, + 136436.18530734754, + 136461.81133700156, + 136487.43856978384, + 136513.06700558143, + 136538.6966442813, + 136564.32748577066, + 136589.95952993655, + 136615.59277666616, + 136641.22722584667, + 136666.86287736523, + 136692.49973110916, + 136718.13778696564, + 136743.77704482197, + 136769.41750456547, + 136795.05916608346, + 136820.70202926331, + 136846.34609399244, + 136871.99136015819, + 136897.63782764805, + 136923.28549634948, + 136948.93436614997, + 136974.58443693706, + 137000.23570859825, + 137025.88818102115, + 137051.54185409332, + 137077.19672770242, + 137102.85280173609, + 137128.51007608202, + 137154.16855062786, + 137179.82822526142, + 137205.48909987041, + 137231.15117434258, + 137256.8144485658, + 137282.47892242789, + 137308.14459581667, + 137333.81146862009, + 137359.47954072602, + 137385.14881202241, + 137410.81928239719, + 137436.49095173844, + 137462.16381993407, + 137487.83788687221, + 137513.51315244089, + 137539.18961652822, + 137564.86727902229, + 137590.54613981131, + 137616.22619878338, + 137641.90745582676, + 137667.58991082967, + 137693.27356368033, + 137718.95841426702, + 137744.64446247809, + 137770.33170820182, + 137796.02015132661, + 137821.70979174081, + 137847.40062933284, + 137873.09266399115, + 137898.78589560417, + 137924.48032406042, + 137950.17594924837, + 137975.8727710566, + 138001.57078937365, + 138027.27000408815, + 138052.97041508864, + 138078.67202226384, + 138104.3748255024, + 138130.07882469296, + 138155.78401972432, + 138181.49041048516, + 138207.1979968643, + 138232.9067787505, + 138258.61675603263, + 138284.32792859949, + 138310.04029633995, + 138335.75385914298, + 138361.46861689744, + 138387.18456949232, + 138412.90171681659, + 138438.62005875923, + 138464.33959520931, + 138490.06032605586, + 138515.78225118798, + 138541.50537049473, + 138567.2296838653, + 138592.95519118884, + 138618.68189235451, + 138644.40978725153, + 138670.13887576913, + 138695.86915779658, + 138721.60063322316, + 138747.33330193823, + 138773.06716383106, + 138798.80221879104, + 138824.53846670757, + 138850.27590747006, + 138876.01454096794, + 138901.7543670907, + 138927.49538572782, + 138953.2375967688, + 138978.9810001032, + 139004.72559562061, + 139030.47138321059, + 139056.2183627628, + 139081.96653416683, + 139107.71589731239, + 139133.46645208917, + 139159.21819838689, + 139184.97113609532, + 139210.72526510421, + 139236.48058530336, + 139262.23709658257, + 139287.99479883176, + 139313.75369194071, + 139339.51377579942, + 139365.27505029776, + 139391.03751532568, + 139416.80117077316, + 139442.56601653024, + 139468.33205248689, + 139494.09927853322, + 139519.86769455927, + 139545.63730045516, + 139571.408096111, + 139597.18008141697, + 139622.95325626322, + 139648.72762054001, + 139674.5031741375, + 139700.27991694602, + 139726.05784885579, + 139751.83696975713, + 139777.61727954043, + 139803.39877809596, + 139829.18146531415, + 139854.96534108539, + 139880.75040530015, + 139906.53665784886, + 139932.32409862199, + 139958.11272751007, + 139983.90254440365, + 140009.69354919327, + 140035.48574176949, + 140061.27912202294, + 140087.07368984428, + 140112.86944512415, + 140138.66638775321, + 140164.4645176222, + 140190.26383462184, + 140216.06433864293, + 140241.86602957622, + 140267.66890731253, + 140293.47297174268, + 140319.27822275754, + 140345.08466024802, + 140370.89228410498, + 140396.70109421943, + 140422.51109048226, + 140448.32227278448, + 140474.13464101712, + 140499.94819507122, + 140525.76293483781, + 140551.57886020801, + 140577.3959710729, + 140603.21426732364, + 140629.03374885136, + 140654.85441554731, + 140680.67626730262, + 140706.49930400858, + 140732.32352555645, + 140758.1489318375, + 140783.97552274304, + 140809.80329816442, + 140835.63225799298, + 140861.46240212015, + 140887.29373043729, + 140913.12624283586, + 140938.95993920733, + 140964.79481944317, + 140990.63088343487, + 141016.46813107401, + 141042.30656225214, + 141068.14617686081, + 141093.98697479168, + 141119.82895593636, + 141145.6721201865, + 141171.51646743377, + 141197.36199756994, + 141223.20871048668, + 141249.05660607578, + 141274.90568422904, + 141300.75594483822, + 141326.6073877952, + 141352.4600129918, + 141378.31382031992, + 141404.16880967148, + 141430.02498093838, + 141455.8823340126, + 141481.74086878612, + 141507.60058515094, + 141533.46148299909, + 141559.32356222265, + 141585.18682271364, + 141611.05126436421, + 141636.9168870665, + 141662.78369071262, + 141688.65167519479, + 141714.5208404052, + 141740.39118623605, + 141766.26271257963, + 141792.1354193282, + 141818.00930637406, + 141843.88437360956, + 141869.760620927, + 141895.6380482188, + 141921.51665537735, + 141947.39644229505, + 141973.27740886438, + 141999.15955497778, + 142025.04288052776, + 142050.92738540689, + 142076.81306950765, + 142102.69993272264, + 142128.58797494444, + 142154.47719606571, + 142180.36759597904, + 142206.25917457714, + 142232.15193175265, + 142258.04586739838, + 142283.94098140698, + 142309.83727367126, + 142335.73474408401, + 142361.63339253806, + 142387.5332189262, + 142413.43422314132, + 142439.33640507635, + 142465.23976462413, + 142491.14430167765, + 142517.05001612983, + 142542.95690787368, + 142568.86497680223, + 142594.77422280848, + 142620.68464578551, + 142646.5962456264, + 142672.50902222423, + 142698.42297547215, + 142724.33810526333, + 142750.25441149093, + 142776.17189404817, + 142802.09055282827, + 142828.01038772447, + 142853.93139863008, + 142879.85358543837, + 142905.77694804268, + 142931.70148633636, + 142957.62720021277, + 142983.55408956532, + 143009.48215428743, + 143035.41139427255, + 143061.34180941415, + 143087.27339960571, + 143113.20616474075, + 143139.14010471283, + 143165.07521941551, + 143191.01150874238, + 143216.94897258704, + 143242.88761084314, + 143268.82742340435, + 143294.76841016437, + 143320.71057101688, + 143346.65390585564, + 143372.59841457437, + 143398.54409706692, + 143424.49095322701, + 143450.43898294857, + 143476.38818612538, + 143502.33856265133, + 143528.29011242036, + 143554.24283532638, + 143580.19673126334, + 143606.1518001252, + 143632.10804180597, + 143658.06545619969, + 143684.02404320039, + 143709.98380270213, + 143735.944734599, + 143761.90683878519, + 143787.87011515474, + 143813.83456360188, + 143839.8001840208, + 143865.76697630569, + 143891.73494035081, + 143917.7040760504, + 143943.67438329876, + 143969.6458619902, + 143995.61851201905, + 144021.59233327967, + 144047.56732566646, + 144073.54348907378, + 144099.52082339607, + 144125.49932852783, + 144151.4790043635, + 144177.45985079758, + 144203.44186772458, + 144229.42505503909, + 144255.40941263564, + 144281.39494040885, + 144307.38163825331, + 144333.36950606373, + 144359.35854373468, + 144385.34875116093, + 144411.34012823718, + 144437.33267485813, + 144463.32639091855, + 144489.32127631325, + 144515.31733093705, + 144541.31455468474, + 144567.3129474512, + 144593.3125091313, + 144619.31323961995, + 144645.31513881206, + 144671.31820660262, + 144697.32244288657, + 144723.32784755889, + 144749.33442051467, + 144775.34216164888, + 144801.35107085665, + 144827.36114803303, + 144853.37239307314, + 144879.38480587213, + 144905.39838632516, + 144931.41313432742, + 144957.4290497741, + 144983.44613256046, + 145009.46438258173, + 145035.48379973322, + 145061.50438391021, + 145087.52613500805, + 145113.54905292206, + 145139.57313754765, + 145165.59838878017, + 145191.62480651509, + 145217.65239064783, + 145243.68114107384, + 145269.71105768863, + 145295.74214038774, + 145321.77438906668, + 145347.80780362099, + 145373.84238394629, + 145399.87812993818, + 145425.91504149229, + 145451.95311850426, + 145477.9923608698, + 145504.03276848458, + 145530.07434124436, + 145556.11707904484, + 145582.16098178181, + 145608.20604935108, + 145634.25228164849, + 145660.29967856981, + 145686.34824001096, + 145712.39796586783, + 145738.4488560363, + 145764.50091041232, + 145790.55412889185, + 145816.60851137087, + 145842.66405774537, + 145868.72076791141, + 145894.77864176501, + 145920.83767920226, + 145946.89788011924, + 145972.95924441208, + 145999.02177197693, + 146025.08546270995, + 146051.15031650732, + 146077.21633326527, + 146103.28351288004, + 146129.35185524789, + 146155.42136026506, + 146181.49202782792, + 146207.56385783272, + 146233.63685017588, + 146259.71100475377, + 146285.78632146274, + 146311.86280019928, + 146337.94044085976, + 146364.01924334071, + 146390.09920753856, + 146416.18033334985, + 146442.26262067116, + 146468.34606939898, + 146494.43067942993, + 146520.51645066062, + 146546.60338298764, + 146572.69147630769, + 146598.78073051744, + 146624.87114551352, + 146650.96272119274, + 146677.05545745179, + 146703.14935418745, + 146729.2444112965, + 146755.34062867577, + 146781.43800622207, + 146807.53654383228, + 146833.63624140329, + 146859.73709883197, + 146885.83911601527, + 146911.94229285014, + 146938.04662923355, + 146964.15212506248, + 146990.25878023397, + 147016.36659464505, + 147042.47556819281, + 147068.58570077427, + 147094.6969922866, + 147120.80944262692, + 147146.92305169237, + 147173.03781938017, + 147199.15374558745, + 147225.27083021149, + 147251.38907314953, + 147277.50847429881, + 147303.62903355664, + 147329.75075082036, + 147355.87362598727, + 147381.99765895473, + 147408.12284962015, + 147434.24919788091, + 147460.37670363448, + 147486.50536677826, + 147512.63518720976, + 147538.76616482646, + 147564.89829952587, + 147591.03159120557, + 147617.16603976308, + 147643.30164509601, + 147669.43840710199, + 147695.57632567859, + 147721.71540072354, + 147747.85563213445, + 147773.99701980909, + 147800.13956364512, + 147826.28326354033, + 147852.42811939248, + 147878.57413109933, + 147904.72129855872, + 147930.86962166851, + 147957.01910032652, + 147983.16973443062, + 148009.32152387875, + 148035.47446856883, + 148061.62856839882, + 148087.78382326665, + 148113.94023307035, + 148140.09779770792, + 148166.25651707739, + 148192.41639107687, + 148218.57741960438, + 148244.73960255808, + 148270.90293983606, + 148297.0674313365, + 148323.23307695755, + 148349.39987659742, + 148375.56783015432, + 148401.73693752653, + 148427.90719861226, + 148454.07861330983, + 148480.25118151752, + 148506.42490313368, + 148532.59977805667, + 148558.77580618486, + 148584.95298741665, + 148611.13132165043, + 148637.31080878471, + 148663.49144871789, + 148689.6732413485, + 148715.85618657502, + 148742.040284296, + 148768.22553440998, + 148794.41193681557, + 148820.59949141133, + 148846.78819809589, + 148872.97805676793, + 148899.16906732606, + 148925.36122966901, + 148951.55454369547, + 148977.74900930419, + 149003.9446263939, + 149030.1413948634, + 149056.33931461151, + 149082.53838553699, + 149108.73860753875, + 149134.9399805156, + 149161.14250436646, + 149187.34617899026, + 149213.5510042859, + 149239.75698015234, + 149265.96410648854, + 149292.17238319354, + 149318.38181016635, + 149344.59238730598, + 149370.80411451156, + 149397.01699168212, + 149423.23101871679, + 149449.44619551473, + 149475.66252197503, + 149501.87999799693, + 149528.0986234796, + 149554.31839832227, + 149580.53932242419, + 149606.76139568459, + 149632.98461800278, + 149659.20898927809, + 149685.43450940982, + 149711.66117829733, + 149737.88899584001, + 149764.11796193724, + 149790.34807648844, + 149816.57933939309, + 149842.81175055061, + 149869.04530986046, + 149895.28001722222, + 149921.51587253538, + 149947.75287569952, + 149973.99102661415, + 150000.23032517891, + 150026.47077129342, + 150052.71236485732, + 150078.95510577026, + 150105.1989939319, + 150131.444029242, + 150157.69021160025, + 150183.93754090639, + 150210.18601706024, + 150236.43563996154, + 150262.68640951012, + 150288.93832560582, + 150315.19138814852, + 150341.44559703805, + 150367.70095217437, + 150393.95745345735, + 150420.21510078697, + 150446.47389406321, + 150472.73383318601, + 150498.99491805542, + 150525.25714857146, + 150551.52052463419, + 150577.78504614369, + 150604.05071300003, + 150630.31752510337, + 150656.58548235384, + 150682.85458465159, + 150709.1248318968, + 150735.39622398972, + 150761.66876083051, + 150787.9424423195, + 150814.21726835691, + 150840.49323884305, + 150866.77035367821, + 150893.04861276277, + 150919.32801599705, + 150945.60856328148, + 150971.89025451642, + 150998.17308960229, + 151024.45706843957, + 151050.74219092872, + 151077.02845697021, + 151103.31586646455, + 151129.60441931229, + 151155.894115414, + 151182.1849546702, + 151208.47693698155, + 151234.77006224863, + 151261.06433037209, + 151287.35974125259, + 151313.65629479082, + 151339.95399088747, + 151366.25282944329, + 151392.55281035902, + 151418.85393353543, + 151445.1561988733, + 151471.45960627345, + 151497.76415563675, + 151524.06984686397, + 151550.37667985607, + 151576.68465451393, + 151602.99377073845, + 151629.30402843058, + 151655.61542749128, + 151681.92796782157, + 151708.24164932242, + 151734.55647189484, + 151760.87243543993, + 151787.18953985872, + 151813.50778505235, + 151839.82717092187, + 151866.14769736846, + 151892.46936429327, + 151918.79217159748, + 151945.11611918229, + 151971.44120694889, + 151997.76743479856, + 152024.09480263255, + 152050.42331035214, + 152076.75295785864, + 152103.08374505339, + 152129.41567183775, + 152155.74873811303, + 152182.08294378067, + 152208.41828874208, + 152234.75477289871, + 152261.09239615197, + 152287.43115840337, + 152313.77105955439, + 152340.11209950657, + 152366.45427816146, + 152392.79759542056, + 152419.14205118554, + 152445.48764535793, + 152471.8343778394, + 152498.18224853161, + 152524.53125733617, + 152550.88140415482, + 152577.23268888926, + 152603.58511144121, + 152629.93867171241, + 152656.29336960468, + 152682.64920501978, + 152709.00617785956, + 152735.36428802583, + 152761.72353542043, + 152788.08391994529, + 152814.44544150229, + 152840.80809999333, + 152867.17189532038, + 152893.53682738543, + 152919.90289609041, + 152946.27010133737, + 152972.63844302832, + 152999.00792106529, + 153025.37853535041, + 153051.7502857857, + 153078.12317227334, + 153104.4971947154, + 153130.8723530141, + 153157.24864707157, + 153183.62607679001, + 153210.00464207167, + 153236.38434281875, + 153262.76517893354, + 153289.14715031831, + 153315.53025687535, + 153341.91449850702, + 153368.2998751156, + 153394.68638660354, + 153421.07403287315, + 153447.46281382689, + 153473.85272936718, + 153500.24377939643, + 153526.63596381716, + 153553.02928253182, + 153579.42373544298, + 153605.81932245308, + 153632.21604346478, + 153658.61389838057, + 153685.0128871031, + 153711.41300953497, + 153737.81426557881, + 153764.21665513728, + 153790.62017811305, + 153817.02483440886, + 153843.43062392739, + 153869.83754657139, + 153896.24560224367, + 153922.65479084692, + 153949.06511228404, + 153975.4765664578, + 154001.88915327107, + 154028.30287262669, + 154054.71772442761, + 154081.13370857667, + 154107.55082497682, + 154133.96907353101, + 154160.38845414223, + 154186.80896671346, + 154213.23061114774, + 154239.65338734805, + 154266.07729521746, + 154292.50233465908, + 154318.92850557598, + 154345.35580787127, + 154371.7842414481, + 154398.21380620965, + 154424.64450205903, + 154451.07632889951, + 154477.50928663427, + 154503.94337516659, + 154530.37859439969, + 154556.81494423689, + 154583.25242458144, + 154609.69103533673, + 154636.13077640603, + 154662.57164769279, + 154689.01364910032, + 154715.45678053208, + 154741.90104189145, + 154768.34643308193, + 154794.79295400696, + 154821.24060457002, + 154847.68938467462, + 154874.13929422433, + 154900.59033312264, + 154927.04250127316, + 154953.49579857948, + 154979.95022494521, + 155006.40578027396, + 155032.86246446942, + 155059.32027743524, + 155085.77921907514, + 155112.2392892928, + 155138.70048799197, + 155165.16281507642, + 155191.62627044989, + 155218.09085401625, + 155244.55656567923, + 155271.02340534274, + 155297.49137291059, + 155323.96046828668, + 155350.4306913749, + 155376.90204207919, + 155403.37452030348, + 155429.84812595171, + 155456.32285892789, + 155482.79871913602, + 155509.27570648011, + 155535.75382086422, + 155562.23306219239, + 155588.71343036872, + 155615.19492529731, + 155641.67754688227, + 155668.16129502779, + 155694.64616963797, + 155721.13217061706, + 155747.61929786921, + 155774.10755129869, + 155800.59693080973, + 155827.08743630661, + 155853.57906769359, + 155880.07182487496, + 155906.56570775513, + 155933.06071623837, + 155959.55685022907, + 155986.05410963166, + 156012.5524943505, + 156039.05200429002, + 156065.55263935472, + 156092.054399449, + 156118.5572844774, + 156145.06129434443, + 156171.5664289546, + 156198.07268821247, + 156224.5800720226, + 156251.08858028959, + 156277.59821291809, + 156304.10896981266, + 156330.62085087801, + 156357.1338560188, + 156383.64798513969, + 156410.16323814544, + 156436.67961494075, + 156463.1971154304, + 156489.71573951913, + 156516.23548711176, + 156542.75635811311, + 156569.27835242799, + 156595.80146996127, + 156622.32571061782, + 156648.85107430254, + 156675.37756092031, + 156701.90517037612, + 156728.43390257491, + 156754.96375742162, + 156781.49473482129, + 156808.02683467892, + 156834.5600568995, + 156861.09440138817, + 156887.62986804993, + 156914.16645678994, + 156940.70416751326, + 156967.24300012505, + 156993.78295453047, + 157020.32403063469, + 157046.8662283429, + 157073.40954756032, + 157099.9539881922, + 157126.49955014378, + 157153.04623332032, + 157179.59403762716, + 157206.14296296958, + 157232.69300925292, + 157259.24417638258, + 157285.79646426387, + 157312.34987280221, + 157338.90440190304, + 157365.46005147175, + 157392.01682141385, + 157418.57471163478, + 157445.13372204005, + 157471.69385253513, + 157498.25510302564, + 157524.81747341706, + 157551.38096361503, + 157577.9455735251, + 157604.51130305286, + 157631.07815210402, + 157657.64612058419, + 157684.21520839902, + 157710.78541545427, + 157737.35674165559, + 157763.92918690876, + 157790.50275111952, + 157817.07743419363, + 157843.65323603692, + 157870.23015655516, + 157896.80819565422, + 157923.3873532399, + 157949.96762921812, + 157976.54902349479, + 158003.13153597576, + 158029.71516656701, + 158056.29991517449, + 158082.88578170416, + 158109.47276606198, + 158136.06086815402, + 158162.65008788629, + 158189.24042516484, + 158215.83187989573, + 158242.42445198505, + 158269.01814133892, + 158295.61294786347, + 158322.20887146486, + 158348.80591204923, + 158375.4040695228, + 158402.00334379176, + 158428.60373476235, + 158455.2052423408, + 158481.80786643337, + 158508.41160694641, + 158535.01646378616, + 158561.62243685898, + 158588.2295260712, + 158614.8377313292, + 158641.44705253936, + 158668.05748960807, + 158694.66904244179, + 158721.28171094693, + 158747.89549502998, + 158774.5103945974, + 158801.12640955573, + 158827.74353981143, + 158854.36178527112, + 158880.9811458413, + 158907.60162142856, + 158934.22321193956, + 158960.84591728085, + 158987.46973735912, + 159014.09467208097, + 159040.72072135314, + 159067.3478850823, + 159093.97616317519, + 159120.60555553852, + 159147.23606207906, + 159173.8676827036, + 159200.50041731889, + 159227.13426583182, + 159253.76922814918, + 159280.40530417781, + 159307.04249382461, + 159333.68079699649, + 159360.32021360032, + 159386.96074354305, + 159413.60238673165, + 159440.24514307309, + 159466.88901247433, + 159493.53399484244, + 159520.18009008438, + 159546.82729810724, + 159573.47561881805, + 159600.12505212394, + 159626.77559793202, + 159653.42725614941, + 159680.08002668325, + 159706.73390944069, + 159733.38890432892, + 159760.04501125516, + 159786.70223012666, + 159813.36056085059, + 159840.02000333427, + 159866.68055748497, + 159893.34222320997, + 159920.00500041663, + 159946.66888901225, + 159973.33388890422, + 159999.99999999988, + 160026.66722220668, + 160053.33555543202, + 160080.0049995833, + 160106.67555456801, + 160133.3472202936, + 160160.0199966676, + 160186.6938835975, + 160213.36888099083, + 160240.04498875517, + 160266.72220679806, + 160293.40053502709, + 160320.07997334987, + 160346.76052167406, + 160373.44217990729, + 160400.1249479572, + 160426.80882573154, + 160453.49381313793, + 160480.17991008417, + 160506.86711647795, + 160533.55543222709, + 160560.24485723933, + 160586.93539142248, + 160613.62703468435, + 160640.31978693281, + 160667.01364807569, + 160693.70861802087, + 160720.40469667627, + 160747.1018839498, + 160773.80017974938, + 160800.49958398298, + 160827.20009655855, + 160853.90171738411, + 160880.60444636765, + 160907.30828341722, + 160934.01322844089, + 160960.71928134665, + 160987.42644204266, + 161014.13471043704, + 161040.84408643784, + 161067.55456995327, + 161094.26616089148, + 161120.97885916062, + 161147.69266466892, + 161174.40757732463, + 161201.12359703594, + 161227.84072371112, + 161254.55895725847, + 161281.27829758628, + 161307.99874460287, + 161334.72029821656, + 161361.44295833571, + 161388.1667248687, + 161414.89159772391, + 161441.61757680977, + 161468.34466203468, + 161495.07285330712, + 161521.80215053557, + 161548.53255362847, + 161575.26406249436, + 161601.99667704175, + 161628.7303971792, + 161655.46522281526, + 161682.20115385848, + 161708.93819021754, + 161735.67633180099, + 161762.41557851751, + 161789.15593027571, + 161815.89738698432, + 161842.63994855201, + 161869.38361488748, + 161896.1283858995, + 161922.87426149679, + 161949.62124158812, + 161976.36932608229, + 162003.1185148881, + 162029.8688079144, + 162056.62020507001, + 162083.37270626382, + 162110.12631140469, + 162136.88102040152, + 162163.63683316324, + 162190.39374959879, + 162217.15176961714, + 162243.91089312723, + 162270.67112003808, + 162297.43245025873, + 162324.19488369819, + 162350.9584202655, + 162377.72305986975, + 162404.48880242003, + 162431.25564782543, + 162458.02359599507, + 162484.79264683815, + 162511.56280026378, + 162538.33405618116, + 162565.10641449949, + 162591.87987512801, + 162618.65443797593, + 162645.43010295252, + 162672.20686996708, + 162698.98473892888, + 162725.76370974723, + 162752.54378233149, + 162779.32495659095, + 162806.10723243505, + 162832.89060977317, + 162859.67508851466, + 162886.46066856899, + 162913.24734984562, + 162940.03513225398, + 162966.82401570358, + 162993.6140001039, + 163020.40508536444, + 163047.19727139481, + 163073.99055810447, + 163100.78494540305, + 163127.58043320014, + 163154.37702140535, + 163181.17470992831, + 163207.97349867865, + 163234.77338756606, + 163261.57437650024, + 163288.37646539087, + 163315.17965414765, + 163341.98394268038, + 163368.78933089875, + 163395.59581871261, + 163422.40340603172, + 163449.2120927659, + 163476.02187882498, + 163502.83276411882, + 163529.6447485573, + 163556.45783205028, + 163583.2720145077, + 163610.08729583945, + 163636.90367595552, + 163663.72115476584, + 163690.53973218042, + 163717.35940810922, + 163744.18018246227, + 163771.00205514964, + 163797.82502608138, + 163824.64909516752, + 163851.4742623182, + 163878.3005274435, + 163905.12789045356, + 163931.95635125853, + 163958.78590976857, + 163985.61656589387, + 164012.44831954464, + 164039.28117063109, + 164066.11511906344, + 164092.95016475199, + 164119.78630760699, + 164146.62354753874, + 164173.46188445756, + 164200.30131827376, + 164227.14184889771, + 164253.98347623978, + 164280.82620021031, + 164307.67002071979, + 164334.51493767856, + 164361.3609509971, + 164388.20806058586, + 164415.05626635533, + 164441.905568216, + 164468.75596607837, + 164495.607459853, + 164522.4600494504, + 164549.31373478117, + 164576.16851575591, + 164603.02439228518, + 164629.88136427966, + 164656.73943164994, + 164683.59859430668, + 164710.45885216061, + 164737.32020512238, + 164764.1826531027, + 164791.04619601235, + 164817.91083376206, + 164844.77656626256, + 164871.64339342469, + 164898.51131515924, + 164925.38033137703, + 164952.25044198887, + 164979.1216469057, + 165005.9939460383, + 165032.86733929763, + 165059.7418265946, + 165086.61740784015, + 165113.4940829452}; +#else + #ifdef BIG_IQ_TABLE + #define IQ_TABLE_SIZE 8192 + #else + #define IQ_TABLE_SIZE 1026 + #endif +static const real_t iq_table[IQ_TABLE_SIZE] = {REAL_CONST(0.0), + REAL_CONST(1.0 / 8.0), + REAL_CONST(2.5198420997897464 / 8.0), + REAL_CONST(4.3267487109222245 / 8.0), + REAL_CONST(6.3496042078727974 / 8.0), + REAL_CONST(8.5498797333834844 / 8.0), + REAL_CONST(10.902723556992836 / 8.0), + REAL_CONST(13.390518279406722 / 8.0), + REAL_CONST(15.999999999999998 / 8.0), + REAL_CONST(18.720754407467133 / 8.0), + REAL_CONST(21.544346900318832 / 8.0), + REAL_CONST(24.463780996262464 / 8.0), + REAL_CONST(27.47314182127996 / 8.0), + REAL_CONST(30.567350940369842 / 8.0), + REAL_CONST(33.741991698453212 / 8.0), + REAL_CONST(36.993181114957046 / 8.0), + REAL_CONST(40.317473596635935 / 8.0), + REAL_CONST(43.711787041189993 / 8.0), + REAL_CONST(47.173345095760126 / 8.0), + REAL_CONST(50.699631325716943 / 8.0), + REAL_CONST(54.288352331898118 / 8.0), + REAL_CONST(57.937407704003519 / 8.0), + REAL_CONST(61.6448652744185 / 8.0), + REAL_CONST(65.408940536585988 / 8.0), + REAL_CONST(69.227979374755591 / 8.0), + REAL_CONST(73.100443455321638 / 8.0), + REAL_CONST(77.024897778591622 / 8.0), + REAL_CONST(80.999999999999986 / 8.0), + REAL_CONST(85.024491212518527 / 8.0), + REAL_CONST(89.097187944889555 / 8.0), + REAL_CONST(93.216975178615741 / 8.0), + REAL_CONST(97.382800224133163 / 8.0), + REAL_CONST(101.59366732596474 / 8.0), + REAL_CONST(105.84863288986224 / 8.0), + REAL_CONST(110.14680124343441 / 8.0), + REAL_CONST(114.4873208566006 / 8.0), + REAL_CONST(118.86938096020653 / 8.0), + REAL_CONST(123.29220851090024 / 8.0), + REAL_CONST(127.75506545836058 / 8.0), + REAL_CONST(132.25724627755247 / 8.0), + REAL_CONST(136.79807573413572 / 8.0), + REAL_CONST(141.37690685569191 / 8.0), + REAL_CONST(145.99311908523086 / 8.0), + REAL_CONST(150.6461165966291 / 8.0), + REAL_CONST(155.33532675434674 / 8.0), + REAL_CONST(160.06019870205279 / 8.0), + REAL_CONST(164.82020206673349 / 8.0), + REAL_CONST(169.61482576651861 / 8.0), + REAL_CONST(174.44357691188537 / 8.0), + REAL_CONST(179.30597979112557 / 8.0), + REAL_CONST(184.20157493201927 / 8.0), + REAL_CONST(189.12991823257562 / 8.0), + REAL_CONST(194.09058015449685 / 8.0), + REAL_CONST(199.08314497371677 / 8.0), + REAL_CONST(204.1072100829694 / 8.0), + REAL_CONST(209.16238534187647 / 8.0), + REAL_CONST(214.24829247050752 / 8.0), + REAL_CONST(219.36456448277784 / 8.0), + REAL_CONST(224.51084515641216 / 8.0), + REAL_CONST(229.6867885365223 / 8.0), + REAL_CONST(234.89205847013176 / 8.0), + REAL_CONST(240.12632816923249 / 8.0), + REAL_CONST(245.38927980018505 / 8.0), + REAL_CONST(250.68060409747261 / 8.0), + REAL_CONST(255.99999999999991 / 8.0), + REAL_CONST(261.34717430828869 / 8.0), + REAL_CONST(266.72184136106449 / 8.0), + REAL_CONST(272.12372272986045 / 8.0), + REAL_CONST(277.55254693037961 / 8.0), + REAL_CONST(283.0080491494619 / 8.0), + REAL_CONST(288.48997098659891 / 8.0), + REAL_CONST(293.99806020902247 / 8.0), + REAL_CONST(299.53207051947408 / 8.0), + REAL_CONST(305.0917613358298 / 8.0), + REAL_CONST(310.67689758182206 / 8.0), + REAL_CONST(316.28724948815585 / 8.0), + REAL_CONST(321.92259240337177 / 8.0), + REAL_CONST(327.58270661385535 / 8.0), + REAL_CONST(333.26737717243742 / 8.0), + REAL_CONST(338.97639373507025 / 8.0), + REAL_CONST(344.70955040510125 / 8.0), + REAL_CONST(350.46664558470013 / 8.0), + REAL_CONST(356.24748183302603 / 8.0), + REAL_CONST(362.05186573075139 / 8.0), + REAL_CONST(367.87960775058258 / 8.0), + REAL_CONST(373.73052213344511 / 8.0), + REAL_CONST(379.60442677002078 / 8.0), + REAL_CONST(385.50114308734607 / 8.0), + REAL_CONST(391.42049594019937 / 8.0), + REAL_CONST(397.36231350702371 / 8.0), + REAL_CONST(403.32642719014467 / 8.0), + REAL_CONST(409.31267152006262 / 8.0), + REAL_CONST(415.32088406360799 / 8.0), + REAL_CONST(421.35090533576471 / 8.0), + REAL_CONST(427.40257871497619 / 8.0), + REAL_CONST(433.4757503617617 / 8.0), + REAL_CONST(439.5702691404793 / 8.0), + REAL_CONST(445.68598654408271 / 8.0), + REAL_CONST(451.82275662172759 / 8.0), + REAL_CONST(457.98043590909128 / 8.0), + REAL_CONST(464.15888336127773 / 8.0), + REAL_CONST(470.35796028818726 / 8.0), + REAL_CONST(476.5775302922363 / 8.0), + REAL_CONST(482.81745920832043 / 8.0), + REAL_CONST(489.07761504591741 / 8.0), + REAL_CONST(495.35786793323581 / 8.0), + REAL_CONST(501.65809006331688 / 8.0), + REAL_CONST(507.97815564200368 / 8.0), + REAL_CONST(514.31794083769648 / 8.0), + REAL_CONST(520.67732373281672 / 8.0), + REAL_CONST(527.05618427690604 / 8.0), + REAL_CONST(533.45440424129174 / 8.0), + REAL_CONST(539.87186717525128 / 8.0), + REAL_CONST(546.30845836361505 / 8.0), + REAL_CONST(552.76406478574609 / 8.0), + REAL_CONST(559.23857507584194 / 8.0), + REAL_CONST(565.73187948450413 / 8.0), + REAL_CONST(572.24386984152341 / 8.0), + REAL_CONST(578.77443951983378 / 8.0), + REAL_CONST(585.32348340058843 / 8.0), + REAL_CONST(591.89089783931263 / 8.0), + REAL_CONST(598.47658063309257 / 8.0), + REAL_CONST(605.08043098876044 / 8.0), + REAL_CONST(611.70234949203643 / 8.0), + REAL_CONST(618.3422380775919 / 8.0), + REAL_CONST(624.99999999999977 / 8.0), + REAL_CONST(631.67553980553748 / 8.0), + REAL_CONST(638.36876330481164 / 8.0), + REAL_CONST(645.07957754617485 / 8.0), + REAL_CONST(651.80789078990415 / 8.0), + REAL_CONST(658.55361248311499 / 8.0), + REAL_CONST(665.31665323538357 / 8.0), + REAL_CONST(672.09692479505225 / 8.0), + REAL_CONST(678.8943400261943 / 8.0), + REAL_CONST(685.70881288621433 / 8.0), + REAL_CONST(692.540258404062 / 8.0), + REAL_CONST(699.38859265903977 / 8.0), + REAL_CONST(706.25373276018058 / 8.0), + REAL_CONST(713.13559682617972 / 8.0), + REAL_CONST(720.03410396586037 / 8.0), + REAL_CONST(726.94917425915435 / 8.0), + REAL_CONST(733.88072873858209 / 8.0), + REAL_CONST(740.82868937121543 / 8.0), + REAL_CONST(747.79297904110535 / 8.0), + REAL_CONST(754.77352153216191 / 8.0), + REAL_CONST(761.77024151147043 / 8.0), + REAL_CONST(768.78306451302956 / 8.0), + REAL_CONST(775.81191692189896 / 8.0), + REAL_CONST(782.85672595874246 / 8.0), + REAL_CONST(789.91741966475445 / 8.0), + REAL_CONST(796.99392688695798 / 8.0), + REAL_CONST(804.08617726386274 / 8.0), + REAL_CONST(811.19410121147098 / 8.0), + REAL_CONST(818.31762990962227 / 8.0), + REAL_CONST(825.45669528866563 / 8.0), + REAL_CONST(832.61123001644864 / 8.0), + REAL_CONST(839.78116748561604 / 8.0), + REAL_CONST(846.96644180120552 / 8.0), + REAL_CONST(854.16698776853514 / 8.0), + REAL_CONST(861.38274088137143 / 8.0), + REAL_CONST(868.61363731036977 / 8.0), + REAL_CONST(875.85961389178203 / 8.0), + REAL_CONST(883.12060811641959 / 8.0), + REAL_CONST(890.39655811886757 / 8.0), + REAL_CONST(897.68740266694181 / 8.0), + REAL_CONST(904.99308115138172 / 8.0), + REAL_CONST(912.31353357577188 / 8.0), + REAL_CONST(919.64870054668756 / 8.0), + REAL_CONST(926.99852326405619 / 8.0), + REAL_CONST(934.36294351172899 / 8.0), + REAL_CONST(941.74190364825859 / 8.0), + REAL_CONST(949.13534659787422 / 8.0), + REAL_CONST(956.54321584165211 / 8.0), + REAL_CONST(963.96545540887348 / 8.0), + REAL_CONST(971.40200986856541 / 8.0), + REAL_CONST(978.85282432122176 / 8.0), + REAL_CONST(986.31784439069588 / 8.0), + REAL_CONST(993.7970162162635 / 8.0), + REAL_CONST(1001.29028644485 / 8.0), + REAL_CONST(1008.797602223418 / 8.0), + REAL_CONST(1016.3189111915103 / 8.0), + REAL_CONST(1023.8541614739464 / 8.0), + REAL_CONST(1031.4033016736653 / 8.0), + REAL_CONST(1038.9662808647138 / 8.0), + REAL_CONST(1046.5430485853758 / 8.0), + REAL_CONST(1054.1335548314366 / 8.0), + REAL_CONST(1061.7377500495838 / 8.0), + REAL_CONST(1069.3555851309357 / 8.0), + REAL_CONST(1076.9870114046978 / 8.0), + REAL_CONST(1084.6319806319441 / 8.0), + REAL_CONST(1092.2904449995174 / 8.0), + REAL_CONST(1099.9623571140482 / 8.0), + REAL_CONST(1107.6476699960892 / 8.0), + REAL_CONST(1115.3463370743607 / 8.0), + REAL_CONST(1123.058312180106 / 8.0), + REAL_CONST(1130.7835495415541 / 8.0), + REAL_CONST(1138.5220037784854 / 8.0), + REAL_CONST(1146.273629896901 / 8.0), + REAL_CONST(1154.0383832837879 / 8.0), + REAL_CONST(1161.816219701986 / 8.0), + REAL_CONST(1169.607095285146 / 8.0), + REAL_CONST(1177.4109665327808 / 8.0), + REAL_CONST(1185.2277903054078 / 8.0), + REAL_CONST(1193.0575238197798 / 8.0), + REAL_CONST(1200.9001246442001 / 8.0), + REAL_CONST(1208.7555506939248 / 8.0), + REAL_CONST(1216.6237602266442 / 8.0), + REAL_CONST(1224.5047118380478 / 8.0), + REAL_CONST(1232.3983644574657 / 8.0), + REAL_CONST(1240.3046773435874 / 8.0), + REAL_CONST(1248.2236100802568 / 8.0), + REAL_CONST(1256.1551225723395 / 8.0), + REAL_CONST(1264.099175041662 / 8.0), + REAL_CONST(1272.0557280230228 / 8.0), + REAL_CONST(1280.0247423602691 / 8.0), + REAL_CONST(1288.0061792024444 / 8.0), + REAL_CONST(1295.9999999999995 / 8.0), + REAL_CONST(1304.006166501068 / 8.0), + REAL_CONST(1312.0246407478062 / 8.0), + REAL_CONST(1320.0553850727929 / 8.0), + REAL_CONST(1328.0983620954903 / 8.0), + REAL_CONST(1336.1535347187651 / 8.0), + REAL_CONST(1344.2208661254647 / 8.0), + REAL_CONST(1352.3003197750522 / 8.0), + REAL_CONST(1360.3918594002962 / 8.0), + REAL_CONST(1368.4954490040145 / 8.0), + REAL_CONST(1376.6110528558709 / 8.0), + REAL_CONST(1384.7386354892244 / 8.0), + REAL_CONST(1392.8781616980295 / 8.0), + REAL_CONST(1401.0295965337855 / 8.0), + REAL_CONST(1409.1929053025353 / 8.0), + REAL_CONST(1417.3680535619119 / 8.0), + REAL_CONST(1425.5550071182327 / 8.0), + REAL_CONST(1433.7537320236374 / 8.0), + REAL_CONST(1441.9641945732744 / 8.0), + REAL_CONST(1450.1863613025282 / 8.0), + REAL_CONST(1458.4201989842913 / 8.0), + REAL_CONST(1466.6656746262797 / 8.0), + REAL_CONST(1474.9227554683875 / 8.0), + REAL_CONST(1483.1914089800841 / 8.0), + REAL_CONST(1491.4716028578516 / 8.0), + REAL_CONST(1499.7633050226596 / 8.0), + REAL_CONST(1508.0664836174794 / 8.0), + REAL_CONST(1516.3811070048375 / 8.0), + REAL_CONST(1524.7071437644029 / 8.0), + REAL_CONST(1533.0445626906128 / 8.0), + REAL_CONST(1541.3933327903342 / 8.0), + REAL_CONST(1549.7534232805581 / 8.0), + REAL_CONST(1558.1248035861302 / 8.0), + REAL_CONST(1566.507443337515 / 8.0), + REAL_CONST(1574.9013123685909 / 8.0), + REAL_CONST(1583.3063807144795 / 8.0), + REAL_CONST(1591.7226186094069 / 8.0), + REAL_CONST(1600.1499964845941 / 8.0), + REAL_CONST(1608.58848496618 / 8.0), + REAL_CONST(1617.0380548731737 / 8.0), + REAL_CONST(1625.4986772154357 / 8.0), + REAL_CONST(1633.9703231916887 / 8.0), + REAL_CONST(1642.4529641875577 / 8.0), + REAL_CONST(1650.9465717736346 / 8.0), + REAL_CONST(1659.4511177035752 / 8.0), + REAL_CONST(1667.9665739122186 / 8.0), + REAL_CONST(1676.4929125137353 / 8.0), + REAL_CONST(1685.030105799801 / 8.0), + REAL_CONST(1693.5781262377957 / 8.0), + REAL_CONST(1702.136946469027 / 8.0), + REAL_CONST(1710.7065393069795 / 8.0), + REAL_CONST(1719.2868777355877 / 8.0), + REAL_CONST(1727.8779349075323 / 8.0), + REAL_CONST(1736.4796841425596 / 8.0), + REAL_CONST(1745.092098925825 / 8.0), + REAL_CONST(1753.7151529062583 / 8.0), + REAL_CONST(1762.3488198949503 / 8.0), + REAL_CONST(1770.9930738635628 / 8.0), + REAL_CONST(1779.6478889427597 / 8.0), + REAL_CONST(1788.3132394206564 / 8.0), + REAL_CONST(1796.9890997412947 / 8.0), + REAL_CONST(1805.6754445031333 / 8.0), + REAL_CONST(1814.3722484575621 / 8.0), + REAL_CONST(1823.0794865074322 / 8.0), + REAL_CONST(1831.7971337056094 / 8.0), + REAL_CONST(1840.5251652535437 / 8.0), + REAL_CONST(1849.2635564998579 / 8.0), + REAL_CONST(1858.0122829389563 / 8.0), + REAL_CONST(1866.7713202096493 / 8.0), + REAL_CONST(1875.5406440937966 / 8.0), + REAL_CONST(1884.3202305149687 / 8.0), + REAL_CONST(1893.110055537124 / 8.0), + REAL_CONST(1901.9100953633042 / 8.0), + REAL_CONST(1910.7203263343454 / 8.0), + REAL_CONST(1919.5407249276057 / 8.0), + REAL_CONST(1928.3712677557098 / 8.0), + REAL_CONST(1937.2119315653083 / 8.0), + REAL_CONST(1946.0626932358525 / 8.0), + REAL_CONST(1954.923529778386 / 8.0), + REAL_CONST(1963.79441833435 / 8.0), + REAL_CONST(1972.6753361744036 / 8.0), + REAL_CONST(1981.5662606972594 / 8.0), + REAL_CONST(1990.467169428533 / 8.0), + REAL_CONST(1999.3780400196069 / 8.0), + REAL_CONST(2008.2988502465078 / 8.0), + REAL_CONST(2017.2295780087982 / 8.0), + REAL_CONST(2026.1702013284819 / 8.0), + REAL_CONST(2035.1206983489212 / 8.0), + REAL_CONST(2044.0810473337688 / 8.0), + REAL_CONST(2053.0512266659125 / 8.0), + REAL_CONST(2062.0312148464309 / 8.0), + REAL_CONST(2071.0209904935646 / 8.0), + REAL_CONST(2080.0205323416958 / 8.0), + REAL_CONST(2089.0298192403443 / 8.0), + REAL_CONST(2098.0488301531714 / 8.0), + REAL_CONST(2107.0775441569995 / 8.0), + REAL_CONST(2116.115940440839 / 8.0), + REAL_CONST(2125.1639983049317 / 8.0), + REAL_CONST(2134.2216971597995 / 8.0), + REAL_CONST(2143.2890165253098 / 8.0), + REAL_CONST(2152.3659360297484 / 8.0), + REAL_CONST(2161.4524354089031 / 8.0), + REAL_CONST(2170.5484945051617 / 8.0), + REAL_CONST(2179.6540932666144 / 8.0), + REAL_CONST(2188.7692117461711 / 8.0), + REAL_CONST(2197.8938301006888 / 8.0), + REAL_CONST(2207.0279285901042 / 8.0), + REAL_CONST(2216.1714875765838 / 8.0), + REAL_CONST(2225.324487523676 / 8.0), + REAL_CONST(2234.4869089954782 / 8.0), + REAL_CONST(2243.6587326558101 / 8.0), + REAL_CONST(2252.8399392673982 / 8.0), + REAL_CONST(2262.0305096910702 / 8.0), + REAL_CONST(2271.2304248849537 / 8.0), + REAL_CONST(2280.4396659036897 / 8.0), + REAL_CONST(2289.6582138976523 / 8.0), + REAL_CONST(2298.8860501121762 / 8.0), + REAL_CONST(2308.1231558867926 / 8.0), + REAL_CONST(2317.3695126544767 / 8.0), + REAL_CONST(2326.6251019409005 / 8.0), + REAL_CONST(2335.8899053636933 / 8.0), + REAL_CONST(2345.1639046317132 / 8.0), + REAL_CONST(2354.4470815443233 / 8.0), + REAL_CONST(2363.7394179906792 / 8.0), + REAL_CONST(2373.0408959490205 / 8.0), + REAL_CONST(2382.3514974859731 / 8.0), + REAL_CONST(2391.6712047558558 / 8.0), + REAL_CONST(2400.9999999999991 / 8.0), + REAL_CONST(2410.3378655460651 / 8.0), + REAL_CONST(2419.6847838073813 / 8.0), + REAL_CONST(2429.0407372822747 / 8.0), + REAL_CONST(2438.4057085534191 / 8.0), + REAL_CONST(2447.7796802871858 / 8.0), + REAL_CONST(2457.1626352330004 / 8.0), + REAL_CONST(2466.5545562227112 / 8.0), + REAL_CONST(2475.9554261699564 / 8.0), + REAL_CONST(2485.3652280695474 / 8.0), + REAL_CONST(2494.7839449968492 / 8.0), + REAL_CONST(2504.2115601071737 / 8.0), + REAL_CONST(2513.6480566351788 / 8.0), + REAL_CONST(2523.0934178942675 / 8.0), + REAL_CONST(2532.5476272760025 / 8.0), + REAL_CONST(2542.0106682495189 / 8.0), + REAL_CONST(2551.482524360948 / 8.0), + REAL_CONST(2560.9631792328441 / 8.0), + REAL_CONST(2570.4526165636184 / 8.0), + REAL_CONST(2579.9508201269791 / 8.0), + REAL_CONST(2589.4577737713744 / 8.0), + REAL_CONST(2598.9734614194458 / 8.0), + REAL_CONST(2608.4978670674823 / 8.0), + REAL_CONST(2618.0309747848837 / 8.0), + REAL_CONST(2627.5727687136259 / 8.0), + REAL_CONST(2637.1232330677353 / 8.0), + REAL_CONST(2646.6823521327647 / 8.0), + REAL_CONST(2656.2501102652768 / 8.0), + REAL_CONST(2665.8264918923328 / 8.0), + REAL_CONST(2675.4114815109842 / 8.0), + REAL_CONST(2685.0050636877722 / 8.0), + REAL_CONST(2694.6072230582295 / 8.0), + REAL_CONST(2704.2179443263894 / 8.0), + REAL_CONST(2713.8372122642972 / 8.0), + REAL_CONST(2723.4650117115279 / 8.0), + REAL_CONST(2733.1013275747096 / 8.0), + REAL_CONST(2742.7461448270483 / 8.0), + REAL_CONST(2752.3994485078601 / 8.0), + REAL_CONST(2762.0612237221085 / 8.0), + REAL_CONST(2771.7314556399419 / 8.0), + REAL_CONST(2781.4101294962406 / 8.0), + REAL_CONST(2791.0972305901655 / 8.0), + REAL_CONST(2800.7927442847094 / 8.0), + REAL_CONST(2810.4966560062589 / 8.0), + REAL_CONST(2820.2089512441521 / 8.0), + REAL_CONST(2829.9296155502466 / 8.0), + REAL_CONST(2839.6586345384894 / 8.0), + REAL_CONST(2849.3959938844923 / 8.0), + REAL_CONST(2859.1416793251065 / 8.0), + REAL_CONST(2868.8956766580086 / 8.0), + REAL_CONST(2878.6579717412847 / 8.0), + REAL_CONST(2888.4285504930212 / 8.0), + REAL_CONST(2898.2073988908974 / 8.0), + REAL_CONST(2907.9945029717837 / 8.0), + REAL_CONST(2917.789848831344 / 8.0), + REAL_CONST(2927.5934226236377 / 8.0), + REAL_CONST(2937.4052105607311 / 8.0), + REAL_CONST(2947.2251989123079 / 8.0), + REAL_CONST(2957.0533740052865 / 8.0), + REAL_CONST(2966.8897222234368 / 8.0), + REAL_CONST(2976.734230007005 / 8.0), + REAL_CONST(2986.5868838523397 / 8.0), + REAL_CONST(2996.4476703115197 / 8.0), + REAL_CONST(3006.3165759919889 / 8.0), + REAL_CONST(3016.1935875561908 / 8.0), + REAL_CONST(3026.0786917212095 / 8.0), + REAL_CONST(3035.9718752584108 / 8.0), + REAL_CONST(3045.8731249930906 / 8.0), + REAL_CONST(3055.7824278041207 / 8.0), + REAL_CONST(3065.6997706236039 / 8.0), + REAL_CONST(3075.625140436528 / 8.0), + REAL_CONST(3085.5585242804245 / 8.0), + REAL_CONST(3095.4999092450298 / 8.0), + REAL_CONST(3105.4492824719491 / 8.0), + REAL_CONST(3115.4066311543256 / 8.0), + REAL_CONST(3125.3719425365089 / 8.0), + REAL_CONST(3135.3452039137287 / 8.0), + REAL_CONST(3145.3264026317715 / 8.0), + REAL_CONST(3155.3155260866592 / 8.0), + REAL_CONST(3165.3125617243295 / 8.0), + REAL_CONST(3175.3174970403229 / 8.0), + REAL_CONST(3185.3303195794679 / 8.0), + REAL_CONST(3195.35101693557 / 8.0), + REAL_CONST(3205.3795767511078 / 8.0), + REAL_CONST(3215.4159867169251 / 8.0), + REAL_CONST(3225.460234571929 / 8.0), + REAL_CONST(3235.5123081027928 / 8.0), + REAL_CONST(3245.5721951436558 / 8.0), + REAL_CONST(3255.63988357583 / 8.0), + REAL_CONST(3265.7153613275095 / 8.0), + REAL_CONST(3275.7986163734795 / 8.0), + REAL_CONST(3285.8896367348289 / 8.0), + REAL_CONST(3295.9884104786665 / 8.0), + REAL_CONST(3306.0949257178395 / 8.0), + REAL_CONST(3316.2091706106517 / 8.0), + REAL_CONST(3326.331133360588 / 8.0), + REAL_CONST(3336.4608022160378 / 8.0), + REAL_CONST(3346.5981654700231 / 8.0), + REAL_CONST(3356.7432114599264 / 8.0), + REAL_CONST(3366.8959285672249 / 8.0), + REAL_CONST(3377.0563052172211 / 8.0), + REAL_CONST(3387.2243298787821 / 8.0), + REAL_CONST(3397.3999910640764 / 8.0), + REAL_CONST(3407.5832773283128 / 8.0), + REAL_CONST(3417.7741772694862 / 8.0), + REAL_CONST(3427.9726795281199 / 8.0), + REAL_CONST(3438.1787727870123 / 8.0), + REAL_CONST(3448.3924457709873 / 8.0), + REAL_CONST(3458.6136872466445 / 8.0), + REAL_CONST(3468.8424860221107 / 8.0), + REAL_CONST(3479.0788309467976 / 8.0), + REAL_CONST(3489.3227109111554 / 8.0), + REAL_CONST(3499.5741148464344 / 8.0), + REAL_CONST(3509.8330317244445 / 8.0), + REAL_CONST(3520.0994505573185 / 8.0), + REAL_CONST(3530.3733603972751 / 8.0), + REAL_CONST(3540.6547503363886 / 8.0), + REAL_CONST(3550.9436095063534 / 8.0), + REAL_CONST(3561.239927078258 / 8.0), + REAL_CONST(3571.5436922623535 / 8.0), + REAL_CONST(3581.8548943078308 / 8.0), + REAL_CONST(3592.1735225025936 / 8.0), + REAL_CONST(3602.4995661730372 / 8.0), + REAL_CONST(3612.8330146838275 / 8.0), + REAL_CONST(3623.1738574376814 / 8.0), + REAL_CONST(3633.5220838751502 / 8.0), + REAL_CONST(3643.8776834744031 / 8.0), + REAL_CONST(3654.2406457510142 / 8.0), + REAL_CONST(3664.6109602577494 / 8.0), + REAL_CONST(3674.9886165843564 / 8.0), + REAL_CONST(3685.3736043573545 / 8.0), + REAL_CONST(3695.7659132398294 / 8.0), + REAL_CONST(3706.1655329312248 / 8.0), + REAL_CONST(3716.5724531671399 / 8.0), + REAL_CONST(3726.9866637191262 / 8.0), + REAL_CONST(3737.4081543944876 / 8.0), + REAL_CONST(3747.8369150360782 / 8.0), + REAL_CONST(3758.2729355221072 / 8.0), + REAL_CONST(3768.7162057659411 / 8.0), + REAL_CONST(3779.1667157159077 / 8.0), + REAL_CONST(3789.6244553551055 / 8.0), + REAL_CONST(3800.0894147012082 / 8.0), + REAL_CONST(3810.5615838062768 / 8.0), + REAL_CONST(3821.0409527565694 / 8.0), + REAL_CONST(3831.5275116723533 / 8.0), + REAL_CONST(3842.0212507077194 / 8.0), + REAL_CONST(3852.522160050396 / 8.0), + REAL_CONST(3863.0302299215673 / 8.0), + REAL_CONST(3873.5454505756893 / 8.0), + REAL_CONST(3884.0678123003108 / 8.0), + REAL_CONST(3894.5973054158922 / 8.0), + REAL_CONST(3905.1339202756285 / 8.0), + REAL_CONST(3915.6776472652732 / 8.0), + REAL_CONST(3926.2284768029604 / 8.0), + REAL_CONST(3936.7863993390338 / 8.0), + REAL_CONST(3947.3514053558706 / 8.0), + REAL_CONST(3957.9234853677135 / 8.0), + REAL_CONST(3968.5026299204969 / 8.0), + REAL_CONST(3979.0888295916798 / 8.0), + REAL_CONST(3989.6820749900776 / 8.0), + REAL_CONST(4000.2823567556948 / 8.0), + REAL_CONST(4010.8896655595613 / 8.0), + REAL_CONST(4021.5039921035655 / 8.0), + REAL_CONST(4032.1253271202945 / 8.0), + REAL_CONST(4042.7536613728694 / 8.0), + REAL_CONST(4053.3889856547858 / 8.0), + REAL_CONST(4064.0312907897551 / 8.0), + REAL_CONST(4074.6805676315448 / 8.0), + REAL_CONST(4085.3368070638221 / 8.0), + REAL_CONST(4095.9999999999982 / 8.0), + REAL_CONST(4106.6701373830711 / 8.0), + REAL_CONST(4117.347210185475 / 8.0), + REAL_CONST(4128.0312094089259 / 8.0), + REAL_CONST(4138.722126084268 / 8.0), + REAL_CONST(4149.4199512713267 / 8.0), + REAL_CONST(4160.1246760587583 / 8.0), + REAL_CONST(4170.8362915638982 / 8.0), + REAL_CONST(4181.5547889326181 / 8.0), + REAL_CONST(4192.2801593391769 / 8.0), + REAL_CONST(4203.0123939860741 / 8.0), + REAL_CONST(4213.7514841039101 / 8.0), + REAL_CONST(4224.4974209512384 / 8.0), + REAL_CONST(4235.2501958144258 / 8.0), + REAL_CONST(4246.0098000075095 / 8.0), + REAL_CONST(4256.7762248720574 / 8.0), + REAL_CONST(4267.549461777031 / 8.0), + REAL_CONST(4278.3295021186423 / 8.0), + REAL_CONST(4289.1163373202198 / 8.0), + REAL_CONST(4299.9099588320714 / 8.0), + REAL_CONST(4310.7103581313495 / 8.0), + REAL_CONST(4321.5175267219138 / 8.0), + REAL_CONST(4332.3314561342004 / 8.0), + REAL_CONST(4343.152137925088 / 8.0), + REAL_CONST(4353.9795636777671 / 8.0), + REAL_CONST(4364.8137250016052 / 8.0), + REAL_CONST(4375.6546135320223 / 8.0), + REAL_CONST(4386.5022209303588 / 8.0), + REAL_CONST(4397.3565388837469 / 8.0), + REAL_CONST(4408.2175591049827 / 8.0), + REAL_CONST(4419.0852733324018 / 8.0), + REAL_CONST(4429.9596733297531 / 8.0), + REAL_CONST(4440.8407508860728 / 8.0), + REAL_CONST(4451.7284978155603 / 8.0), + REAL_CONST(4462.6229059574571 / 8.0), + REAL_CONST(4473.5239671759227 / 8.0), + REAL_CONST(4484.4316733599126 / 8.0), + REAL_CONST(4495.3460164230582 / 8.0), + REAL_CONST(4506.2669883035496 / 8.0), + REAL_CONST(4517.1945809640119 / 8.0), + REAL_CONST(4528.1287863913894 / 8.0), + REAL_CONST(4539.069596596828 / 8.0), + REAL_CONST(4550.0170036155587 / 8.0), + REAL_CONST(4560.9709995067806 / 8.0), + REAL_CONST(4571.931576353546 / 8.0), + REAL_CONST(4582.898726262647 / 8.0), + REAL_CONST(4593.8724413645004 / 8.0), + REAL_CONST(4604.8527138130348 / 8.0), + REAL_CONST(4615.8395357855816 / 8.0), + REAL_CONST(4626.8328994827571 / 8.0), + REAL_CONST(4637.8327971283588 / 8.0), + REAL_CONST(4648.8392209692511 / 8.0), + REAL_CONST(4659.8521632752563 / 8.0), + REAL_CONST(4670.8716163390473 / 8.0), + REAL_CONST(4681.8975724760394 / 8.0), + REAL_CONST(4692.9300240242837 / 8.0), + REAL_CONST(4703.9689633443595 / 8.0), + REAL_CONST(4715.0143828192668 / 8.0), + REAL_CONST(4726.0662748543255 / 8.0), + REAL_CONST(4737.1246318770682 / 8.0), + REAL_CONST(4748.1894463371373 / 8.0), + REAL_CONST(4759.2607107061804 / 8.0), + REAL_CONST(4770.3384174777493 / 8.0), + REAL_CONST(4781.4225591671993 / 8.0), + REAL_CONST(4792.5131283115852 / 8.0), + REAL_CONST(4803.6101174695614 / 8.0), + REAL_CONST(4814.7135192212854 / 8.0), + REAL_CONST(4825.8233261683154 / 8.0), + REAL_CONST(4836.9395309335096 / 8.0), + REAL_CONST(4848.0621261609349 / 8.0), + REAL_CONST(4859.1911045157631 / 8.0), + REAL_CONST(4870.3264586841779 / 8.0), + REAL_CONST(4881.4681813732768 / 8.0), + REAL_CONST(4892.6162653109768 / 8.0), + REAL_CONST(4903.7707032459193 / 8.0), + REAL_CONST(4914.931487947375 / 8.0), + REAL_CONST(4926.0986122051509 / 8.0), + REAL_CONST(4937.2720688294967 / 8.0), + REAL_CONST(4948.4518506510112 / 8.0), + REAL_CONST(4959.637950520555 / 8.0), + REAL_CONST(4970.8303613091521 / 8.0), + REAL_CONST(4982.0290759079044 / 8.0), + REAL_CONST(4993.2340872278974 / 8.0), + REAL_CONST(5004.4453882001153 / 8.0), + REAL_CONST(5015.6629717753467 / 8.0), + REAL_CONST(5026.8868309241007 / 8.0), + REAL_CONST(5038.1169586365131 / 8.0), + REAL_CONST(5049.353347922266 / 8.0), + REAL_CONST(5060.5959918104927 / 8.0), + REAL_CONST(5071.8448833496996 / 8.0), + REAL_CONST(5083.1000156076734 / 8.0), + REAL_CONST(5094.3613816713996 / 8.0), + REAL_CONST(5105.6289746469747 / 8.0), + REAL_CONST(5116.9027876595246 / 8.0), + REAL_CONST(5128.18281385312 / 8.0), + REAL_CONST(5139.4690463906918 / 8.0), + REAL_CONST(5150.7614784539473 / 8.0), + REAL_CONST(5162.0601032432933 / 8.0), + REAL_CONST(5173.3649139777472 / 8.0), + REAL_CONST(5184.6759038948594 / 8.0), + REAL_CONST(5195.9930662506322 / 8.0), + REAL_CONST(5207.3163943194386 / 8.0), + REAL_CONST(5218.6458813939435 / 8.0), + REAL_CONST(5229.9815207850224 / 8.0), + REAL_CONST(5241.3233058216847 / 8.0), + REAL_CONST(5252.6712298509919 / 8.0), + REAL_CONST(5264.025286237983 / 8.0), + REAL_CONST(5275.3854683655954 / 8.0), + REAL_CONST(5286.7517696345885 / 8.0), + REAL_CONST(5298.1241834634639 / 8.0), + REAL_CONST(5309.5027032883945 / 8.0), + REAL_CONST(5320.887322563146 / 8.0), + REAL_CONST(5332.2780347589978 / 8.0), + REAL_CONST(5343.6748333646756 / 8.0), + REAL_CONST(5355.0777118862716 / 8.0), + REAL_CONST(5366.4866638471722 / 8.0), + REAL_CONST(5377.901682787985 / 8.0), + REAL_CONST(5389.3227622664635 / 8.0), + REAL_CONST(5400.749895857437 / 8.0), + REAL_CONST(5412.1830771527357 / 8.0), + REAL_CONST(5423.622299761123 / 8.0), + REAL_CONST(5435.067557308219 / 8.0), + REAL_CONST(5446.5188434364318 / 8.0), + REAL_CONST(5457.9761518048872 / 8.0), + REAL_CONST(5469.4394760893592 / 8.0), + REAL_CONST(5480.9088099821975 / 8.0), + REAL_CONST(5492.3841471922606 / 8.0), + REAL_CONST(5503.8654814448455 / 8.0), + REAL_CONST(5515.3528064816201 / 8.0), + REAL_CONST(5526.846116060552 / 8.0), + REAL_CONST(5538.3454039558474 / 8.0), + REAL_CONST(5549.8506639578736 / 8.0), + REAL_CONST(5561.3618898731029 / 8.0), + REAL_CONST(5572.8790755240361 / 8.0), + REAL_CONST(5584.4022147491451 / 8.0), + REAL_CONST(5595.9313014027975 / 8.0), + REAL_CONST(5607.4663293552012 / 8.0), + REAL_CONST(5619.0072924923297 / 8.0), + REAL_CONST(5630.5541847158656 / 8.0), + REAL_CONST(5642.1069999431284 / 8.0), + REAL_CONST(5653.665732107017 / 8.0), + REAL_CONST(5665.230375155943 / 8.0), + REAL_CONST(5676.8009230537655 / 8.0), + REAL_CONST(5688.3773697797333 / 8.0), + REAL_CONST(5699.9597093284156 / 8.0), + REAL_CONST(5711.5479357096474 / 8.0), + REAL_CONST(5723.1420429484588 / 8.0), + REAL_CONST(5734.7420250850209 / 8.0), + REAL_CONST(5746.347876174581 / 8.0), + REAL_CONST(5757.9595902874016 / 8.0), + REAL_CONST(5769.5771615087006 / 8.0), + REAL_CONST(5781.2005839385911 / 8.0), + REAL_CONST(5792.8298516920213 / 8.0), + REAL_CONST(5804.4649588987149 / 8.0), + REAL_CONST(5816.1058997031105 / 8.0), + REAL_CONST(5827.7526682643065 / 8.0), + REAL_CONST(5839.4052587559972 / 8.0), + REAL_CONST(5851.0636653664196 / 8.0), + REAL_CONST(5862.7278822982908 / 8.0), + REAL_CONST(5874.3979037687541 / 8.0), + REAL_CONST(5886.0737240093204 / 8.0), + REAL_CONST(5897.7553372658094 / 8.0), + REAL_CONST(5909.4427377982956 / 8.0), + REAL_CONST(5921.1359198810505 / 8.0), + REAL_CONST(5932.8348778024874 / 8.0), + REAL_CONST(5944.5396058651031 / 8.0), + REAL_CONST(5956.2500983854261 / 8.0), + REAL_CONST(5967.9663496939575 / 8.0), + REAL_CONST(5979.6883541351208 / 8.0), + REAL_CONST(5991.4161060672022 / 8.0), + REAL_CONST(6003.1495998623004 / 8.0), + REAL_CONST(6014.8888299062692 / 8.0), + REAL_CONST(6026.6337905986684 / 8.0), + REAL_CONST(6038.3844763527022 / 8.0), + REAL_CONST(6050.1408815951781 / 8.0), + REAL_CONST(6061.9030007664414 / 8.0), + REAL_CONST(6073.6708283203316 / 8.0), + REAL_CONST(6085.4443587241267 / 8.0), + REAL_CONST(6097.2235864584891 / 8.0), + REAL_CONST(6109.0085060174197 / 8.0), + REAL_CONST(6120.7991119081998 / 8.0), + REAL_CONST(6132.595398651345 / 8.0), + REAL_CONST(6144.3973607805519 / 8.0), + REAL_CONST(6156.2049928426459 / 8.0), + REAL_CONST(6168.0182893975361 / 8.0), + REAL_CONST(6179.8372450181578 / 8.0), + REAL_CONST(6191.6618542904307 / 8.0), + REAL_CONST(6203.4921118132024 / 8.0), + REAL_CONST(6215.3280121982016 / 8.0), + REAL_CONST(6227.1695500699925 / 8.0), + REAL_CONST(6239.0167200659189 / 8.0), + REAL_CONST(6250.8695168360628 / 8.0), + REAL_CONST(6262.7279350431891 / 8.0), + REAL_CONST(6274.5919693627056 / 8.0), + REAL_CONST(6286.4616144826068 / 8.0), + REAL_CONST(6298.3368651034316 / 8.0), + REAL_CONST(6310.2177159382172 / 8.0), + REAL_CONST(6322.1041617124456 / 8.0), + REAL_CONST(6333.9961971640032 / 8.0), + REAL_CONST(6345.8938170431311 / 8.0), + REAL_CONST(6357.7970161123785 / 8.0), + REAL_CONST(6369.7057891465583 / 8.0), + REAL_CONST(6381.6201309327007 / 8.0), + REAL_CONST(6393.5400362700075 / 8.0), + REAL_CONST(6405.4654999698032 / 8.0), + REAL_CONST(6417.3965168554978 / 8.0), + REAL_CONST(6429.3330817625329 / 8.0), + REAL_CONST(6441.2751895383453 / 8.0), + REAL_CONST(6453.2228350423138 / 8.0), + REAL_CONST(6465.176013145724 / 8.0), + REAL_CONST(6477.134718731716 / 8.0), + REAL_CONST(6489.0989466952469 / 8.0), + REAL_CONST(6501.0686919430445 / 8.0), + REAL_CONST(6513.0439493935628 / 8.0), + REAL_CONST(6525.0247139769417 / 8.0), + REAL_CONST(6537.010980634961 / 8.0), + REAL_CONST(6549.002744321001 / 8.0), + REAL_CONST(6560.9999999999973 / 8.0), + REAL_CONST(6573.0027426483985 / 8.0), + REAL_CONST(6585.0109672541284 / 8.0), + REAL_CONST(6597.0246688165371 / 8.0), + REAL_CONST(6609.0438423463656 / 8.0), + REAL_CONST(6621.0684828657004 / 8.0), + REAL_CONST(6633.0985854079354 / 8.0), + REAL_CONST(6645.134145017727 / 8.0), + REAL_CONST(6657.1751567509573 / 8.0), + REAL_CONST(6669.2216156746908 / 8.0), + REAL_CONST(6681.2735168671343 / 8.0), + REAL_CONST(6693.3308554176001 / 8.0), + REAL_CONST(6705.3936264264594 / 8.0), + REAL_CONST(6717.461825005108 / 8.0), + REAL_CONST(6729.535446275926 / 8.0), + REAL_CONST(6741.6144853722335 / 8.0), + REAL_CONST(6753.6989374382601 / 8.0), + REAL_CONST(6765.7887976290967 / 8.0), + REAL_CONST(6777.8840611106634 / 8.0), + REAL_CONST(6789.9847230596661 / 8.0), + REAL_CONST(6802.0907786635626 / 8.0), + REAL_CONST(6814.2022231205201 / 8.0), + REAL_CONST(6826.3190516393797 / 8.0), + REAL_CONST(6838.4412594396181 / 8.0), + REAL_CONST(6850.5688417513074 / 8.0), + REAL_CONST(6862.701793815083 / 8.0), + REAL_CONST(6874.840110882099 / 8.0), + REAL_CONST(6886.9837882139991 / 8.0), + REAL_CONST(6899.1328210828724 / 8.0), + REAL_CONST(6911.2872047712199 / 8.0), + REAL_CONST(6923.4469345719199 / 8.0), + REAL_CONST(6935.6120057881863 / 8.0), + REAL_CONST(6947.7824137335365 / 8.0), + REAL_CONST(6959.9581537317536 / 8.0), + REAL_CONST(6972.1392211168532 / 8.0), + REAL_CONST(6984.3256112330409 / 8.0), + REAL_CONST(6996.5173194346862 / 8.0), + REAL_CONST(7008.7143410862773 / 8.0), + REAL_CONST(7020.9166715623942 / 8.0), + REAL_CONST(7033.1243062476678 / 8.0), + REAL_CONST(7045.3372405367481 / 8.0), + REAL_CONST(7057.5554698342685 / 8.0), + REAL_CONST(7069.7789895548103 / 8.0), + REAL_CONST(7082.0077951228714 / 8.0), + REAL_CONST(7094.2418819728273 / 8.0), + REAL_CONST(7106.4812455489018 / 8.0), + REAL_CONST(7118.7258813051285 / 8.0), + REAL_CONST(7130.9757847053224 / 8.0), + REAL_CONST(7143.2309512230404 / 8.0), + REAL_CONST(7155.4913763415516 / 8.0), + REAL_CONST(7167.7570555538041 / 8.0), + REAL_CONST(7180.0279843623894 / 8.0), + REAL_CONST(7192.3041582795131 / 8.0), + REAL_CONST(7204.5855728269571 / 8.0), + REAL_CONST(7216.8722235360519 / 8.0), + REAL_CONST(7229.1641059476406 / 8.0), + REAL_CONST(7241.4612156120484 / 8.0), + REAL_CONST(7253.7635480890503 / 8.0), + REAL_CONST(7266.0710989478375 / 8.0), + REAL_CONST(7278.3838637669869 / 8.0), + REAL_CONST(7290.7018381344296 / 8.0), + REAL_CONST(7303.0250176474174 / 8.0), + REAL_CONST(7315.3533979124932 / 8.0), + REAL_CONST(7327.6869745454596 / 8.0), + REAL_CONST(7340.0257431713462 / 8.0), + REAL_CONST(7352.3696994243801 / 8.0), + REAL_CONST(7364.7188389479543 / 8.0), + REAL_CONST(7377.0731573945968 / 8.0), + REAL_CONST(7389.4326504259407 / 8.0), + REAL_CONST(7401.7973137126937 / 8.0), + REAL_CONST(7414.1671429346061 / 8.0), + REAL_CONST(7426.5421337804428 / 8.0), + REAL_CONST(7438.922281947951 / 8.0), + REAL_CONST(7451.3075831438346 / 8.0), + REAL_CONST(7463.6980330837177 / 8.0), + REAL_CONST(7476.0936274921214 / 8.0), + REAL_CONST(7488.4943621024304 / 8.0), + REAL_CONST(7500.9002326568652 / 8.0), + REAL_CONST(7513.3112349064522 / 8.0), + REAL_CONST(7525.7273646109943 / 8.0), + REAL_CONST(7538.1486175390446 / 8.0), + REAL_CONST(7550.5749894678729 / 8.0), + REAL_CONST(7563.0064761834419 / 8.0), + REAL_CONST(7575.4430734803736 / 8.0), + REAL_CONST(7587.8847771619248 / 8.0), + REAL_CONST(7600.3315830399597 / 8.0), + REAL_CONST(7612.7834869349153 / 8.0), + REAL_CONST(7625.24048467578 / 8.0), + REAL_CONST(7637.7025721000637 / 8.0), + REAL_CONST(7650.1697450537677 / 8.0), + REAL_CONST(7662.6419993913596 / 8.0), + REAL_CONST(7675.1193309757446 / 8.0), + REAL_CONST(7687.6017356782404 / 8.0), + REAL_CONST(7700.0892093785433 / 8.0), + REAL_CONST(7712.5817479647112 / 8.0), + REAL_CONST(7725.079347333125 / 8.0), + REAL_CONST(7737.5820033884729 / 8.0), + REAL_CONST(7750.0897120437139 / 8.0), + REAL_CONST(7762.6024692200581 / 8.0), + REAL_CONST(7775.1202708469355 / 8.0), + REAL_CONST(7787.6431128619733 / 8.0), + REAL_CONST(7800.1709912109645 / 8.0), + REAL_CONST(7812.7039018478481 / 8.0), + REAL_CONST(7825.2418407346768 / 8.0), + REAL_CONST(7837.7848038415968 / 8.0), + REAL_CONST(7850.3327871468155 / 8.0), + REAL_CONST(7862.8857866365806 / 8.0), + REAL_CONST(7875.4437983051539 / 8.0), + REAL_CONST(7888.006818154784 / 8.0), + REAL_CONST(7900.5748421956796 / 8.0), + REAL_CONST(7913.1478664459901 / 8.0), + REAL_CONST(7925.725886931772 / 8.0), + REAL_CONST(7938.3088996869719 / 8.0), + REAL_CONST(7950.8969007533951 / 8.0), + REAL_CONST(7963.4898861806851 / 8.0), + REAL_CONST(7976.0878520262959 / 8.0), + REAL_CONST(7988.6907943554688 / 8.0), + REAL_CONST(8001.2987092412086 / 8.0), + REAL_CONST(8013.911592764257 / 8.0), + REAL_CONST(8026.5294410130691 / 8.0), + REAL_CONST(8039.1522500837891 / 8.0), + REAL_CONST(8051.7800160802271 / 8.0), + REAL_CONST(8064.412735113835 / 8.0), + REAL_CONST(8077.0504033036796 / 8.0), + REAL_CONST(8089.6930167764222 / 8.0), + REAL_CONST(8102.3405716662946 / 8.0), + REAL_CONST(8114.9930641150731 / 8.0), + REAL_CONST(8127.6504902720571 / 8.0), + REAL_CONST(8140.3128462940449 / 8.0), + REAL_CONST(8152.9801283453098 / 8.0), + REAL_CONST(8165.6523325975786 / 8.0), + REAL_CONST(8178.3294552300049 / 8.0), + REAL_CONST(8191.0114924291529 / 8.0), + REAL_CONST(8203.6984403889655 / 8.0), + REAL_CONST(8216.3902953107463 / 8.0), + REAL_CONST(8229.0870534031419 / 8.0), + REAL_CONST(8241.7887108821069 / 8.0), + REAL_CONST(8254.4952639708936 / 8.0), + REAL_CONST(8267.2067089000211 / 8.0), + REAL_CONST(8279.9230419072574 / 8.0), + REAL_CONST(8292.6442592375952 / 8.0), + REAL_CONST(8305.3703571432306 / 8.0), + REAL_CONST(8318.101331883543 / 8.0), + REAL_CONST(8330.8371797250657 / 8.0), + REAL_CONST(8343.577896941475 / 8.0), + REAL_CONST(8356.3234798135582 / 8.0), + REAL_CONST(8369.0739246291978 / 8.0), + REAL_CONST(8381.8292276833508 / 8.0), + REAL_CONST(8394.5893852780209 / 8.0), + REAL_CONST(8407.3543937222421 / 8.0), + REAL_CONST(8420.1242493320569 / 8.0), + REAL_CONST(8432.8989484304948 / 8.0), + REAL_CONST(8445.6784873475499 / 8.0), + REAL_CONST(8458.4628624201578 / 8.0), + REAL_CONST(8471.2520699921806 / 8.0), + REAL_CONST(8484.0461064143838 / 8.0), + REAL_CONST(8496.8449680444082 / 8.0), + REAL_CONST(8509.6486512467636 / 8.0), + REAL_CONST(8522.4571523927953 / 8.0), + REAL_CONST(8535.270467860666 / 8.0), + REAL_CONST(8548.0885940353437 / 8.0), + REAL_CONST(8560.9115273085663 / 8.0), + REAL_CONST(8573.7392640788403 / 8.0), + REAL_CONST(8586.5718007514006 / 8.0), + REAL_CONST(8599.4091337382069 / 8.0), + REAL_CONST(8612.2512594579148 / 8.0), + REAL_CONST(8625.0981743358552 / 8.0), + REAL_CONST(8637.9498748040205 / 8.0), + REAL_CONST(8650.8063573010386 / 8.0), + REAL_CONST(8663.6676182721567 / 8.0), + REAL_CONST(8676.533654169225 / 8.0), + REAL_CONST(8689.4044614506638 / 8.0), + REAL_CONST(8702.2800365814601 / 8.0), + REAL_CONST(8715.1603760331418 / 8.0), + REAL_CONST(8728.0454762837508 / 8.0), + REAL_CONST(8740.9353338178389 / 8.0), + REAL_CONST(8753.8299451264356 / 8.0), + REAL_CONST(8766.7293067070332 / 8.0), + REAL_CONST(8779.6334150635721 / 8.0), + REAL_CONST(8792.5422667064158 / 8.0), + REAL_CONST(8805.4558581523324 / 8.0), + REAL_CONST(8818.3741859244819 / 8.0), + REAL_CONST(8831.2972465523908 / 8.0), + REAL_CONST(8844.2250365719356 / 8.0), + REAL_CONST(8857.1575525253265 / 8.0), + REAL_CONST(8870.0947909610859 / 8.0), + REAL_CONST(8883.0367484340295 / 8.0), + REAL_CONST(8895.9834215052524 / 8.0), + REAL_CONST(8908.934806742107 / 8.0), + REAL_CONST(8921.8909007181846 / 8.0), + REAL_CONST(8934.8517000132997 / 8.0), + REAL_CONST(8947.817201213471 / 8.0), + REAL_CONST(8960.7874009109 / 8.0), + REAL_CONST(8973.7622957039603 / 8.0), + REAL_CONST(8986.7418821971733 / 8.0), + REAL_CONST(8999.7261570011924 / 8.0), + REAL_CONST(9012.7151167327884 / 8.0), + REAL_CONST(9025.7087580148236 / 8.0), + REAL_CONST(9038.7070774762469 / 8.0), + REAL_CONST(9051.7100717520643 / 8.0), + REAL_CONST(9064.7177374833282 / 8.0), + REAL_CONST(9077.7300713171153 / 8.0), + REAL_CONST(9090.7470699065179 / 8.0), + REAL_CONST(9103.7687299106146 / 8.0), + REAL_CONST(9116.7950479944648 / 8.0), + REAL_CONST(9129.8260208290812 / 8.0), + REAL_CONST(9142.8616450914233 / 8.0), + REAL_CONST(9155.9019174643727 / 8.0), + REAL_CONST(9168.9468346367157 / 8.0), + REAL_CONST(9181.9963933031358 / 8.0), + REAL_CONST(9195.0505901641845 / 8.0), + REAL_CONST(9208.1094219262741 / 8.0), + REAL_CONST(9221.1728853016557 / 8.0), + REAL_CONST(9234.240977008405 / 8.0), + REAL_CONST(9247.3136937704076 / 8.0), + REAL_CONST(9260.3910323173386 / 8.0), + REAL_CONST(9273.472989384647 / 8.0), + REAL_CONST(9286.5595617135423 / 8.0), + REAL_CONST(9299.6507460509747 / 8.0), + REAL_CONST(9312.7465391496207 / 8.0), + REAL_CONST(9325.8469377678684 / 8.0), + REAL_CONST(9338.9519386698012 / 8.0), + REAL_CONST(9352.0615386251757 / 8.0), + REAL_CONST(9365.1757344094131 / 8.0), + REAL_CONST(9378.2945228035842 / 8.0), + REAL_CONST(9391.4179005943843 / 8.0), + REAL_CONST(9404.5458645741273 / 8.0), + REAL_CONST(9417.6784115407263 / 8.0), + REAL_CONST(9430.8155382976747 / 8.0), + REAL_CONST(9443.9572416540359 / 8.0), + REAL_CONST(9457.1035184244265 / 8.0), + REAL_CONST(9470.2543654290002 / 8.0), + REAL_CONST(9483.4097794934296 / 8.0), + REAL_CONST(9496.5697574488931 / 8.0), + REAL_CONST(9509.7342961320664 / 8.0), + REAL_CONST(9522.9033923850911 / 8.0), + REAL_CONST(9536.0770430555804 / 8.0), + REAL_CONST(9549.2552449965824 / 8.0), + REAL_CONST(9562.4379950665825 / 8.0), + REAL_CONST(9575.6252901294793 / 8.0), + REAL_CONST(9588.8171270545736 / 8.0), + REAL_CONST(9602.0135027165488 / 8.0), + REAL_CONST(9615.2144139954635 / 8.0), + REAL_CONST(9628.4198577767274 / 8.0), + REAL_CONST(9641.629830951093 / 8.0), + REAL_CONST(9654.844330414644 / 8.0), + REAL_CONST(9668.0633530687719 / 8.0), + REAL_CONST(9681.286895820167 / 8.0), + REAL_CONST(9694.5149555808002 / 8.0), + REAL_CONST(9707.7475292679192 / 8.0), + REAL_CONST(9720.9846138040157 / 8.0), + REAL_CONST(9734.2262061168276 / 8.0), + REAL_CONST(9747.4723031393187 / 8.0), + REAL_CONST(9760.7229018096641 / 8.0), + REAL_CONST(9773.9779990712323 / 8.0), + REAL_CONST(9787.2375918725811 / 8.0), + REAL_CONST(9800.5016771674327 / 8.0), + REAL_CONST(9813.7702519146696 / 8.0), + REAL_CONST(9827.0433130783094 / 8.0), + REAL_CONST(9840.3208576275028 / 8.0), + REAL_CONST(9853.602882536512 / 8.0), + REAL_CONST(9866.8893847846994 / 8.0), + REAL_CONST(9880.1803613565116 / 8.0), + REAL_CONST(9893.4758092414686 / 8.0), + REAL_CONST(9906.7757254341523 / 8.0), + REAL_CONST(9920.0801069341851 / 8.0), + REAL_CONST(9933.3889507462245 / 8.0), + REAL_CONST(9946.7022538799429 / 8.0), + REAL_CONST(9960.0200133500221 / 8.0), + REAL_CONST(9973.3422261761298 / 8.0), + REAL_CONST(9986.6688893829159 / 8.0), + REAL_CONST(9999.9999999999945 / 8.0), + REAL_CONST(10013.335555061929 / 8.0), + REAL_CONST(10026.675551608221 / 8.0), + REAL_CONST(10040.019986683301 / 8.0), + REAL_CONST(10053.368857336509 / 8.0), + REAL_CONST(10066.722160622081 / 8.0), + REAL_CONST(10080.079893599144 / 8.0), + REAL_CONST(10093.442053331697 / 8.0), + REAL_CONST(10106.808636888598 / 8.0), + REAL_CONST(10120.179641343551 / 8.0), + REAL_CONST(10133.555063775095 / 8.0), + REAL_CONST(10146.934901266595 / 8.0), + REAL_CONST(10160.31915090622 / 8.0), + REAL_CONST(10173.707809786936 / 8.0), + REAL_CONST(10187.100875006496 / 8.0), + REAL_CONST(10200.498343667417 / 8.0), + REAL_CONST(10213.900212876984 / 8.0), + REAL_CONST(10227.306479747222 / 8.0), + REAL_CONST(10240.717141394889 / 8.0), + REAL_CONST(10254.132194941467 / 8.0), + REAL_CONST(10267.551637513146 / 8.0), + REAL_CONST(10280.975466240814 / 8.0), + REAL_CONST(10294.40367826004 / 8.0), + REAL_CONST(10307.836270711066 / 8.0), + REAL_CONST(10321.273240738796 / 8.0), + REAL_CONST(10334.71458549278 / 8.0) + #ifdef BIG_IQ_TABLE + , + REAL_CONST(10348.160302127204 / 8.0), + REAL_CONST(10361.610387800878 / 8.0), + REAL_CONST(10375.064839677221 / 8.0), + REAL_CONST(10388.523654924258 / 8.0), + REAL_CONST(10401.986830714593 / 8.0), + REAL_CONST(10415.454364225412 / 8.0), + REAL_CONST(10428.926252638465 / 8.0), + REAL_CONST(10442.402493140049 / 8.0), + REAL_CONST(10455.883082921007 / 8.0), + REAL_CONST(10469.368019176709 / 8.0), + REAL_CONST(10482.85729910704 / 8.0), + REAL_CONST(10496.350919916393 / 8.0), + REAL_CONST(10509.848878813653 / 8.0), + REAL_CONST(10523.351173012188 / 8.0), + REAL_CONST(10536.857799729838 / 8.0), + REAL_CONST(10550.3687561889 / 8.0), + REAL_CONST(10563.884039616123 / 8.0), + REAL_CONST(10577.403647242685 / 8.0), + REAL_CONST(10590.927576304197 / 8.0), + REAL_CONST(10604.455824040679 / 8.0), + REAL_CONST(10617.988387696556 / 8.0), + REAL_CONST(10631.525264520642 / 8.0), + REAL_CONST(10645.066451766135 / 8.0), + REAL_CONST(10658.611946690598 / 8.0), + REAL_CONST(10672.161746555956 / 8.0), + REAL_CONST(10685.715848628475 / 8.0), + REAL_CONST(10699.274250178762 / 8.0), + REAL_CONST(10712.836948481747 / 8.0), + REAL_CONST(10726.403940816675 / 8.0), + REAL_CONST(10739.975224467091 / 8.0), + REAL_CONST(10753.550796720834 / 8.0), + REAL_CONST(10767.130654870027 / 8.0), + REAL_CONST(10780.714796211059 / 8.0), + REAL_CONST(10794.303218044579 / 8.0), + REAL_CONST(10807.895917675487 / 8.0), + REAL_CONST(10821.492892412922 / 8.0), + REAL_CONST(10835.094139570248 / 8.0), + REAL_CONST(10848.699656465047 / 8.0), + REAL_CONST(10862.309440419107 / 8.0), + REAL_CONST(10875.923488758415 / 8.0), + REAL_CONST(10889.541798813138 / 8.0), + REAL_CONST(10903.16436791762 / 8.0), + REAL_CONST(10916.791193410372 / 8.0), + REAL_CONST(10930.422272634056 / 8.0), + REAL_CONST(10944.05760293548 / 8.0), + REAL_CONST(10957.697181665582 / 8.0), + REAL_CONST(10971.341006179427 / 8.0), + REAL_CONST(10984.98907383619 / 8.0), + REAL_CONST(10998.641381999149 / 8.0), + REAL_CONST(11012.297928035676 / 8.0), + REAL_CONST(11025.958709317223 / 8.0), + REAL_CONST(11039.623723219316 / 8.0), + REAL_CONST(11053.292967121541 / 8.0), + REAL_CONST(11066.966438407539 / 8.0), + REAL_CONST(11080.64413446499 / 8.0), + REAL_CONST(11094.326052685608 / 8.0), + REAL_CONST(11108.012190465128 / 8.0), + REAL_CONST(11121.702545203296 / 8.0), + REAL_CONST(11135.397114303863 / 8.0), + REAL_CONST(11149.095895174571 / 8.0), + REAL_CONST(11162.798885227143 / 8.0), + REAL_CONST(11176.506081877278 / 8.0), + REAL_CONST(11190.217482544635 / 8.0), + REAL_CONST(11203.933084652828 / 8.0), + REAL_CONST(11217.652885629415 / 8.0), + REAL_CONST(11231.376882905886 / 8.0), + REAL_CONST(11245.105073917659 / 8.0), + REAL_CONST(11258.837456104062 / 8.0), + REAL_CONST(11272.574026908333 / 8.0), + REAL_CONST(11286.314783777601 / 8.0), + REAL_CONST(11300.059724162888 / 8.0), + REAL_CONST(11313.808845519083 / 8.0), + REAL_CONST(11327.562145304952 / 8.0), + REAL_CONST(11341.319620983111 / 8.0), + REAL_CONST(11355.081270020033 / 8.0), + REAL_CONST(11368.847089886023 / 8.0), + REAL_CONST(11382.617078055218 / 8.0), + REAL_CONST(11396.391232005579 / 8.0), + REAL_CONST(11410.169549218874 / 8.0), + REAL_CONST(11423.952027180676 / 8.0), + REAL_CONST(11437.738663380349 / 8.0), + REAL_CONST(11451.529455311042 / 8.0), + REAL_CONST(11465.324400469679 / 8.0), + REAL_CONST(11479.123496356951 / 8.0), + REAL_CONST(11492.926740477304 / 8.0), + REAL_CONST(11506.734130338931 / 8.0), + REAL_CONST(11520.545663453764 / 8.0), + REAL_CONST(11534.361337337466 / 8.0), + REAL_CONST(11548.181149509423 / 8.0), + REAL_CONST(11562.005097492724 / 8.0), + REAL_CONST(11575.83317881417 / 8.0), + REAL_CONST(11589.665391004253 / 8.0), + REAL_CONST(11603.501731597149 / 8.0), + REAL_CONST(11617.342198130715 / 8.0), + REAL_CONST(11631.186788146468 / 8.0), + REAL_CONST(11645.035499189589 / 8.0), + REAL_CONST(11658.888328808911 / 8.0), + REAL_CONST(11672.745274556904 / 8.0), + REAL_CONST(11686.606333989675 / 8.0), + REAL_CONST(11700.471504666955 / 8.0), + REAL_CONST(11714.340784152086 / 8.0), + REAL_CONST(11728.214170012021 / 8.0), + REAL_CONST(11742.091659817312 / 8.0), + REAL_CONST(11755.973251142101 / 8.0), + REAL_CONST(11769.858941564111 / 8.0), + REAL_CONST(11783.748728664636 / 8.0), + REAL_CONST(11797.642610028539 / 8.0), + REAL_CONST(11811.540583244237 / 8.0), + REAL_CONST(11825.442645903697 / 8.0), + REAL_CONST(11839.34879560242 / 8.0), + REAL_CONST(11853.259029939445 / 8.0), + REAL_CONST(11867.173346517333 / 8.0), + REAL_CONST(11881.091742942155 / 8.0), + REAL_CONST(11895.014216823492 / 8.0), + REAL_CONST(11908.940765774427 / 8.0), + REAL_CONST(11922.871387411526 / 8.0), + REAL_CONST(11936.806079354839 / 8.0), + REAL_CONST(11950.744839227897 / 8.0), + REAL_CONST(11964.687664657684 / 8.0), + REAL_CONST(11978.634553274653 / 8.0), + REAL_CONST(11992.585502712702 / 8.0), + REAL_CONST(12006.540510609168 / 8.0), + REAL_CONST(12020.499574604828 / 8.0), + REAL_CONST(12034.462692343877 / 8.0), + REAL_CONST(12048.429861473938 / 8.0), + REAL_CONST(12062.401079646032 / 8.0), + REAL_CONST(12076.376344514589 / 8.0), + REAL_CONST(12090.355653737433 / 8.0), + REAL_CONST(12104.339004975769 / 8.0), + REAL_CONST(12118.326395894188 / 8.0), + REAL_CONST(12132.317824160644 / 8.0), + REAL_CONST(12146.313287446457 / 8.0), + REAL_CONST(12160.312783426305 / 8.0), + REAL_CONST(12174.316309778205 / 8.0), + REAL_CONST(12188.323864183525 / 8.0), + REAL_CONST(12202.335444326955 / 8.0), + REAL_CONST(12216.351047896511 / 8.0), + REAL_CONST(12230.370672583531 / 8.0), + REAL_CONST(12244.394316082657 / 8.0), + REAL_CONST(12258.421976091831 / 8.0), + REAL_CONST(12272.453650312296 / 8.0), + REAL_CONST(12286.489336448574 / 8.0), + REAL_CONST(12300.529032208471 / 8.0), + REAL_CONST(12314.572735303058 / 8.0), + REAL_CONST(12328.620443446678 / 8.0), + REAL_CONST(12342.672154356922 / 8.0), + REAL_CONST(12356.727865754638 / 8.0), + REAL_CONST(12370.787575363909 / 8.0), + REAL_CONST(12384.851280912055 / 8.0), + REAL_CONST(12398.918980129623 / 8.0), + REAL_CONST(12412.990670750381 / 8.0), + REAL_CONST(12427.066350511306 / 8.0), + REAL_CONST(12441.146017152583 / 8.0), + REAL_CONST(12455.229668417589 / 8.0), + REAL_CONST(12469.317302052901 / 8.0), + REAL_CONST(12483.40891580827 / 8.0), + REAL_CONST(12497.50450743663 / 8.0), + REAL_CONST(12511.604074694078 / 8.0), + REAL_CONST(12525.707615339878 / 8.0), + REAL_CONST(12539.815127136444 / 8.0), + REAL_CONST(12553.926607849342 / 8.0), + REAL_CONST(12568.042055247275 / 8.0), + REAL_CONST(12582.161467102082 / 8.0), + REAL_CONST(12596.284841188726 / 8.0), + REAL_CONST(12610.41217528529 / 8.0), + REAL_CONST(12624.543467172971 / 8.0), + REAL_CONST(12638.678714636069 / 8.0), + REAL_CONST(12652.817915461985 / 8.0), + REAL_CONST(12666.961067441209 / 8.0), + REAL_CONST(12681.108168367316 / 8.0), + REAL_CONST(12695.259216036962 / 8.0), + REAL_CONST(12709.414208249869 / 8.0), + REAL_CONST(12723.573142808827 / 8.0), + REAL_CONST(12737.736017519681 / 8.0), + REAL_CONST(12751.902830191326 / 8.0), + REAL_CONST(12766.073578635704 / 8.0), + REAL_CONST(12780.248260667788 / 8.0), + REAL_CONST(12794.426874105588 / 8.0), + REAL_CONST(12808.609416770132 / 8.0), + REAL_CONST(12822.795886485468 / 8.0), + REAL_CONST(12836.986281078653 / 8.0), + REAL_CONST(12851.180598379744 / 8.0), + REAL_CONST(12865.378836221802 / 8.0), + REAL_CONST(12879.580992440871 / 8.0), + REAL_CONST(12893.787064875984 / 8.0), + REAL_CONST(12907.997051369144 / 8.0), + REAL_CONST(12922.210949765335 / 8.0), + REAL_CONST(12936.428757912496 / 8.0), + REAL_CONST(12950.650473661524 / 8.0), + REAL_CONST(12964.876094866273 / 8.0), + REAL_CONST(12979.105619383534 / 8.0), + REAL_CONST(12993.339045073039 / 8.0), + REAL_CONST(13007.576369797454 / 8.0), + REAL_CONST(13021.817591422368 / 8.0), + REAL_CONST(13036.062707816285 / 8.0), + REAL_CONST(13050.311716850629 / 8.0), + REAL_CONST(13064.564616399723 / 8.0), + REAL_CONST(13078.821404340792 / 8.0), + REAL_CONST(13093.082078553954 / 8.0), + REAL_CONST(13107.346636922217 / 8.0), + REAL_CONST(13121.615077331464 / 8.0), + REAL_CONST(13135.887397670458 / 8.0), + REAL_CONST(13150.163595830827 / 8.0), + REAL_CONST(13164.44366970706 / 8.0), + REAL_CONST(13178.727617196502 / 8.0), + REAL_CONST(13193.015436199352 / 8.0), + REAL_CONST(13207.307124618648 / 8.0), + REAL_CONST(13221.602680360265 / 8.0), + REAL_CONST(13235.902101332911 / 8.0), + REAL_CONST(13250.205385448118 / 8.0), + REAL_CONST(13264.512530620239 / 8.0), + REAL_CONST(13278.823534766434 / 8.0), + REAL_CONST(13293.138395806676 / 8.0), + REAL_CONST(13307.457111663734 / 8.0), + REAL_CONST(13321.779680263176 / 8.0), + REAL_CONST(13336.106099533356 / 8.0), + REAL_CONST(13350.436367405409 / 8.0), + REAL_CONST(13364.77048181325 / 8.0), + REAL_CONST(13379.108440693562 / 8.0), + REAL_CONST(13393.450241985796 / 8.0), + REAL_CONST(13407.795883632158 / 8.0), + REAL_CONST(13422.145363577607 / 8.0), + REAL_CONST(13436.498679769853 / 8.0), + REAL_CONST(13450.855830159346 / 8.0), + REAL_CONST(13465.216812699266 / 8.0), + REAL_CONST(13479.581625345529 / 8.0), + REAL_CONST(13493.950266056772 / 8.0), + REAL_CONST(13508.32273279435 / 8.0), + REAL_CONST(13522.699023522329 / 8.0), + REAL_CONST(13537.079136207483 / 8.0), + REAL_CONST(13551.463068819286 / 8.0), + REAL_CONST(13565.850819329906 / 8.0), + REAL_CONST(13580.2423857142 / 8.0), + REAL_CONST(13594.63776594971 / 8.0), + REAL_CONST(13609.036958016657 / 8.0), + REAL_CONST(13623.439959897927 / 8.0), + REAL_CONST(13637.846769579081 / 8.0), + REAL_CONST(13652.257385048335 / 8.0), + REAL_CONST(13666.67180429656 / 8.0), + REAL_CONST(13681.090025317284 / 8.0), + REAL_CONST(13695.512046106669 / 8.0), + REAL_CONST(13709.937864663521 / 8.0), + REAL_CONST(13724.367478989278 / 8.0), + REAL_CONST(13738.800887088004 / 8.0), + REAL_CONST(13753.238086966385 / 8.0), + REAL_CONST(13767.679076633727 / 8.0), + REAL_CONST(13782.123854101939 / 8.0), + REAL_CONST(13796.572417385545 / 8.0), + REAL_CONST(13811.024764501659 / 8.0), + REAL_CONST(13825.480893469998 / 8.0), + REAL_CONST(13839.94080231286 / 8.0), + REAL_CONST(13854.404489055134 / 8.0), + REAL_CONST(13868.871951724283 / 8.0), + REAL_CONST(13883.34318835034 / 8.0), + REAL_CONST(13897.818196965914 / 8.0), + REAL_CONST(13912.296975606168 / 8.0), + REAL_CONST(13926.779522308825 / 8.0), + REAL_CONST(13941.26583511416 / 8.0), + REAL_CONST(13955.755912064991 / 8.0), + REAL_CONST(13970.249751206682 / 8.0), + REAL_CONST(13984.747350587126 / 8.0), + REAL_CONST(13999.248708256751 / 8.0), + REAL_CONST(14013.753822268511 / 8.0), + REAL_CONST(14028.262690677873 / 8.0), + REAL_CONST(14042.775311542828 / 8.0), + REAL_CONST(14057.291682923867 / 8.0), + REAL_CONST(14071.811802883994 / 8.0), + REAL_CONST(14086.335669488704 / 8.0), + REAL_CONST(14100.863280805994 / 8.0), + REAL_CONST(14115.394634906341 / 8.0), + REAL_CONST(14129.92972986271 / 8.0), + REAL_CONST(14144.468563750548 / 8.0), + REAL_CONST(14159.01113464777 / 8.0), + REAL_CONST(14173.55744063476 / 8.0), + REAL_CONST(14188.107479794369 / 8.0), + REAL_CONST(14202.661250211901 / 8.0), + REAL_CONST(14217.218749975118 / 8.0), + REAL_CONST(14231.779977174227 / 8.0), + REAL_CONST(14246.344929901879 / 8.0), + REAL_CONST(14260.913606253163 / 8.0), + REAL_CONST(14275.486004325601 / 8.0), + REAL_CONST(14290.062122219146 / 8.0), + REAL_CONST(14304.641958036171 / 8.0), + REAL_CONST(14319.225509881464 / 8.0), + REAL_CONST(14333.812775862236 / 8.0), + REAL_CONST(14348.403754088098 / 8.0), + REAL_CONST(14362.998442671067 / 8.0), + REAL_CONST(14377.59683972556 / 8.0), + REAL_CONST(14392.198943368388 / 8.0), + REAL_CONST(14406.804751718748 / 8.0), + REAL_CONST(14421.414262898223 / 8.0), + REAL_CONST(14436.027475030774 / 8.0), + REAL_CONST(14450.64438624274 / 8.0), + REAL_CONST(14465.264994662828 / 8.0), + REAL_CONST(14479.889298422106 / 8.0), + REAL_CONST(14494.517295654005 / 8.0), + REAL_CONST(14509.148984494313 / 8.0), + REAL_CONST(14523.784363081166 / 8.0), + REAL_CONST(14538.423429555049 / 8.0), + REAL_CONST(14553.066182058781 / 8.0), + REAL_CONST(14567.712618737527 / 8.0), + REAL_CONST(14582.362737738777 / 8.0), + REAL_CONST(14597.016537212348 / 8.0), + REAL_CONST(14611.674015310382 / 8.0), + REAL_CONST(14626.33517018734 / 8.0), + REAL_CONST(14640.999999999993 / 8.0), + REAL_CONST(14655.668502907418 / 8.0), + REAL_CONST(14670.340677071003 / 8.0), + REAL_CONST(14685.016520654426 / 8.0), + REAL_CONST(14699.696031823671 / 8.0), + REAL_CONST(14714.379208746999 / 8.0), + REAL_CONST(14729.066049594967 / 8.0), + REAL_CONST(14743.756552540408 / 8.0), + REAL_CONST(14758.45071575843 / 8.0), + REAL_CONST(14773.148537426418 / 8.0), + REAL_CONST(14787.850015724018 / 8.0), + REAL_CONST(14802.555148833142 / 8.0), + REAL_CONST(14817.263934937961 / 8.0), + REAL_CONST(14831.976372224897 / 8.0), + REAL_CONST(14846.692458882624 / 8.0), + REAL_CONST(14861.41219310206 / 8.0), + REAL_CONST(14876.135573076363 / 8.0), + REAL_CONST(14890.862597000923 / 8.0), + REAL_CONST(14905.593263073371 / 8.0), + REAL_CONST(14920.327569493558 / 8.0), + REAL_CONST(14935.065514463557 / 8.0), + REAL_CONST(14949.807096187662 / 8.0), + REAL_CONST(14964.552312872382 / 8.0), + REAL_CONST(14979.301162726431 / 8.0), + REAL_CONST(14994.053643960735 / 8.0), + REAL_CONST(15008.809754788414 / 8.0), + REAL_CONST(15023.569493424788 / 8.0), + REAL_CONST(15038.332858087369 / 8.0), + REAL_CONST(15053.099846995858 / 8.0), + REAL_CONST(15067.870458372134 / 8.0), + REAL_CONST(15082.644690440264 / 8.0), + REAL_CONST(15097.422541426484 / 8.0), + REAL_CONST(15112.204009559202 / 8.0), + REAL_CONST(15126.989093068994 / 8.0), + REAL_CONST(15141.777790188597 / 8.0), + REAL_CONST(15156.570099152905 / 8.0), + REAL_CONST(15171.366018198967 / 8.0), + REAL_CONST(15186.165545565986 / 8.0), + REAL_CONST(15200.968679495301 / 8.0), + REAL_CONST(15215.775418230402 / 8.0), + REAL_CONST(15230.585760016909 / 8.0), + REAL_CONST(15245.399703102579 / 8.0), + REAL_CONST(15260.217245737298 / 8.0), + REAL_CONST(15275.038386173073 / 8.0), + REAL_CONST(15289.863122664035 / 8.0), + REAL_CONST(15304.691453466432 / 8.0), + REAL_CONST(15319.523376838621 / 8.0), + REAL_CONST(15334.358891041069 / 8.0), + REAL_CONST(15349.197994336346 / 8.0), + REAL_CONST(15364.040684989128 / 8.0), + REAL_CONST(15378.886961266177 / 8.0), + REAL_CONST(15393.736821436356 / 8.0), + REAL_CONST(15408.590263770609 / 8.0), + REAL_CONST(15423.447286541972 / 8.0), + REAL_CONST(15438.307888025554 / 8.0), + REAL_CONST(15453.172066498542 / 8.0), + REAL_CONST(15468.039820240196 / 8.0), + REAL_CONST(15482.91114753184 / 8.0), + REAL_CONST(15497.786046656869 / 8.0), + REAL_CONST(15512.664515900733 / 8.0), + REAL_CONST(15527.546553550939 / 8.0), + REAL_CONST(15542.432157897045 / 8.0), + REAL_CONST(15557.32132723066 / 8.0), + REAL_CONST(15572.214059845435 / 8.0), + REAL_CONST(15587.110354037064 / 8.0), + REAL_CONST(15602.010208103273 / 8.0), + REAL_CONST(15616.913620343823 / 8.0), + REAL_CONST(15631.820589060506 / 8.0), + REAL_CONST(15646.731112557136 / 8.0), + REAL_CONST(15661.645189139546 / 8.0), + REAL_CONST(15676.562817115593 / 8.0), + REAL_CONST(15691.483994795139 / 8.0), + REAL_CONST(15706.408720490062 / 8.0), + REAL_CONST(15721.336992514242 / 8.0), + REAL_CONST(15736.268809183561 / 8.0), + REAL_CONST(15751.204168815901 / 8.0), + REAL_CONST(15766.143069731135 / 8.0), + REAL_CONST(15781.085510251132 / 8.0), + REAL_CONST(15796.03148869974 / 8.0), + REAL_CONST(15810.981003402798 / 8.0), + REAL_CONST(15825.934052688119 / 8.0), + REAL_CONST(15840.890634885489 / 8.0), + REAL_CONST(15855.850748326673 / 8.0), + REAL_CONST(15870.814391345401 / 8.0), + REAL_CONST(15885.781562277361 / 8.0), + REAL_CONST(15900.752259460214 / 8.0), + REAL_CONST(15915.726481233565 / 8.0), + REAL_CONST(15930.704225938984 / 8.0), + REAL_CONST(15945.685491919978 / 8.0), + REAL_CONST(15960.670277522009 / 8.0), + REAL_CONST(15975.658581092481 / 8.0), + REAL_CONST(15990.65040098073 / 8.0), + REAL_CONST(16005.645735538035 / 8.0), + REAL_CONST(16020.644583117599 / 8.0), + REAL_CONST(16035.646942074556 / 8.0), + REAL_CONST(16050.652810765967 / 8.0), + REAL_CONST(16065.662187550806 / 8.0), + REAL_CONST(16080.675070789974 / 8.0), + REAL_CONST(16095.691458846273 / 8.0), + REAL_CONST(16110.711350084424 / 8.0), + REAL_CONST(16125.734742871053 / 8.0), + REAL_CONST(16140.761635574685 / 8.0), + REAL_CONST(16155.792026565747 / 8.0), + REAL_CONST(16170.825914216561 / 8.0), + REAL_CONST(16185.863296901338 / 8.0), + REAL_CONST(16200.904172996183 / 8.0), + REAL_CONST(16215.948540879079 / 8.0), + REAL_CONST(16230.996398929899 / 8.0), + REAL_CONST(16246.047745530386 / 8.0), + REAL_CONST(16261.102579064163 / 8.0), + REAL_CONST(16276.160897916721 / 8.0), + REAL_CONST(16291.22270047542 / 8.0), + REAL_CONST(16306.287985129484 / 8.0), + REAL_CONST(16321.356750269995 / 8.0), + REAL_CONST(16336.428994289896 / 8.0), + REAL_CONST(16351.504715583982 / 8.0), + REAL_CONST(16366.5839125489 / 8.0), + REAL_CONST(16381.666583583141 / 8.0), + REAL_CONST(16396.752727087041 / 8.0), + REAL_CONST(16411.842341462776 / 8.0), + REAL_CONST(16426.935425114363 / 8.0), + REAL_CONST(16442.031976447644 / 8.0), + REAL_CONST(16457.131993870298 / 8.0), + REAL_CONST(16472.235475791829 / 8.0), + REAL_CONST(16487.342420623561 / 8.0), + REAL_CONST(16502.452826778641 / 8.0), + REAL_CONST(16517.566692672033 / 8.0), + REAL_CONST(16532.684016720516 / 8.0), + REAL_CONST(16547.804797342676 / 8.0), + REAL_CONST(16562.929032958902 / 8.0), + REAL_CONST(16578.056721991394 / 8.0), + REAL_CONST(16593.18786286415 / 8.0), + REAL_CONST(16608.322454002962 / 8.0), + REAL_CONST(16623.460493835417 / 8.0), + REAL_CONST(16638.601980790896 / 8.0), + REAL_CONST(16653.746913300558 / 8.0), + REAL_CONST(16668.895289797354 / 8.0), + REAL_CONST(16684.047108716015 / 8.0), + REAL_CONST(16699.202368493046 / 8.0), + REAL_CONST(16714.361067566726 / 8.0), + REAL_CONST(16729.523204377107 / 8.0), + REAL_CONST(16744.688777366009 / 8.0), + REAL_CONST(16759.857784977012 / 8.0), + REAL_CONST(16775.030225655464 / 8.0), + REAL_CONST(16790.206097848466 / 8.0), + REAL_CONST(16805.385400004874 / 8.0), + REAL_CONST(16820.568130575302 / 8.0), + REAL_CONST(16835.754288012104 / 8.0), + REAL_CONST(16850.943870769381 / 8.0), + REAL_CONST(16866.136877302983 / 8.0), + REAL_CONST(16881.333306070494 / 8.0), + REAL_CONST(16896.53315553123 / 8.0), + REAL_CONST(16911.736424146249 / 8.0), + REAL_CONST(16926.943110378332 / 8.0), + REAL_CONST(16942.153212691992 / 8.0), + REAL_CONST(16957.366729553454 / 8.0), + REAL_CONST(16972.583659430682 / 8.0), + REAL_CONST(16987.804000793338 / 8.0), + REAL_CONST(17003.027752112816 / 8.0), + REAL_CONST(17018.254911862205 / 8.0), + REAL_CONST(17033.485478516312 / 8.0), + REAL_CONST(17048.719450551645 / 8.0), + REAL_CONST(17063.956826446421 / 8.0), + REAL_CONST(17079.197604680547 / 8.0), + REAL_CONST(17094.44178373563 / 8.0), + REAL_CONST(17109.689362094967 / 8.0), + REAL_CONST(17124.940338243552 / 8.0), + REAL_CONST(17140.194710668064 / 8.0), + REAL_CONST(17155.452477856852 / 8.0), + REAL_CONST(17170.713638299967 / 8.0), + REAL_CONST(17185.978190489128 / 8.0), + REAL_CONST(17201.246132917724 / 8.0), + REAL_CONST(17216.517464080825 / 8.0), + REAL_CONST(17231.792182475165 / 8.0), + REAL_CONST(17247.070286599141 / 8.0), + REAL_CONST(17262.351774952826 / 8.0), + REAL_CONST(17277.636646037936 / 8.0), + REAL_CONST(17292.924898357855 / 8.0), + REAL_CONST(17308.216530417623 / 8.0), + REAL_CONST(17323.511540723921 / 8.0), + REAL_CONST(17338.809927785089 / 8.0), + REAL_CONST(17354.111690111105 / 8.0), + REAL_CONST(17369.416826213594 / 8.0), + REAL_CONST(17384.725334605821 / 8.0), + REAL_CONST(17400.037213802683 / 8.0), + REAL_CONST(17415.352462320716 / 8.0), + REAL_CONST(17430.67107867809 / 8.0), + REAL_CONST(17445.993061394587 / 8.0), + REAL_CONST(17461.318408991636 / 8.0), + REAL_CONST(17476.647119992274 / 8.0), + REAL_CONST(17491.979192921168 / 8.0), + REAL_CONST(17507.314626304586 / 8.0), + REAL_CONST(17522.653418670423 / 8.0), + REAL_CONST(17537.995568548187 / 8.0), + REAL_CONST(17553.341074468986 / 8.0), + REAL_CONST(17568.689934965536 / 8.0), + REAL_CONST(17584.042148572156 / 8.0), + REAL_CONST(17599.397713824768 / 8.0), + REAL_CONST(17614.75662926089 / 8.0), + REAL_CONST(17630.118893419625 / 8.0), + REAL_CONST(17645.484504841683 / 8.0), + REAL_CONST(17660.853462069354 / 8.0), + REAL_CONST(17676.225763646511 / 8.0), + REAL_CONST(17691.601408118619 / 8.0), + REAL_CONST(17706.980394032718 / 8.0), + REAL_CONST(17722.362719937424 / 8.0), + REAL_CONST(17737.748384382936 / 8.0), + REAL_CONST(17753.137385921014 / 8.0), + REAL_CONST(17768.529723104999 / 8.0), + REAL_CONST(17783.92539448979 / 8.0), + REAL_CONST(17799.324398631856 / 8.0), + REAL_CONST(17814.726734089225 / 8.0), + REAL_CONST(17830.13239942148 / 8.0), + REAL_CONST(17845.541393189767 / 8.0), + REAL_CONST(17860.95371395678 / 8.0), + REAL_CONST(17876.369360286772 / 8.0), + REAL_CONST(17891.788330745527 / 8.0), + REAL_CONST(17907.210623900395 / 8.0), + REAL_CONST(17922.636238320254 / 8.0), + REAL_CONST(17938.065172575527 / 8.0), + REAL_CONST(17953.497425238176 / 8.0), + REAL_CONST(17968.932994881692 / 8.0), + REAL_CONST(17984.371880081104 / 8.0), + REAL_CONST(17999.814079412972 / 8.0), + REAL_CONST(18015.259591455371 / 8.0), + REAL_CONST(18030.708414787914 / 8.0), + REAL_CONST(18046.160547991731 / 8.0), + REAL_CONST(18061.615989649465 / 8.0), + REAL_CONST(18077.074738345284 / 8.0), + REAL_CONST(18092.536792664861 / 8.0), + REAL_CONST(18108.002151195393 / 8.0), + REAL_CONST(18123.470812525571 / 8.0), + REAL_CONST(18138.942775245599 / 8.0), + REAL_CONST(18154.418037947191 / 8.0), + REAL_CONST(18169.896599223546 / 8.0), + REAL_CONST(18185.37845766938 / 8.0), + REAL_CONST(18200.863611880886 / 8.0), + REAL_CONST(18216.352060455767 / 8.0), + REAL_CONST(18231.843801993204 / 8.0), + REAL_CONST(18247.338835093873 / 8.0), + REAL_CONST(18262.837158359936 / 8.0), + REAL_CONST(18278.338770395032 / 8.0), + REAL_CONST(18293.84366980429 / 8.0), + REAL_CONST(18309.351855194309 / 8.0), + REAL_CONST(18324.863325173166 / 8.0), + REAL_CONST(18340.378078350412 / 8.0), + REAL_CONST(18355.896113337069 / 8.0), + REAL_CONST(18371.417428745623 / 8.0), + REAL_CONST(18386.942023190033 / 8.0), + REAL_CONST(18402.469895285718 / 8.0), + REAL_CONST(18418.00104364955 / 8.0), + REAL_CONST(18433.53546689987 / 8.0), + REAL_CONST(18449.073163656474 / 8.0), + REAL_CONST(18464.614132540602 / 8.0), + REAL_CONST(18480.158372174956 / 8.0), + REAL_CONST(18495.705881183676 / 8.0), + REAL_CONST(18511.256658192357 / 8.0), + REAL_CONST(18526.810701828035 / 8.0), + REAL_CONST(18542.368010719183 / 8.0), + REAL_CONST(18557.928583495715 / 8.0), + REAL_CONST(18573.492418788985 / 8.0), + REAL_CONST(18589.059515231773 / 8.0), + REAL_CONST(18604.629871458303 / 8.0), + REAL_CONST(18620.203486104212 / 8.0), + REAL_CONST(18635.78035780658 / 8.0), + REAL_CONST(18651.360485203899 / 8.0), + REAL_CONST(18666.943866936086 / 8.0), + REAL_CONST(18682.53050164448 / 8.0), + REAL_CONST(18698.120387971841 / 8.0), + REAL_CONST(18713.713524562332 / 8.0), + REAL_CONST(18729.30991006154 / 8.0), + REAL_CONST(18744.909543116457 / 8.0), + REAL_CONST(18760.512422375479 / 8.0), + REAL_CONST(18776.118546488418 / 8.0), + REAL_CONST(18791.727914106479 / 8.0), + REAL_CONST(18807.340523882274 / 8.0), + REAL_CONST(18822.95637446981 / 8.0), + REAL_CONST(18838.575464524489 / 8.0), + REAL_CONST(18854.197792703111 / 8.0), + REAL_CONST(18869.823357663863 / 8.0), + REAL_CONST(18885.452158066328 / 8.0), + REAL_CONST(18901.08419257147 / 8.0), + REAL_CONST(18916.719459841639 / 8.0), + REAL_CONST(18932.357958540564 / 8.0), + REAL_CONST(18947.999687333362 / 8.0), + REAL_CONST(18963.644644886521 / 8.0), + REAL_CONST(18979.292829867907 / 8.0), + REAL_CONST(18994.944240946759 / 8.0), + REAL_CONST(19010.598876793687 / 8.0), + REAL_CONST(19026.256736080668 / 8.0), + REAL_CONST(19041.917817481048 / 8.0), + REAL_CONST(19057.582119669532 / 8.0), + REAL_CONST(19073.2496413222 / 8.0), + REAL_CONST(19088.920381116473 / 8.0), + REAL_CONST(19104.594337731145 / 8.0), + REAL_CONST(19120.271509846356 / 8.0), + REAL_CONST(19135.951896143604 / 8.0), + REAL_CONST(19151.635495305738 / 8.0), + REAL_CONST(19167.322306016948 / 8.0), + REAL_CONST(19183.012326962784 / 8.0), + REAL_CONST(19198.705556830122 / 8.0), + REAL_CONST(19214.401994307198 / 8.0), + REAL_CONST(19230.101638083579 / 8.0), + REAL_CONST(19245.804486850167 / 8.0), + REAL_CONST(19261.510539299208 / 8.0), + REAL_CONST(19277.219794124274 / 8.0), + REAL_CONST(19292.932250020265 / 8.0), + REAL_CONST(19308.647905683421 / 8.0), + REAL_CONST(19324.366759811302 / 8.0), + REAL_CONST(19340.088811102793 / 8.0), + REAL_CONST(19355.8140582581 / 8.0), + REAL_CONST(19371.542499978754 / 8.0), + REAL_CONST(19387.2741349676 / 8.0), + REAL_CONST(19403.008961928797 / 8.0), + REAL_CONST(19418.746979567823 / 8.0), + REAL_CONST(19434.488186591469 / 8.0), + REAL_CONST(19450.232581707827 / 8.0), + REAL_CONST(19465.980163626304 / 8.0), + REAL_CONST(19481.730931057613 / 8.0), + REAL_CONST(19497.484882713761 / 8.0), + REAL_CONST(19513.242017308068 / 8.0), + REAL_CONST(19529.002333555141 / 8.0), + REAL_CONST(19544.765830170898 / 8.0), + REAL_CONST(19560.532505872539 / 8.0), + REAL_CONST(19576.302359378566 / 8.0), + REAL_CONST(19592.075389408761 / 8.0), + REAL_CONST(19607.851594684209 / 8.0), + REAL_CONST(19623.630973927269 / 8.0), + REAL_CONST(19639.41352586159 / 8.0), + REAL_CONST(19655.199249212103 / 8.0), + REAL_CONST(19670.988142705017 / 8.0), + REAL_CONST(19686.780205067826 / 8.0), + REAL_CONST(19702.575435029288 / 8.0), + REAL_CONST(19718.373831319448 / 8.0), + REAL_CONST(19734.175392669615 / 8.0), + REAL_CONST(19749.980117812371 / 8.0), + REAL_CONST(19765.788005481569 / 8.0), + REAL_CONST(19781.599054412323 / 8.0), + REAL_CONST(19797.413263341008 / 8.0), + REAL_CONST(19813.230631005274 / 8.0), + REAL_CONST(19829.051156144014 / 8.0), + REAL_CONST(19844.874837497395 / 8.0), + REAL_CONST(19860.701673806827 / 8.0), + REAL_CONST(19876.531663814985 / 8.0), + REAL_CONST(19892.364806265789 / 8.0), + REAL_CONST(19908.201099904403 / 8.0), + REAL_CONST(19924.040543477258 / 8.0), + REAL_CONST(19939.883135732012 / 8.0), + REAL_CONST(19955.728875417579 / 8.0), + REAL_CONST(19971.577761284105 / 8.0), + REAL_CONST(19987.429792082985 / 8.0), + REAL_CONST(20003.284966566847 / 8.0), + REAL_CONST(20019.14328348956 / 8.0), + REAL_CONST(20035.004741606219 / 8.0), + REAL_CONST(20050.869339673161 / 8.0), + REAL_CONST(20066.737076447946 / 8.0), + REAL_CONST(20082.607950689362 / 8.0), + REAL_CONST(20098.481961157428 / 8.0), + REAL_CONST(20114.359106613385 / 8.0), + REAL_CONST(20130.239385819699 / 8.0), + REAL_CONST(20146.122797540058 / 8.0), + REAL_CONST(20162.009340539353 / 8.0), + REAL_CONST(20177.899013583716 / 8.0), + REAL_CONST(20193.791815440476 / 8.0), + REAL_CONST(20209.687744878182 / 8.0), + REAL_CONST(20225.586800666591 / 8.0), + REAL_CONST(20241.488981576669 / 8.0), + REAL_CONST(20257.394286380597 / 8.0), + REAL_CONST(20273.302713851754 / 8.0), + REAL_CONST(20289.214262764715 / 8.0), + REAL_CONST(20305.128931895277 / 8.0), + REAL_CONST(20321.046720020415 / 8.0), + REAL_CONST(20336.967625918318 / 8.0), + REAL_CONST(20352.891648368361 / 8.0), + REAL_CONST(20368.818786151114 / 8.0), + REAL_CONST(20384.749038048347 / 8.0), + REAL_CONST(20400.682402843009 / 8.0), + REAL_CONST(20416.618879319249 / 8.0), + REAL_CONST(20432.558466262391 / 8.0), + REAL_CONST(20448.501162458953 / 8.0), + REAL_CONST(20464.446966696629 / 8.0), + REAL_CONST(20480.395877764302 / 8.0), + REAL_CONST(20496.347894452025 / 8.0), + REAL_CONST(20512.303015551031 / 8.0), + REAL_CONST(20528.261239853735 / 8.0), + REAL_CONST(20544.22256615372 / 8.0), + REAL_CONST(20560.186993245738 / 8.0), + REAL_CONST(20576.15451992572 / 8.0), + REAL_CONST(20592.125144990758 / 8.0), + REAL_CONST(20608.098867239107 / 8.0), + REAL_CONST(20624.075685470198 / 8.0), + REAL_CONST(20640.055598484618 / 8.0), + REAL_CONST(20656.038605084115 / 8.0), + REAL_CONST(20672.024704071595 / 8.0), + REAL_CONST(20688.013894251126 / 8.0), + REAL_CONST(20704.006174427926 / 8.0), + REAL_CONST(20720.001543408373 / 8.0), + REAL_CONST(20735.999999999989 / 8.0), + REAL_CONST(20752.001543011454 / 8.0), + REAL_CONST(20768.006171252597 / 8.0), + REAL_CONST(20784.013883534382 / 8.0), + REAL_CONST(20800.024678668931 / 8.0), + REAL_CONST(20816.038555469506 / 8.0), + REAL_CONST(20832.055512750507 / 8.0), + REAL_CONST(20848.075549327474 / 8.0), + REAL_CONST(20864.098664017085 / 8.0), + REAL_CONST(20880.124855637161 / 8.0), + REAL_CONST(20896.154123006647 / 8.0), + REAL_CONST(20912.186464945626 / 8.0), + REAL_CONST(20928.221880275312 / 8.0), + REAL_CONST(20944.260367818049 / 8.0), + REAL_CONST(20960.301926397311 / 8.0), + REAL_CONST(20976.346554837684 / 8.0), + REAL_CONST(20992.394251964895 / 8.0), + REAL_CONST(21008.445016605787 / 8.0), + REAL_CONST(21024.498847588318 / 8.0), + REAL_CONST(21040.555743741574 / 8.0), + REAL_CONST(21056.615703895754 / 8.0), + REAL_CONST(21072.678726882168 / 8.0), + REAL_CONST(21088.744811533252 / 8.0), + REAL_CONST(21104.813956682538 / 8.0), + REAL_CONST(21120.886161164683 / 8.0), + REAL_CONST(21136.961423815443 / 8.0), + REAL_CONST(21153.039743471683 / 8.0), + REAL_CONST(21169.121118971379 / 8.0), + REAL_CONST(21185.205549153605 / 8.0), + REAL_CONST(21201.293032858535 / 8.0), + REAL_CONST(21217.383568927453 / 8.0), + REAL_CONST(21233.477156202731 / 8.0), + REAL_CONST(21249.573793527841 / 8.0), + REAL_CONST(21265.673479747358 / 8.0), + REAL_CONST(21281.776213706937 / 8.0), + REAL_CONST(21297.881994253334 / 8.0), + REAL_CONST(21313.990820234398 / 8.0), + REAL_CONST(21330.102690499054 / 8.0), + REAL_CONST(21346.21760389733 / 8.0), + REAL_CONST(21362.335559280327 / 8.0), + REAL_CONST(21378.456555500241 / 8.0), + REAL_CONST(21394.580591410333 / 8.0), + REAL_CONST(21410.707665864964 / 8.0), + REAL_CONST(21426.83777771956 / 8.0), + REAL_CONST(21442.970925830628 / 8.0), + REAL_CONST(21459.107109055756 / 8.0), + REAL_CONST(21475.246326253604 / 8.0), + REAL_CONST(21491.388576283895 / 8.0), + REAL_CONST(21507.533858007431 / 8.0), + REAL_CONST(21523.682170286087 / 8.0), + REAL_CONST(21539.833511982797 / 8.0), + REAL_CONST(21555.987881961566 / 8.0), + REAL_CONST(21572.145279087465 / 8.0), + REAL_CONST(21588.305702226615 / 8.0), + REAL_CONST(21604.469150246216 / 8.0), + REAL_CONST(21620.635622014521 / 8.0), + REAL_CONST(21636.805116400832 / 8.0), + REAL_CONST(21652.977632275521 / 8.0), + REAL_CONST(21669.153168510009 / 8.0), + REAL_CONST(21685.331723976764 / 8.0), + REAL_CONST(21701.513297549318 / 8.0), + REAL_CONST(21717.697888102244 / 8.0), + REAL_CONST(21733.885494511167 / 8.0), + REAL_CONST(21750.076115652759 / 8.0), + REAL_CONST(21766.269750404736 / 8.0), + REAL_CONST(21782.466397645861 / 8.0), + REAL_CONST(21798.666056255934 / 8.0), + REAL_CONST(21814.868725115801 / 8.0), + REAL_CONST(21831.074403107345 / 8.0), + REAL_CONST(21847.283089113484 / 8.0), + REAL_CONST(21863.494782018177 / 8.0), + REAL_CONST(21879.709480706417 / 8.0), + REAL_CONST(21895.927184064229 / 8.0), + REAL_CONST(21912.147890978667 / 8.0), + REAL_CONST(21928.371600337818 / 8.0), + REAL_CONST(21944.598311030797 / 8.0), + REAL_CONST(21960.828021947746 / 8.0), + REAL_CONST(21977.060731979829 / 8.0), + REAL_CONST(21993.296440019243 / 8.0), + REAL_CONST(22009.535144959198 / 8.0), + REAL_CONST(22025.77684569393 / 8.0), + REAL_CONST(22042.021541118691 / 8.0), + REAL_CONST(22058.269230129757 / 8.0), + REAL_CONST(22074.519911624411 / 8.0), + REAL_CONST(22090.773584500959 / 8.0), + REAL_CONST(22107.030247658717 / 8.0), + REAL_CONST(22123.289899998013 / 8.0), + REAL_CONST(22139.552540420187 / 8.0), + REAL_CONST(22155.818167827587 / 8.0), + REAL_CONST(22172.086781123569 / 8.0), + REAL_CONST(22188.358379212495 / 8.0), + REAL_CONST(22204.632960999726 / 8.0), + REAL_CONST(22220.910525391639 / 8.0), + REAL_CONST(22237.191071295601 / 8.0), + REAL_CONST(22253.474597619981 / 8.0), + REAL_CONST(22269.761103274148 / 8.0), + REAL_CONST(22286.050587168469 / 8.0), + REAL_CONST(22302.343048214312 / 8.0), + REAL_CONST(22318.638485324027 / 8.0), + REAL_CONST(22334.936897410968 / 8.0), + REAL_CONST(22351.23828338947 / 8.0), + REAL_CONST(22367.542642174871 / 8.0), + REAL_CONST(22383.849972683485 / 8.0), + REAL_CONST(22400.160273832618 / 8.0), + REAL_CONST(22416.473544540564 / 8.0), + REAL_CONST(22432.789783726603 / 8.0), + REAL_CONST(22449.108990310986 / 8.0), + REAL_CONST(22465.431163214958 / 8.0), + REAL_CONST(22481.75630136074 / 8.0), + REAL_CONST(22498.084403671528 / 8.0), + REAL_CONST(22514.415469071497 / 8.0), + REAL_CONST(22530.749496485802 / 8.0), + REAL_CONST(22547.086484840562 / 8.0), + REAL_CONST(22563.426433062879 / 8.0), + REAL_CONST(22579.769340080824 / 8.0), + REAL_CONST(22596.115204823436 / 8.0), + REAL_CONST(22612.464026220721 / 8.0), + REAL_CONST(22628.815803203655 / 8.0), + REAL_CONST(22645.170534704179 / 8.0), + REAL_CONST(22661.5282196552 / 8.0), + REAL_CONST(22677.888856990587 / 8.0), + REAL_CONST(22694.252445645168 / 8.0), + REAL_CONST(22710.618984554734 / 8.0), + REAL_CONST(22726.988472656034 / 8.0), + REAL_CONST(22743.360908886778 / 8.0), + REAL_CONST(22759.736292185622 / 8.0), + REAL_CONST(22776.114621492186 / 8.0), + REAL_CONST(22792.495895747044 / 8.0), + REAL_CONST(22808.880113891719 / 8.0), + REAL_CONST(22825.267274868678 / 8.0), + REAL_CONST(22841.657377621348 / 8.0), + REAL_CONST(22858.050421094096 / 8.0), + REAL_CONST(22874.446404232243 / 8.0), + REAL_CONST(22890.845325982053 / 8.0), + REAL_CONST(22907.247185290722 / 8.0), + REAL_CONST(22923.651981106406 / 8.0), + REAL_CONST(22940.059712378195 / 8.0), + REAL_CONST(22956.470378056114 / 8.0), + REAL_CONST(22972.883977091129 / 8.0), + REAL_CONST(22989.300508435153 / 8.0), + REAL_CONST(23005.719971041017 / 8.0), + REAL_CONST(23022.142363862498 / 8.0), + REAL_CONST(23038.567685854305 / 8.0), + REAL_CONST(23054.995935972078 / 8.0), + REAL_CONST(23071.427113172387 / 8.0), + REAL_CONST(23087.86121641273 / 8.0), + REAL_CONST(23104.298244651531 / 8.0), + REAL_CONST(23120.738196848146 / 8.0), + REAL_CONST(23137.181071962848 / 8.0), + REAL_CONST(23153.626868956846 / 8.0), + REAL_CONST(23170.075586792263 / 8.0), + REAL_CONST(23186.527224432142 / 8.0), + REAL_CONST(23202.981780840448 / 8.0), + REAL_CONST(23219.439254982066 / 8.0), + REAL_CONST(23235.899645822796 / 8.0), + REAL_CONST(23252.362952329357 / 8.0), + REAL_CONST(23268.829173469378 / 8.0), + REAL_CONST(23285.298308211408 / 8.0), + REAL_CONST(23301.770355524899 / 8.0), + REAL_CONST(23318.245314380223 / 8.0), + REAL_CONST(23334.723183748658 / 8.0), + REAL_CONST(23351.203962602387 / 8.0), + REAL_CONST(23367.687649914504 / 8.0), + REAL_CONST(23384.174244659007 / 8.0), + REAL_CONST(23400.663745810798 / 8.0), + REAL_CONST(23417.15615234568 / 8.0), + REAL_CONST(23433.651463240367 / 8.0), + REAL_CONST(23450.149677472462 / 8.0), + REAL_CONST(23466.650794020472 / 8.0), + REAL_CONST(23483.154811863806 / 8.0), + REAL_CONST(23499.661729982763 / 8.0), + REAL_CONST(23516.171547358543 / 8.0), + REAL_CONST(23532.684262973235 / 8.0), + REAL_CONST(23549.199875809823 / 8.0), + REAL_CONST(23565.718384852185 / 8.0), + REAL_CONST(23582.239789085092 / 8.0), + REAL_CONST(23598.764087494197 / 8.0), + REAL_CONST(23615.291279066041 / 8.0), + REAL_CONST(23631.821362788058 / 8.0), + REAL_CONST(23648.354337648565 / 8.0), + REAL_CONST(23664.890202636761 / 8.0), + REAL_CONST(23681.428956742733 / 8.0), + REAL_CONST(23697.970598957443 / 8.0), + REAL_CONST(23714.515128272738 / 8.0), + REAL_CONST(23731.062543681343 / 8.0), + REAL_CONST(23747.612844176863 / 8.0), + REAL_CONST(23764.166028753778 / 8.0), + REAL_CONST(23780.72209640744 / 8.0), + REAL_CONST(23797.281046134085 / 8.0), + REAL_CONST(23813.842876930816 / 8.0), + REAL_CONST(23830.407587795606 / 8.0), + REAL_CONST(23846.975177727301 / 8.0), + REAL_CONST(23863.545645725622 / 8.0), + REAL_CONST(23880.11899079115 / 8.0), + REAL_CONST(23896.695211925336 / 8.0), + REAL_CONST(23913.274308130498 / 8.0), + REAL_CONST(23929.856278409821 / 8.0), + REAL_CONST(23946.441121767348 / 8.0), + REAL_CONST(23963.028837207989 / 8.0), + REAL_CONST(23979.619423737513 / 8.0), + REAL_CONST(23996.212880362549 / 8.0), + REAL_CONST(24012.809206090584 / 8.0), + REAL_CONST(24029.408399929966 / 8.0), + REAL_CONST(24046.010460889898 / 8.0), + REAL_CONST(24062.615387980433 / 8.0), + REAL_CONST(24079.223180212492 / 8.0), + REAL_CONST(24095.833836597827 / 8.0), + REAL_CONST(24112.447356149063 / 8.0), + REAL_CONST(24129.063737879667 / 8.0), + REAL_CONST(24145.682980803951 / 8.0), + REAL_CONST(24162.305083937081 / 8.0), + REAL_CONST(24178.930046295067 / 8.0), + REAL_CONST(24195.557866894767 / 8.0), + REAL_CONST(24212.188544753884 / 8.0), + REAL_CONST(24228.822078890964 / 8.0), + REAL_CONST(24245.458468325389 / 8.0), + REAL_CONST(24262.097712077397 / 8.0), + REAL_CONST(24278.739809168052 / 8.0), + REAL_CONST(24295.384758619261 / 8.0), + REAL_CONST(24312.032559453768 / 8.0), + REAL_CONST(24328.683210695162 / 8.0), + REAL_CONST(24345.336711367858 / 8.0), + REAL_CONST(24361.993060497109 / 8.0), + REAL_CONST(24378.652257108995 / 8.0), + REAL_CONST(24395.314300230442 / 8.0), + REAL_CONST(24411.979188889192 / 8.0), + REAL_CONST(24428.646922113825 / 8.0), + REAL_CONST(24445.317498933746 / 8.0), + REAL_CONST(24461.990918379193 / 8.0), + REAL_CONST(24478.667179481225 / 8.0), + REAL_CONST(24495.346281271726 / 8.0), + REAL_CONST(24512.028222783407 / 8.0), + REAL_CONST(24528.713003049801 / 8.0), + REAL_CONST(24545.400621105266 / 8.0), + REAL_CONST(24562.091075984976 / 8.0), + REAL_CONST(24578.784366724925 / 8.0), + REAL_CONST(24595.480492361927 / 8.0), + REAL_CONST(24612.179451933614 / 8.0), + REAL_CONST(24628.881244478438 / 8.0), + REAL_CONST(24645.585869035654 / 8.0), + REAL_CONST(24662.293324645343 / 8.0), + REAL_CONST(24679.003610348394 / 8.0), + REAL_CONST(24695.716725186514 / 8.0), + REAL_CONST(24712.432668202211 / 8.0), + REAL_CONST(24729.151438438807 / 8.0), + REAL_CONST(24745.873034940436 / 8.0), + REAL_CONST(24762.597456752032 / 8.0), + REAL_CONST(24779.324702919344 / 8.0), + REAL_CONST(24796.054772488926 / 8.0), + REAL_CONST(24812.787664508123 / 8.0), + REAL_CONST(24829.5233780251 / 8.0), + REAL_CONST(24846.261912088819 / 8.0), + REAL_CONST(24863.003265749034 / 8.0), + REAL_CONST(24879.747438056307 / 8.0), + REAL_CONST(24896.494428062004 / 8.0), + REAL_CONST(24913.244234818278 / 8.0), + REAL_CONST(24929.996857378079 / 8.0), + REAL_CONST(24946.752294795166 / 8.0), + REAL_CONST(24963.510546124078 / 8.0), + REAL_CONST(24980.271610420157 / 8.0), + REAL_CONST(24997.035486739525 / 8.0), + REAL_CONST(25013.802174139113 / 8.0), + REAL_CONST(25030.571671676629 / 8.0), + REAL_CONST(25047.343978410572 / 8.0), + REAL_CONST(25064.119093400237 / 8.0), + REAL_CONST(25080.897015705697 / 8.0), + REAL_CONST(25097.677744387816 / 8.0), + REAL_CONST(25114.461278508239 / 8.0), + REAL_CONST(25131.2476171294 / 8.0), + REAL_CONST(25148.036759314517 / 8.0), + REAL_CONST(25164.828704127583 / 8.0), + REAL_CONST(25181.623450633375 / 8.0), + REAL_CONST(25198.42099789745 / 8.0), + REAL_CONST(25215.221344986145 / 8.0), + REAL_CONST(25232.024490966574 / 8.0), + REAL_CONST(25248.830434906627 / 8.0), + REAL_CONST(25265.639175874974 / 8.0), + REAL_CONST(25282.450712941049 / 8.0), + REAL_CONST(25299.265045175071 / 8.0), + REAL_CONST(25316.082171648024 / 8.0), + REAL_CONST(25332.902091431668 / 8.0), + REAL_CONST(25349.724803598532 / 8.0), + REAL_CONST(25366.550307221914 / 8.0), + REAL_CONST(25383.378601375884 / 8.0), + REAL_CONST(25400.209685135269 / 8.0), + REAL_CONST(25417.043557575678 / 8.0), + REAL_CONST(25433.880217773472 / 8.0), + REAL_CONST(25450.719664805783 / 8.0), + REAL_CONST(25467.561897750507 / 8.0), + REAL_CONST(25484.406915686297 / 8.0), + REAL_CONST(25501.254717692573 / 8.0), + REAL_CONST(25518.105302849512 / 8.0), + REAL_CONST(25534.958670238051 / 8.0), + REAL_CONST(25551.814818939893 / 8.0), + REAL_CONST(25568.67374803748 / 8.0), + REAL_CONST(25585.535456614027 / 8.0), + REAL_CONST(25602.399943753502 / 8.0), + REAL_CONST(25619.267208540619 / 8.0), + REAL_CONST(25636.137250060852 / 8.0), + REAL_CONST(25653.010067400432 / 8.0), + REAL_CONST(25669.885659646327 / 8.0), + REAL_CONST(25686.76402588627 / 8.0), + REAL_CONST(25703.645165208734 / 8.0), + REAL_CONST(25720.529076702944 / 8.0), + REAL_CONST(25737.415759458876 / 8.0), + REAL_CONST(25754.305212567244 / 8.0), + REAL_CONST(25771.197435119517 / 8.0), + REAL_CONST(25788.092426207899 / 8.0), + REAL_CONST(25804.990184925344 / 8.0), + REAL_CONST(25821.890710365547 / 8.0), + REAL_CONST(25838.794001622944 / 8.0), + REAL_CONST(25855.700057792714 / 8.0), + REAL_CONST(25872.608877970775 / 8.0), + REAL_CONST(25889.520461253778 / 8.0), + REAL_CONST(25906.434806739118 / 8.0), + REAL_CONST(25923.351913524923 / 8.0), + REAL_CONST(25940.271780710063 / 8.0), + REAL_CONST(25957.194407394138 / 8.0), + REAL_CONST(25974.11979267748 / 8.0), + REAL_CONST(25991.047935661154 / 8.0), + REAL_CONST(26007.978835446964 / 8.0), + REAL_CONST(26024.912491137442 / 8.0), + REAL_CONST(26041.848901835841 / 8.0), + REAL_CONST(26058.788066646157 / 8.0), + REAL_CONST(26075.729984673108 / 8.0), + REAL_CONST(26092.674655022136 / 8.0), + REAL_CONST(26109.622076799409 / 8.0), + REAL_CONST(26126.572249111829 / 8.0), + REAL_CONST(26143.525171067016 / 8.0), + REAL_CONST(26160.480841773315 / 8.0), + REAL_CONST(26177.43926033979 / 8.0), + REAL_CONST(26194.400425876229 / 8.0), + REAL_CONST(26211.364337493149 / 8.0), + REAL_CONST(26228.330994301767 / 8.0), + REAL_CONST(26245.30039541404 / 8.0), + REAL_CONST(26262.272539942627 / 8.0), + REAL_CONST(26279.247427000919 / 8.0), + REAL_CONST(26296.225055703002 / 8.0), + REAL_CONST(26313.205425163702 / 8.0), + REAL_CONST(26330.188534498539 / 8.0), + REAL_CONST(26347.174382823756 / 8.0), + REAL_CONST(26364.162969256304 / 8.0), + REAL_CONST(26381.154292913852 / 8.0), + REAL_CONST(26398.148352914774 / 8.0), + REAL_CONST(26415.145148378149 / 8.0), + REAL_CONST(26432.144678423778 / 8.0), + REAL_CONST(26449.146942172156 / 8.0), + REAL_CONST(26466.151938744493 / 8.0), + REAL_CONST(26483.159667262702 / 8.0), + REAL_CONST(26500.170126849403 / 8.0), + REAL_CONST(26517.183316627921 / 8.0), + REAL_CONST(26534.199235722277 / 8.0), + REAL_CONST(26551.217883257199 / 8.0), + REAL_CONST(26568.239258358124 / 8.0), + REAL_CONST(26585.263360151173 / 8.0), + REAL_CONST(26602.290187763181 / 8.0), + REAL_CONST(26619.319740321676 / 8.0), + REAL_CONST(26636.352016954883 / 8.0), + REAL_CONST(26653.387016791727 / 8.0), + REAL_CONST(26670.424738961825 / 8.0), + REAL_CONST(26687.465182595493 / 8.0), + REAL_CONST(26704.508346823739 / 8.0), + REAL_CONST(26721.554230778267 / 8.0), + REAL_CONST(26738.602833591467 / 8.0), + REAL_CONST(26755.65415439643 / 8.0), + REAL_CONST(26772.708192326929 / 8.0), + REAL_CONST(26789.764946517433 / 8.0), + REAL_CONST(26806.824416103096 / 8.0), + REAL_CONST(26823.886600219761 / 8.0), + REAL_CONST(26840.95149800396 / 8.0), + REAL_CONST(26858.019108592915 / 8.0), + REAL_CONST(26875.089431124517 / 8.0), + REAL_CONST(26892.162464737365 / 8.0), + REAL_CONST(26909.238208570721 / 8.0), + REAL_CONST(26926.316661764544 / 8.0), + REAL_CONST(26943.397823459472 / 8.0), + REAL_CONST(26960.481692796813 / 8.0), + REAL_CONST(26977.568268918571 / 8.0), + REAL_CONST(26994.657550967422 / 8.0), + REAL_CONST(27011.749538086722 / 8.0), + REAL_CONST(27028.844229420498 / 8.0), + REAL_CONST(27045.941624113464 / 8.0), + REAL_CONST(27063.041721311005 / 8.0), + REAL_CONST(27080.144520159181 / 8.0), + REAL_CONST(27097.250019804727 / 8.0), + REAL_CONST(27114.35821939505 / 8.0), + REAL_CONST(27131.469118078236 / 8.0), + REAL_CONST(27148.582715003027 / 8.0), + REAL_CONST(27165.699009318858 / 8.0), + REAL_CONST(27182.818000175819 / 8.0), + REAL_CONST(27199.939686724665 / 8.0), + REAL_CONST(27217.064068116837 / 8.0), + REAL_CONST(27234.191143504428 / 8.0), + REAL_CONST(27251.320912040203 / 8.0), + REAL_CONST(27268.453372877593 / 8.0), + REAL_CONST(27285.588525170693 / 8.0), + REAL_CONST(27302.726368074269 / 8.0), + REAL_CONST(27319.866900743735 / 8.0), + REAL_CONST(27337.010122335181 / 8.0), + REAL_CONST(27354.156032005358 / 8.0), + REAL_CONST(27371.304628911668 / 8.0), + REAL_CONST(27388.455912212183 / 8.0), + REAL_CONST(27405.609881065626 / 8.0), + REAL_CONST(27422.766534631384 / 8.0), + REAL_CONST(27439.925872069507 / 8.0), + REAL_CONST(27457.087892540683 / 8.0), + REAL_CONST(27474.252595206275 / 8.0), + REAL_CONST(27491.419979228293 / 8.0), + REAL_CONST(27508.5900437694 / 8.0), + REAL_CONST(27525.762787992917 / 8.0), + REAL_CONST(27542.93821106281 / 8.0), + REAL_CONST(27560.116312143706 / 8.0), + REAL_CONST(27577.297090400876 / 8.0), + REAL_CONST(27594.480545000242 / 8.0), + REAL_CONST(27611.666675108383 / 8.0), + REAL_CONST(27628.855479892518 / 8.0), + REAL_CONST(27646.046958520514 / 8.0), + REAL_CONST(27663.241110160889 / 8.0), + REAL_CONST(27680.437933982801 / 8.0), + REAL_CONST(27697.637429156068 / 8.0), + REAL_CONST(27714.839594851132 / 8.0), + REAL_CONST(27732.04443023909 / 8.0), + REAL_CONST(27749.251934491687 / 8.0), + REAL_CONST(27766.462106781299 / 8.0), + REAL_CONST(27783.674946280949 / 8.0), + REAL_CONST(27800.890452164302 / 8.0), + REAL_CONST(27818.108623605654 / 8.0), + REAL_CONST(27835.329459779954 / 8.0), + REAL_CONST(27852.55295986278 / 8.0), + REAL_CONST(27869.779123030345 / 8.0), + REAL_CONST(27887.007948459504 / 8.0), + REAL_CONST(27904.239435327745 / 8.0), + REAL_CONST(27921.473582813196 / 8.0), + REAL_CONST(27938.710390094613 / 8.0), + REAL_CONST(27955.949856351392 / 8.0), + REAL_CONST(27973.19198076355 / 8.0), + REAL_CONST(27990.436762511745 / 8.0), + REAL_CONST(28007.684200777272 / 8.0), + REAL_CONST(28024.934294742041 / 8.0), + REAL_CONST(28042.187043588601 / 8.0), + REAL_CONST(28059.442446500128 / 8.0), + REAL_CONST(28076.700502660427 / 8.0), + REAL_CONST(28093.961211253929 / 8.0), + REAL_CONST(28111.224571465693 / 8.0), + REAL_CONST(28128.490582481401 / 8.0), + REAL_CONST(28145.759243487362 / 8.0), + REAL_CONST(28163.030553670509 / 8.0), + REAL_CONST(28180.304512218394 / 8.0), + REAL_CONST(28197.581118319198 / 8.0), + REAL_CONST(28214.860371161725 / 8.0), + REAL_CONST(28232.14226993539 / 8.0), + REAL_CONST(28249.42681383024 / 8.0), + REAL_CONST(28266.71400203693 / 8.0), + REAL_CONST(28284.003833746745 / 8.0), + REAL_CONST(28301.296308151585 / 8.0), + REAL_CONST(28318.591424443959 / 8.0), + REAL_CONST(28335.889181817001 / 8.0), + REAL_CONST(28353.189579464462 / 8.0), + REAL_CONST(28370.492616580705 / 8.0), + REAL_CONST(28387.798292360701 / 8.0), + REAL_CONST(28405.106606000048 / 8.0), + REAL_CONST(28422.417556694945 / 8.0), + REAL_CONST(28439.731143642206 / 8.0), + REAL_CONST(28457.047366039264 / 8.0), + REAL_CONST(28474.366223084147 / 8.0), + REAL_CONST(28491.687713975512 / 8.0), + REAL_CONST(28509.011837912611 / 8.0), + REAL_CONST(28526.338594095305 / 8.0), + REAL_CONST(28543.667981724069 / 8.0), + REAL_CONST(28560.999999999982 / 8.0), + REAL_CONST(28578.334648124732 / 8.0), + REAL_CONST(28595.671925300605 / 8.0), + REAL_CONST(28613.011830730498 / 8.0), + REAL_CONST(28630.354363617909 / 8.0), + REAL_CONST(28647.699523166943 / 8.0), + REAL_CONST(28665.0473085823 / 8.0), + REAL_CONST(28682.397719069289 / 8.0), + REAL_CONST(28699.750753833818 / 8.0), + REAL_CONST(28717.10641208239 / 8.0), + REAL_CONST(28734.464693022121 / 8.0), + REAL_CONST(28751.825595860708 / 8.0), + REAL_CONST(28769.189119806462 / 8.0), + REAL_CONST(28786.55526406828 / 8.0), + REAL_CONST(28803.924027855664 / 8.0), + REAL_CONST(28821.295410378701 / 8.0), + REAL_CONST(28838.669410848088 / 8.0), + REAL_CONST(28856.046028475103 / 8.0), + REAL_CONST(28873.425262471628 / 8.0), + REAL_CONST(28890.80711205013 / 8.0), + REAL_CONST(28908.191576423673 / 8.0), + REAL_CONST(28925.578654805915 / 8.0), + REAL_CONST(28942.968346411097 / 8.0), + REAL_CONST(28960.360650454055 / 8.0), + REAL_CONST(28977.755566150216 / 8.0), + REAL_CONST(28995.153092715591 / 8.0), + REAL_CONST(29012.553229366786 / 8.0), + REAL_CONST(29029.955975320987 / 8.0), + REAL_CONST(29047.361329795975 / 8.0), + REAL_CONST(29064.769292010107 / 8.0), + REAL_CONST(29082.179861182336 / 8.0), + REAL_CONST(29099.593036532187 / 8.0), + REAL_CONST(29117.00881727978 / 8.0), + REAL_CONST(29134.427202645813 / 8.0), + REAL_CONST(29151.848191851568 / 8.0), + REAL_CONST(29169.271784118911 / 8.0), + REAL_CONST(29186.697978670283 / 8.0), + REAL_CONST(29204.126774728706 / 8.0), + REAL_CONST(29221.55817151779 / 8.0), + REAL_CONST(29238.992168261717 / 8.0), + REAL_CONST(29256.42876418525 / 8.0), + REAL_CONST(29273.867958513725 / 8.0), + REAL_CONST(29291.309750473058 / 8.0), + REAL_CONST(29308.754139289747 / 8.0), + REAL_CONST(29326.201124190855 / 8.0), + REAL_CONST(29343.65070440403 / 8.0), + REAL_CONST(29361.102879157483 / 8.0), + REAL_CONST(29378.557647680012 / 8.0), + REAL_CONST(29396.015009200975 / 8.0), + REAL_CONST(29413.474962950309 / 8.0), + REAL_CONST(29430.937508158524 / 8.0), + REAL_CONST(29448.402644056692 / 8.0), + REAL_CONST(29465.870369876469 / 8.0), + REAL_CONST(29483.340684850071 / 8.0), + REAL_CONST(29500.81358821028 / 8.0), + REAL_CONST(29518.289079190454 / 8.0), + REAL_CONST(29535.767157024511 / 8.0), + REAL_CONST(29553.247820946945 / 8.0), + REAL_CONST(29570.731070192807 / 8.0), + REAL_CONST(29588.216903997723 / 8.0), + REAL_CONST(29605.70532159787 / 8.0), + REAL_CONST(29623.19632223 / 8.0), + REAL_CONST(29640.689905131429 / 8.0), + REAL_CONST(29658.186069540028 / 8.0), + REAL_CONST(29675.684814694236 / 8.0), + REAL_CONST(29693.186139833047 / 8.0), + REAL_CONST(29710.690044196028 / 8.0), + REAL_CONST(29728.196527023298 / 8.0), + REAL_CONST(29745.705587555527 / 8.0), + REAL_CONST(29763.217225033964 / 8.0), + REAL_CONST(29780.731438700397 / 8.0), + REAL_CONST(29798.248227797183 / 8.0), + REAL_CONST(29815.76759156723 / 8.0), + REAL_CONST(29833.289529254005 / 8.0), + REAL_CONST(29850.81404010153 / 8.0), + REAL_CONST(29868.341123354381 / 8.0), + REAL_CONST(29885.870778257693 / 8.0), + REAL_CONST(29903.403004057145 / 8.0), + REAL_CONST(29920.937799998974 / 8.0), + REAL_CONST(29938.475165329975 / 8.0), + REAL_CONST(29956.015099297485 / 8.0), + REAL_CONST(29973.557601149394 / 8.0), + REAL_CONST(29991.102670134147 / 8.0), + REAL_CONST(30008.650305500738 / 8.0), + REAL_CONST(30026.200506498706 / 8.0), + REAL_CONST(30043.753272378144 / 8.0), + REAL_CONST(30061.308602389683 / 8.0), + REAL_CONST(30078.866495784507 / 8.0), + REAL_CONST(30096.426951814352 / 8.0), + REAL_CONST(30113.989969731494 / 8.0), + REAL_CONST(30131.55554878875 / 8.0), + REAL_CONST(30149.123688239491 / 8.0), + REAL_CONST(30166.694387337629 / 8.0), + REAL_CONST(30184.267645337608 / 8.0), + REAL_CONST(30201.843461494434 / 8.0), + REAL_CONST(30219.42183506364 / 8.0), + REAL_CONST(30237.002765301309 / 8.0), + REAL_CONST(30254.586251464058 / 8.0), + REAL_CONST(30272.172292809046 / 8.0), + REAL_CONST(30289.760888593977 / 8.0), + REAL_CONST(30307.35203807709 / 8.0), + REAL_CONST(30324.94574051716 / 8.0), + REAL_CONST(30342.541995173502 / 8.0), + REAL_CONST(30360.140801305966 / 8.0), + REAL_CONST(30377.742158174944 / 8.0), + REAL_CONST(30395.346065041358 / 8.0), + REAL_CONST(30412.952521166666 / 8.0), + REAL_CONST(30430.561525812864 / 8.0), + REAL_CONST(30448.173078242475 / 8.0), + REAL_CONST(30465.787177718561 / 8.0), + REAL_CONST(30483.403823504719 / 8.0), + REAL_CONST(30501.02301486507 / 8.0), + REAL_CONST(30518.644751064272 / 8.0), + REAL_CONST(30536.269031367516 / 8.0), + REAL_CONST(30553.895855040515 / 8.0), + REAL_CONST(30571.525221349519 / 8.0), + REAL_CONST(30589.157129561307 / 8.0), + REAL_CONST(30606.791578943175 / 8.0), + REAL_CONST(30624.428568762964 / 8.0), + REAL_CONST(30642.06809828903 / 8.0), + REAL_CONST(30659.710166790261 / 8.0), + REAL_CONST(30677.35477353607 / 8.0), + REAL_CONST(30695.001917796391 / 8.0), + REAL_CONST(30712.651598841687 / 8.0), + REAL_CONST(30730.303815942945 / 8.0), + REAL_CONST(30747.958568371676 / 8.0), + REAL_CONST(30765.615855399912 / 8.0), + REAL_CONST(30783.275676300211 / 8.0), + REAL_CONST(30800.938030345646 / 8.0), + REAL_CONST(30818.602916809814 / 8.0), + REAL_CONST(30836.270334966837 / 8.0), + REAL_CONST(30853.940284091354 / 8.0), + REAL_CONST(30871.612763458521 / 8.0), + REAL_CONST(30889.287772344011 / 8.0), + REAL_CONST(30906.965310024025 / 8.0), + REAL_CONST(30924.645375775272 / 8.0), + REAL_CONST(30942.327968874983 / 8.0), + REAL_CONST(30960.013088600903 / 8.0), + REAL_CONST(30977.700734231294 / 8.0), + REAL_CONST(30995.390905044929 / 8.0), + REAL_CONST(31013.083600321101 / 8.0), + REAL_CONST(31030.778819339619 / 8.0), + REAL_CONST(31048.476561380798 / 8.0), + REAL_CONST(31066.17682572547 / 8.0), + REAL_CONST(31083.879611654978 / 8.0), + REAL_CONST(31101.584918451179 / 8.0), + REAL_CONST(31119.29274539644 / 8.0), + REAL_CONST(31137.003091773637 / 8.0), + REAL_CONST(31154.715956866155 / 8.0), + REAL_CONST(31172.431339957893 / 8.0), + REAL_CONST(31190.14924033326 / 8.0), + REAL_CONST(31207.869657277162 / 8.0), + REAL_CONST(31225.592590075023 / 8.0), + REAL_CONST(31243.318038012771 / 8.0), + REAL_CONST(31261.046000376838 / 8.0), + REAL_CONST(31278.776476454172 / 8.0), + REAL_CONST(31296.50946553221 / 8.0), + REAL_CONST(31314.24496689891 / 8.0), + REAL_CONST(31331.98297984272 / 8.0), + REAL_CONST(31349.7235036526 / 8.0), + REAL_CONST(31367.466537618013 / 8.0), + REAL_CONST(31385.212081028923 / 8.0), + REAL_CONST(31402.960133175795 / 8.0), + REAL_CONST(31420.710693349596 / 8.0), + REAL_CONST(31438.463760841791 / 8.0), + REAL_CONST(31456.219334944351 / 8.0), + REAL_CONST(31473.977414949743 / 8.0), + REAL_CONST(31491.738000150934 / 8.0), + REAL_CONST(31509.501089841389 / 8.0), + REAL_CONST(31527.266683315069 / 8.0), + REAL_CONST(31545.034779866437 / 8.0), + REAL_CONST(31562.80537879045 / 8.0), + REAL_CONST(31580.578479382562 / 8.0), + REAL_CONST(31598.35408093872 / 8.0), + REAL_CONST(31616.132182755369 / 8.0), + REAL_CONST(31633.91278412945 / 8.0), + REAL_CONST(31651.695884358396 / 8.0), + REAL_CONST(31669.481482740131 / 8.0), + REAL_CONST(31687.269578573076 / 8.0), + REAL_CONST(31705.060171156143 / 8.0), + REAL_CONST(31722.853259788735 / 8.0), + REAL_CONST(31740.648843770748 / 8.0), + REAL_CONST(31758.446922402567 / 8.0), + REAL_CONST(31776.247494985066 / 8.0), + REAL_CONST(31794.050560819614 / 8.0), + REAL_CONST(31811.85611920806 / 8.0), + REAL_CONST(31829.664169452753 / 8.0), + REAL_CONST(31847.474710856521 / 8.0), + REAL_CONST(31865.287742722685 / 8.0), + REAL_CONST(31883.103264355046 / 8.0), + REAL_CONST(31900.921275057899 / 8.0), + REAL_CONST(31918.741774136019 / 8.0), + REAL_CONST(31936.564760894671 / 8.0), + REAL_CONST(31954.390234639599 / 8.0), + REAL_CONST(31972.21819467704 / 8.0), + REAL_CONST(31990.048640313704 / 8.0), + REAL_CONST(32007.881570856793 / 8.0), + REAL_CONST(32025.716985613984 / 8.0), + REAL_CONST(32043.554883893445 / 8.0), + REAL_CONST(32061.395265003815 / 8.0), + REAL_CONST(32079.238128254223 / 8.0), + REAL_CONST(32097.083472954269 / 8.0), + REAL_CONST(32114.931298414049 / 8.0), + REAL_CONST(32132.781603944117 / 8.0), + REAL_CONST(32150.634388855524 / 8.0), + REAL_CONST(32168.48965245979 / 8.0), + REAL_CONST(32186.347394068915 / 8.0), + REAL_CONST(32204.207612995371 / 8.0), + REAL_CONST(32222.07030855212 / 8.0), + REAL_CONST(32239.935480052583 / 8.0), + REAL_CONST(32257.803126810672 / 8.0), + REAL_CONST(32275.673248140767 / 8.0), + REAL_CONST(32293.545843357719 / 8.0), + REAL_CONST(32311.420911776862 / 8.0), + REAL_CONST(32329.298452713996 / 8.0), + REAL_CONST(32347.178465485395 / 8.0), + REAL_CONST(32365.060949407813 / 8.0), + REAL_CONST(32382.945903798463 / 8.0), + REAL_CONST(32400.83332797504 / 8.0), + REAL_CONST(32418.723221255706 / 8.0), + REAL_CONST(32436.615582959093 / 8.0), + REAL_CONST(32454.510412404306 / 8.0), + REAL_CONST(32472.407708910916 / 8.0), + REAL_CONST(32490.307471798966 / 8.0), + REAL_CONST(32508.209700388961 / 8.0), + REAL_CONST(32526.114394001877 / 8.0), + REAL_CONST(32544.021551959166 / 8.0), + REAL_CONST(32561.931173582732 / 8.0), + REAL_CONST(32579.843258194956 / 8.0), + REAL_CONST(32597.757805118679 / 8.0), + REAL_CONST(32615.674813677211 / 8.0), + REAL_CONST(32633.594283194328 / 8.0), + REAL_CONST(32651.516212994258 / 8.0), + REAL_CONST(32669.440602401712 / 8.0), + REAL_CONST(32687.367450741847 / 8.0), + REAL_CONST(32705.296757340297 / 8.0), + REAL_CONST(32723.228521523146 / 8.0), + REAL_CONST(32741.162742616943 / 8.0), + REAL_CONST(32759.099419948703 / 8.0), + REAL_CONST(32777.038552845901 / 8.0), + REAL_CONST(32794.980140636464 / 8.0), + REAL_CONST(32812.924182648792 / 8.0), + REAL_CONST(32830.87067821173 / 8.0), + REAL_CONST(32848.819626654593 / 8.0), + REAL_CONST(32866.77102730715 / 8.0), + REAL_CONST(32884.724879499619 / 8.0), + REAL_CONST(32902.681182562686 / 8.0), + REAL_CONST(32920.639935827494 / 8.0), + REAL_CONST(32938.601138625643 / 8.0), + REAL_CONST(32956.56479028918 / 8.0), + REAL_CONST(32974.530890150607 / 8.0), + REAL_CONST(32992.499437542894 / 8.0), + REAL_CONST(33010.470431799447 / 8.0), + REAL_CONST(33028.443872254145 / 8.0), + REAL_CONST(33046.419758241311 / 8.0), + REAL_CONST(33064.39808909571 / 8.0), + REAL_CONST(33082.378864152583 / 8.0), + REAL_CONST(33100.36208274759 / 8.0), + REAL_CONST(33118.347744216881 / 8.0), + REAL_CONST(33136.335847897026 / 8.0), + REAL_CONST(33154.326393125062 / 8.0), + REAL_CONST(33172.31937923847 / 8.0), + REAL_CONST(33190.314805575174 / 8.0), + REAL_CONST(33208.312671473555 / 8.0), + REAL_CONST(33226.312976272442 / 8.0), + REAL_CONST(33244.315719311111 / 8.0), + REAL_CONST(33262.320899929284 / 8.0), + REAL_CONST(33280.328517467125 / 8.0), + REAL_CONST(33298.33857126526 / 8.0), + REAL_CONST(33316.351060664747 / 8.0), + REAL_CONST(33334.365985007091 / 8.0), + REAL_CONST(33352.383343634239 / 8.0), + REAL_CONST(33370.403135888591 / 8.0), + REAL_CONST(33388.42536111299 / 8.0), + REAL_CONST(33406.450018650721 / 8.0), + REAL_CONST(33424.477107845501 / 8.0), + REAL_CONST(33442.506628041512 / 8.0), + REAL_CONST(33460.53857858335 / 8.0), + REAL_CONST(33478.572958816083 / 8.0), + REAL_CONST(33496.609768085189 / 8.0), + REAL_CONST(33514.649005736617 / 8.0), + REAL_CONST(33532.690671116739 / 8.0), + REAL_CONST(33550.734763572356 / 8.0), + REAL_CONST(33568.781282450735 / 8.0), + REAL_CONST(33586.830227099563 / 8.0), + REAL_CONST(33604.881596866973 / 8.0), + REAL_CONST(33622.935391101528 / 8.0), + REAL_CONST(33640.991609152239 / 8.0), + REAL_CONST(33659.050250368542 / 8.0), + REAL_CONST(33677.111314100322 / 8.0), + REAL_CONST(33695.174799697881 / 8.0), + REAL_CONST(33713.240706511984 / 8.0), + REAL_CONST(33731.309033893805 / 8.0), + REAL_CONST(33749.37978119497 / 8.0), + REAL_CONST(33767.452947767531 / 8.0), + REAL_CONST(33785.528532963974 / 8.0), + REAL_CONST(33803.606536137209 / 8.0), + REAL_CONST(33821.686956640602 / 8.0), + REAL_CONST(33839.769793827938 / 8.0), + REAL_CONST(33857.855047053425 / 8.0), + REAL_CONST(33875.942715671707 / 8.0), + REAL_CONST(33894.032799037872 / 8.0), + REAL_CONST(33912.125296507431 / 8.0), + REAL_CONST(33930.220207436316 / 8.0), + REAL_CONST(33948.317531180888 / 8.0), + REAL_CONST(33966.417267097961 / 8.0), + REAL_CONST(33984.519414544746 / 8.0), + REAL_CONST(34002.623972878901 / 8.0), + REAL_CONST(34020.730941458511 / 8.0), + REAL_CONST(34038.840319642077 / 8.0), + REAL_CONST(34056.952106788536 / 8.0), + REAL_CONST(34075.066302257255 / 8.0), + REAL_CONST(34093.182905408015 / 8.0), + REAL_CONST(34111.301915601027 / 8.0), + REAL_CONST(34129.42333219693 / 8.0), + REAL_CONST(34147.547154556785 / 8.0), + REAL_CONST(34165.673382042078 / 8.0), + REAL_CONST(34183.80201401472 / 8.0), + REAL_CONST(34201.933049837033 / 8.0), + REAL_CONST(34220.06648887178 / 8.0), + REAL_CONST(34238.202330482141 / 8.0), + REAL_CONST(34256.340574031703 / 8.0), + REAL_CONST(34274.481218884495 / 8.0), + REAL_CONST(34292.624264404949 / 8.0), + REAL_CONST(34310.769709957938 / 8.0), + REAL_CONST(34328.91755490873 / 8.0), + REAL_CONST(34347.067798623029 / 8.0), + REAL_CONST(34365.220440466954 / 8.0), + REAL_CONST(34383.375479807051 / 8.0), + REAL_CONST(34401.532916010263 / 8.0), + REAL_CONST(34419.692748443973 / 8.0), + REAL_CONST(34437.854976475966 / 8.0), + REAL_CONST(34456.01959947445 / 8.0), + REAL_CONST(34474.18661680806 / 8.0), + REAL_CONST(34492.356027845817 / 8.0), + REAL_CONST(34510.527831957188 / 8.0), + REAL_CONST(34528.702028512052 / 8.0), + REAL_CONST(34546.878616880676 / 8.0), + REAL_CONST(34565.05759643377 / 8.0), + REAL_CONST(34583.238966542449 / 8.0), + REAL_CONST(34601.422726578232 / 8.0), + REAL_CONST(34619.608875913065 / 8.0), + REAL_CONST(34637.797413919296 / 8.0), + REAL_CONST(34655.988339969692 / 8.0), + REAL_CONST(34674.181653437423 / 8.0), + REAL_CONST(34692.37735369608 / 8.0), + REAL_CONST(34710.575440119668 / 8.0), + REAL_CONST(34728.775912082579 / 8.0), + REAL_CONST(34746.978768959649 / 8.0), + REAL_CONST(34765.184010126082 / 8.0), + REAL_CONST(34783.391634957537 / 8.0), + REAL_CONST(34801.60164283005 / 8.0), + REAL_CONST(34819.814033120063 / 8.0), + REAL_CONST(34838.028805204456 / 8.0), + REAL_CONST(34856.24595846048 / 8.0), + REAL_CONST(34874.465492265823 / 8.0), + REAL_CONST(34892.687405998557 / 8.0), + REAL_CONST(34910.911699037177 / 8.0), + REAL_CONST(34929.138370760564 / 8.0), + REAL_CONST(34947.367420548027 / 8.0), + REAL_CONST(34965.598847779271 / 8.0), + REAL_CONST(34983.832651834389 / 8.0), + REAL_CONST(35002.068832093908 / 8.0), + REAL_CONST(35020.307387938738 / 8.0), + REAL_CONST(35038.548318750189 / 8.0), + REAL_CONST(35056.79162390998 / 8.0), + REAL_CONST(35075.03730280025 / 8.0), + REAL_CONST(35093.285354803513 / 8.0), + REAL_CONST(35111.535779302685 / 8.0), + REAL_CONST(35129.788575681116 / 8.0), + REAL_CONST(35148.043743322516 / 8.0), + REAL_CONST(35166.301281611013 / 8.0), + REAL_CONST(35184.561189931141 / 8.0), + REAL_CONST(35202.823467667826 / 8.0), + REAL_CONST(35221.088114206388 / 8.0), + REAL_CONST(35239.355128932555 / 8.0), + REAL_CONST(35257.624511232447 / 8.0), + REAL_CONST(35275.896260492584 / 8.0), + REAL_CONST(35294.170376099886 / 8.0), + REAL_CONST(35312.446857441668 / 8.0), + REAL_CONST(35330.725703905628 / 8.0), + REAL_CONST(35349.006914879887 / 8.0), + REAL_CONST(35367.290489752944 / 8.0), + REAL_CONST(35385.576427913686 / 8.0), + REAL_CONST(35403.864728751418 / 8.0), + REAL_CONST(35422.155391655811 / 8.0), + REAL_CONST(35440.448416016967 / 8.0), + REAL_CONST(35458.743801225341 / 8.0), + REAL_CONST(35477.041546671804 / 8.0), + REAL_CONST(35495.341651747622 / 8.0), + REAL_CONST(35513.644115844436 / 8.0), + REAL_CONST(35531.948938354304 / 8.0), + REAL_CONST(35550.256118669655 / 8.0), + REAL_CONST(35568.565656183309 / 8.0), + REAL_CONST(35586.877550288496 / 8.0), + REAL_CONST(35605.191800378816 / 8.0), + REAL_CONST(35623.508405848268 / 8.0), + REAL_CONST(35641.827366091238 / 8.0), + REAL_CONST(35660.148680502505 / 8.0), + REAL_CONST(35678.472348477233 / 8.0), + REAL_CONST(35696.798369410979 / 8.0), + REAL_CONST(35715.126742699678 / 8.0), + REAL_CONST(35733.457467739659 / 8.0), + REAL_CONST(35751.790543927644 / 8.0), + REAL_CONST(35770.125970660738 / 8.0), + REAL_CONST(35788.46374733642 / 8.0), + REAL_CONST(35806.803873352568 / 8.0), + REAL_CONST(35825.146348107453 / 8.0), + REAL_CONST(35843.49117099971 / 8.0), + REAL_CONST(35861.838341428367 / 8.0), + REAL_CONST(35880.187858792851 / 8.0), + REAL_CONST(35898.539722492955 / 8.0), + REAL_CONST(35916.893931928862 / 8.0), + REAL_CONST(35935.250486501129 / 8.0), + REAL_CONST(35953.609385610718 / 8.0), + REAL_CONST(35971.970628658957 / 8.0), + REAL_CONST(35990.334215047558 / 8.0), + REAL_CONST(36008.700144178612 / 8.0), + REAL_CONST(36027.068415454596 / 8.0), + REAL_CONST(36045.439028278372 / 8.0), + REAL_CONST(36063.811982053165 / 8.0), + REAL_CONST(36082.187276182609 / 8.0), + REAL_CONST(36100.564910070694 / 8.0), + REAL_CONST(36118.944883121789 / 8.0), + REAL_CONST(36137.327194740654 / 8.0), + REAL_CONST(36155.711844332429 / 8.0), + REAL_CONST(36174.098831302617 / 8.0), + REAL_CONST(36192.488155057115 / 8.0), + REAL_CONST(36210.87981500219 / 8.0), + REAL_CONST(36229.273810544473 / 8.0), + REAL_CONST(36247.670141091003 / 8.0), + REAL_CONST(36266.068806049167 / 8.0), + REAL_CONST(36284.469804826738 / 8.0), + REAL_CONST(36302.873136831862 / 8.0), + REAL_CONST(36321.278801473069 / 8.0), + REAL_CONST(36339.686798159251 / 8.0), + REAL_CONST(36358.097126299683 / 8.0), + REAL_CONST(36376.509785304013 / 8.0), + REAL_CONST(36394.924774582258 / 8.0), + REAL_CONST(36413.342093544816 / 8.0), + REAL_CONST(36431.761741602444 / 8.0), + REAL_CONST(36450.183718166292 / 8.0), + REAL_CONST(36468.608022647859 / 8.0), + REAL_CONST(36487.034654459028 / 8.0), + REAL_CONST(36505.463613012063 / 8.0), + REAL_CONST(36523.894897719583 / 8.0), + REAL_CONST(36542.328507994578 / 8.0), + REAL_CONST(36560.764443250409 / 8.0), + REAL_CONST(36579.202702900831 / 8.0), + REAL_CONST(36597.643286359926 / 8.0), + REAL_CONST(36616.086193042182 / 8.0), + REAL_CONST(36634.531422362437 / 8.0), + REAL_CONST(36652.978973735895 / 8.0), + REAL_CONST(36671.428846578143 / 8.0), + REAL_CONST(36689.881040305125 / 8.0), + REAL_CONST(36708.335554333149 / 8.0), + REAL_CONST(36726.792388078902 / 8.0), + REAL_CONST(36745.251540959427 / 8.0), + REAL_CONST(36763.713012392138 / 8.0), + REAL_CONST(36782.176801794812 / 8.0), + REAL_CONST(36800.642908585593 / 8.0), + REAL_CONST(36819.111332182983 / 8.0), + REAL_CONST(36837.582072005869 / 8.0), + REAL_CONST(36856.055127473483 / 8.0), + REAL_CONST(36874.530498005421 / 8.0), + REAL_CONST(36893.008183021651 / 8.0), + REAL_CONST(36911.488181942506 / 8.0), + REAL_CONST(36929.970494188674 / 8.0), + REAL_CONST(36948.455119181206 / 8.0), + REAL_CONST(36966.942056341519 / 8.0), + REAL_CONST(36985.431305091392 / 8.0), + REAL_CONST(37003.922864852961 / 8.0), + REAL_CONST(37022.416735048733 / 8.0), + REAL_CONST(37040.912915101559 / 8.0), + REAL_CONST(37059.411404434657 / 8.0), + REAL_CONST(37077.91220247162 / 8.0), + REAL_CONST(37096.415308636388 / 8.0), + REAL_CONST(37114.920722353243 / 8.0), + REAL_CONST(37133.428443046862 / 8.0), + REAL_CONST(37151.938470142253 / 8.0), + REAL_CONST(37170.450803064785 / 8.0), + REAL_CONST(37188.965441240209 / 8.0), + REAL_CONST(37207.482384094597 / 8.0), + REAL_CONST(37226.001631054402 / 8.0), + REAL_CONST(37244.523181546429 / 8.0), + REAL_CONST(37263.047034997842 / 8.0), + REAL_CONST(37281.573190836149 / 8.0), + REAL_CONST(37300.101648489224 / 8.0), + REAL_CONST(37318.632407385296 / 8.0), + REAL_CONST(37337.165466952945 / 8.0), + REAL_CONST(37355.700826621112 / 8.0), + REAL_CONST(37374.238485819085 / 8.0), + REAL_CONST(37392.778443976509 / 8.0), + REAL_CONST(37411.320700523385 / 8.0), + REAL_CONST(37429.865254890057 / 8.0), + REAL_CONST(37448.412106507232 / 8.0), + REAL_CONST(37466.961254805974 / 8.0), + REAL_CONST(37485.512699217681 / 8.0), + REAL_CONST(37504.066439174116 / 8.0), + REAL_CONST(37522.622474107404 / 8.0), + REAL_CONST(37541.180803449992 / 8.0), + REAL_CONST(37559.741426634704 / 8.0), + REAL_CONST(37578.304343094693 / 8.0), + REAL_CONST(37596.869552263488 / 8.0), + REAL_CONST(37615.43705357494 / 8.0), + REAL_CONST(37634.006846463279 / 8.0), + REAL_CONST(37652.578930363044 / 8.0), + REAL_CONST(37671.153304709165 / 8.0), + REAL_CONST(37689.729968936896 / 8.0), + REAL_CONST(37708.308922481847 / 8.0), + REAL_CONST(37726.890164779965 / 8.0), + REAL_CONST(37745.473695267559 / 8.0), + REAL_CONST(37764.059513381275 / 8.0), + REAL_CONST(37782.647618558112 / 8.0), + REAL_CONST(37801.238010235415 / 8.0), + REAL_CONST(37819.830687850859 / 8.0), + REAL_CONST(37838.425650842495 / 8.0), + REAL_CONST(37857.022898648691 / 8.0), + REAL_CONST(37875.622430708172 / 8.0), + REAL_CONST(37894.224246460013 / 8.0), + REAL_CONST(37912.828345343616 / 8.0), + REAL_CONST(37931.434726798747 / 8.0), + REAL_CONST(37950.043390265506 / 8.0), + REAL_CONST(37968.654335184328 / 8.0), + REAL_CONST(37987.267560995999 / 8.0), + REAL_CONST(38005.883067141665 / 8.0), + REAL_CONST(38024.500853062775 / 8.0), + REAL_CONST(38043.120918201159 / 8.0), + REAL_CONST(38061.743261998963 / 8.0), + REAL_CONST(38080.367883898682 / 8.0), + REAL_CONST(38098.994783343158 / 8.0), + REAL_CONST(38117.623959775563 / 8.0), + REAL_CONST(38136.255412639417 / 8.0), + REAL_CONST(38154.889141378575 / 8.0), + REAL_CONST(38173.525145437234 / 8.0), + REAL_CONST(38192.163424259939 / 8.0), + REAL_CONST(38210.803977291551 / 8.0), + REAL_CONST(38229.446803977284 / 8.0), + REAL_CONST(38248.091903762703 / 8.0), + REAL_CONST(38266.739276093685 / 8.0), + REAL_CONST(38285.388920416466 / 8.0), + REAL_CONST(38304.040836177606 / 8.0), + REAL_CONST(38322.695022824002 / 8.0), + REAL_CONST(38341.351479802899 / 8.0), + REAL_CONST(38360.010206561863 / 8.0), + REAL_CONST(38378.671202548816 / 8.0), + REAL_CONST(38397.334467211993 / 8.0), + REAL_CONST(38415.999999999978 / 8.0), + REAL_CONST(38434.667800361683 / 8.0), + REAL_CONST(38453.33786774637 / 8.0), + REAL_CONST(38472.010201603611 / 8.0), + REAL_CONST(38490.684801383337 / 8.0), + REAL_CONST(38509.361666535784 / 8.0), + REAL_CONST(38528.040796511552 / 8.0), + REAL_CONST(38546.722190761553 / 8.0), + REAL_CONST(38565.405848737035 / 8.0), + REAL_CONST(38584.091769889594 / 8.0), + REAL_CONST(38602.779953671132 / 8.0), + REAL_CONST(38621.470399533908 / 8.0), + REAL_CONST(38640.163106930493 / 8.0), + REAL_CONST(38658.858075313794 / 8.0), + REAL_CONST(38677.555304137059 / 8.0), + REAL_CONST(38696.254792853862 / 8.0), + REAL_CONST(38714.956540918094 / 8.0), + REAL_CONST(38733.660547783991 / 8.0), + REAL_CONST(38752.366812906112 / 8.0), + REAL_CONST(38771.075335739348 / 8.0), + REAL_CONST(38789.78611573892 / 8.0), + REAL_CONST(38808.499152360368 / 8.0), + REAL_CONST(38827.214445059573 / 8.0), + REAL_CONST(38845.931993292739 / 8.0), + REAL_CONST(38864.651796516388 / 8.0), + REAL_CONST(38883.373854187383 / 8.0), + REAL_CONST(38902.098165762916 / 8.0), + REAL_CONST(38920.824730700486 / 8.0), + REAL_CONST(38939.553548457938 / 8.0), + REAL_CONST(38958.284618493431 / 8.0), + REAL_CONST(38977.017940265461 / 8.0), + REAL_CONST(38995.753513232834 / 8.0), + REAL_CONST(39014.491336854699 / 8.0), + REAL_CONST(39033.231410590517 / 8.0), + REAL_CONST(39051.973733900079 / 8.0), + REAL_CONST(39070.718306243485 / 8.0), + REAL_CONST(39089.465127081188 / 8.0), + REAL_CONST(39108.214195873945 / 8.0), + REAL_CONST(39126.965512082832 / 8.0), + REAL_CONST(39145.719075169261 / 8.0), + REAL_CONST(39164.474884594965 / 8.0), + REAL_CONST(39183.232939821988 / 8.0), + REAL_CONST(39201.99324031271 / 8.0), + REAL_CONST(39220.755785529815 / 8.0), + REAL_CONST(39239.52057493633 / 8.0), + REAL_CONST(39258.287607995589 / 8.0), + REAL_CONST(39277.056884171245 / 8.0), + REAL_CONST(39295.828402927284 / 8.0), + REAL_CONST(39314.602163728006 / 8.0), + REAL_CONST(39333.378166038019 / 8.0), + REAL_CONST(39352.15640932227 / 8.0), + REAL_CONST(39370.936893046004 / 8.0), + REAL_CONST(39389.719616674811 / 8.0), + REAL_CONST(39408.504579674584 / 8.0), + REAL_CONST(39427.291781511522 / 8.0), + REAL_CONST(39446.081221652174 / 8.0), + REAL_CONST(39464.872899563372 / 8.0), + REAL_CONST(39483.666814712291 / 8.0), + REAL_CONST(39502.462966566411 / 8.0), + REAL_CONST(39521.261354593538 / 8.0), + REAL_CONST(39540.06197826178 / 8.0), + REAL_CONST(39558.864837039568 / 8.0), + REAL_CONST(39577.669930395656 / 8.0), + REAL_CONST(39596.47725779911 / 8.0), + REAL_CONST(39615.286818719302 / 8.0), + REAL_CONST(39634.098612625923 / 8.0), + REAL_CONST(39652.912638988993 / 8.0), + REAL_CONST(39671.728897278823 / 8.0), + REAL_CONST(39690.547386966064 / 8.0), + REAL_CONST(39709.368107521652 / 8.0), + REAL_CONST(39728.191058416858 / 8.0), + REAL_CONST(39747.016239123259 / 8.0), + REAL_CONST(39765.84364911275 / 8.0), + REAL_CONST(39784.673287857528 / 8.0), + REAL_CONST(39803.505154830105 / 8.0), + REAL_CONST(39822.339249503319 / 8.0), + REAL_CONST(39841.175571350293 / 8.0), + REAL_CONST(39860.014119844491 / 8.0), + REAL_CONST(39878.854894459677 / 8.0), + REAL_CONST(39897.697894669909 / 8.0), + REAL_CONST(39916.54311994958 / 8.0), + REAL_CONST(39935.390569773372 / 8.0), + REAL_CONST(39954.240243616303 / 8.0), + REAL_CONST(39973.092140953675 / 8.0), + REAL_CONST(39991.946261261117 / 8.0), + REAL_CONST(40010.802604014549 / 8.0), + REAL_CONST(40029.661168690225 / 8.0), + REAL_CONST(40048.521954764678 / 8.0), + REAL_CONST(40067.384961714779 / 8.0), + REAL_CONST(40086.250189017679 / 8.0), + REAL_CONST(40105.117636150855 / 8.0), + REAL_CONST(40123.98730259209 / 8.0), + REAL_CONST(40142.859187819471 / 8.0), + REAL_CONST(40161.733291311379 / 8.0), + REAL_CONST(40180.609612546526 / 8.0), + REAL_CONST(40199.488151003912 / 8.0), + REAL_CONST(40218.368906162854 / 8.0), + REAL_CONST(40237.25187750296 / 8.0), + REAL_CONST(40256.137064504153 / 8.0), + REAL_CONST(40275.024466646668 / 8.0), + REAL_CONST(40293.914083411029 / 8.0), + REAL_CONST(40312.805914278084 / 8.0), + REAL_CONST(40331.699958728961 / 8.0), + REAL_CONST(40350.596216245103 / 8.0), + REAL_CONST(40369.494686308273 / 8.0), + REAL_CONST(40388.39536840051 / 8.0), + REAL_CONST(40407.298262004173 / 8.0), + REAL_CONST(40426.20336660192 / 8.0), + REAL_CONST(40445.110681676706 / 8.0), + REAL_CONST(40464.020206711793 / 8.0), + REAL_CONST(40482.931941190756 / 8.0), + REAL_CONST(40501.845884597446 / 8.0), + REAL_CONST(40520.762036416032 / 8.0), + REAL_CONST(40539.680396130985 / 8.0), + REAL_CONST(40558.600963227072 / 8.0), + REAL_CONST(40577.523737189367 / 8.0), + REAL_CONST(40596.448717503234 / 8.0), + REAL_CONST(40615.375903654342 / 8.0), + REAL_CONST(40634.305295128659 / 8.0), + REAL_CONST(40653.236891412453 / 8.0), + REAL_CONST(40672.170691992294 / 8.0), + REAL_CONST(40691.106696355047 / 8.0), + REAL_CONST(40710.044903987873 / 8.0), + REAL_CONST(40728.985314378238 / 8.0), + REAL_CONST(40747.927927013901 / 8.0), + REAL_CONST(40766.872741382918 / 8.0), + REAL_CONST(40785.819756973651 / 8.0), + REAL_CONST(40804.768973274746 / 8.0), + REAL_CONST(40823.720389775161 / 8.0), + REAL_CONST(40842.674005964131 / 8.0), + REAL_CONST(40861.629821331211 / 8.0), + REAL_CONST(40880.587835366234 / 8.0), + REAL_CONST(40899.548047559321 / 8.0), + REAL_CONST(40918.510457400931 / 8.0), + REAL_CONST(40937.475064381761 / 8.0), + REAL_CONST(40956.441867992849 / 8.0), + REAL_CONST(40975.410867725499 / 8.0), + REAL_CONST(40994.382063071331 / 8.0), + REAL_CONST(41013.355453522236 / 8.0), + REAL_CONST(41032.331038570417 / 8.0), + REAL_CONST(41051.308817708363 / 8.0), + REAL_CONST(41070.288790428858 / 8.0), + REAL_CONST(41089.270956224987 / 8.0), + REAL_CONST(41108.255314590111 / 8.0), + REAL_CONST(41127.241865017888 / 8.0), + REAL_CONST(41146.23060700229 / 8.0), + REAL_CONST(41165.221540037543 / 8.0), + REAL_CONST(41184.214663618193 / 8.0), + REAL_CONST(41203.209977239079 / 8.0), + REAL_CONST(41222.207480395307 / 8.0), + REAL_CONST(41241.207172582297 / 8.0), + REAL_CONST(41260.209053295752 / 8.0), + REAL_CONST(41279.213122031659 / 8.0), + REAL_CONST(41298.219378286303 / 8.0), + REAL_CONST(41317.227821556255 / 8.0), + REAL_CONST(41336.23845133838 / 8.0), + REAL_CONST(41355.251267129832 / 8.0), + REAL_CONST(41374.266268428037 / 8.0), + REAL_CONST(41393.283454730743 / 8.0), + REAL_CONST(41412.302825535953 / 8.0), + REAL_CONST(41431.324380341983 / 8.0), + REAL_CONST(41450.348118647416 / 8.0), + REAL_CONST(41469.374039951144 / 8.0), + REAL_CONST(41488.402143752326 / 8.0), + REAL_CONST(41507.432429550427 / 8.0), + REAL_CONST(41526.464896845187 / 8.0), + REAL_CONST(41545.499545136627 / 8.0), + REAL_CONST(41564.536373925075 / 8.0), + REAL_CONST(41583.575382711126 / 8.0), + REAL_CONST(41602.616570995662 / 8.0), + REAL_CONST(41621.659938279874 / 8.0), + REAL_CONST(41640.705484065205 / 8.0), + REAL_CONST(41659.753207853406 / 8.0), + REAL_CONST(41678.803109146495 / 8.0), + REAL_CONST(41697.855187446803 / 8.0), + REAL_CONST(41716.909442256911 / 8.0), + REAL_CONST(41735.965873079709 / 8.0), + REAL_CONST(41755.02447941836 / 8.0), + REAL_CONST(41774.085260776315 / 8.0), + REAL_CONST(41793.148216657297 / 8.0), + REAL_CONST(41812.213346565331 / 8.0), + REAL_CONST(41831.280650004708 / 8.0), + REAL_CONST(41850.350126480014 / 8.0), + REAL_CONST(41869.421775496106 / 8.0), + REAL_CONST(41888.495596558132 / 8.0), + REAL_CONST(41907.571589171515 / 8.0), + REAL_CONST(41926.649752841957 / 8.0), + REAL_CONST(41945.730087075463 / 8.0), + REAL_CONST(41964.812591378286 / 8.0), + REAL_CONST(41983.897265256979 / 8.0), + REAL_CONST(42002.984108218378 / 8.0), + REAL_CONST(42022.073119769593 / 8.0), + REAL_CONST(42041.164299418015 / 8.0), + REAL_CONST(42060.257646671307 / 8.0), + REAL_CONST(42079.353161037419 / 8.0), + REAL_CONST(42098.450842024591 / 8.0), + REAL_CONST(42117.550689141324 / 8.0), + REAL_CONST(42136.652701896404 / 8.0), + REAL_CONST(42155.756879798893 / 8.0), + REAL_CONST(42174.863222358137 / 8.0), + REAL_CONST(42193.971729083758 / 8.0), + REAL_CONST(42213.082399485655 / 8.0), + REAL_CONST(42232.195233074002 / 8.0), + REAL_CONST(42251.310229359246 / 8.0), + REAL_CONST(42270.427387852127 / 8.0), + REAL_CONST(42289.546708063644 / 8.0), + REAL_CONST(42308.668189505079 / 8.0), + REAL_CONST(42327.791831687995 / 8.0), + REAL_CONST(42346.917634124227 / 8.0), + REAL_CONST(42366.045596325886 / 8.0), + REAL_CONST(42385.175717805352 / 8.0), + REAL_CONST(42404.307998075295 / 8.0), + REAL_CONST(42423.442436648642 / 8.0), + REAL_CONST(42442.579033038608 / 8.0), + REAL_CONST(42461.717786758672 / 8.0), + REAL_CONST(42480.858697322597 / 8.0), + REAL_CONST(42500.001764244422 / 8.0), + REAL_CONST(42519.146987038446 / 8.0), + REAL_CONST(42538.294365219248 / 8.0), + REAL_CONST(42557.443898301688 / 8.0), + REAL_CONST(42576.595585800882 / 8.0), + REAL_CONST(42595.749427232236 / 8.0), + REAL_CONST(42614.90542211142 / 8.0), + REAL_CONST(42634.063569954378 / 8.0), + REAL_CONST(42653.223870277317 / 8.0), + REAL_CONST(42672.386322596729 / 8.0), + REAL_CONST(42691.55092642938 / 8.0), + REAL_CONST(42710.717681292292 / 8.0), + REAL_CONST(42729.886586702756 / 8.0), + REAL_CONST(42749.057642178363 / 8.0), + REAL_CONST(42768.23084723694 / 8.0), + REAL_CONST(42787.406201396603 / 8.0), + REAL_CONST(42806.58370417574 / 8.0), + REAL_CONST(42825.76335509299 / 8.0), + REAL_CONST(42844.945153667286 / 8.0), + REAL_CONST(42864.129099417805 / 8.0), + REAL_CONST(42883.315191864014 / 8.0), + REAL_CONST(42902.503430525649 / 8.0), + REAL_CONST(42921.693814922692 / 8.0), + REAL_CONST(42940.88634457541 / 8.0), + REAL_CONST(42960.081019004348 / 8.0), + REAL_CONST(42979.277837730297 / 8.0), + REAL_CONST(42998.476800274322 / 8.0), + REAL_CONST(43017.677906157769 / 8.0), + REAL_CONST(43036.881154902228 / 8.0), + REAL_CONST(43056.086546029583 / 8.0), + REAL_CONST(43075.294079061961 / 8.0), + REAL_CONST(43094.503753521763 / 8.0), + REAL_CONST(43113.715568931671 / 8.0), + REAL_CONST(43132.929524814601 / 8.0), + REAL_CONST(43152.145620693766 / 8.0), + REAL_CONST(43171.363856092619 / 8.0), + REAL_CONST(43190.584230534907 / 8.0), + REAL_CONST(43209.806743544621 / 8.0), + REAL_CONST(43229.031394646016 / 8.0), + REAL_CONST(43248.258183363621 / 8.0), + REAL_CONST(43267.487109222224 / 8.0), + REAL_CONST(43286.718171746885 / 8.0), + REAL_CONST(43305.951370462906 / 8.0), + REAL_CONST(43325.186704895881 / 8.0), + REAL_CONST(43344.42417457165 / 8.0), + REAL_CONST(43363.663779016322 / 8.0), + REAL_CONST(43382.905517756262 / 8.0), + REAL_CONST(43402.149390318104 / 8.0), + REAL_CONST(43421.395396228749 / 8.0), + REAL_CONST(43440.643535015348 / 8.0), + REAL_CONST(43459.89380620532 / 8.0), + REAL_CONST(43479.146209326354 / 8.0), + REAL_CONST(43498.400743906379 / 8.0), + REAL_CONST(43517.657409473606 / 8.0), + REAL_CONST(43536.916205556496 / 8.0), + REAL_CONST(43556.177131683784 / 8.0), + REAL_CONST(43575.44018738444 / 8.0), + REAL_CONST(43594.705372187724 / 8.0), + REAL_CONST(43613.972685623135 / 8.0), + REAL_CONST(43633.242127220445 / 8.0), + REAL_CONST(43652.513696509668 / 8.0), + REAL_CONST(43671.787393021099 / 8.0), + REAL_CONST(43691.063216285271 / 8.0), + REAL_CONST(43710.341165833001 / 8.0), + REAL_CONST(43729.621241195346 / 8.0), + REAL_CONST(43748.903441903625 / 8.0), + REAL_CONST(43768.187767489413 / 8.0), + REAL_CONST(43787.474217484552 / 8.0), + REAL_CONST(43806.762791421126 / 8.0), + REAL_CONST(43826.053488831501 / 8.0), + REAL_CONST(43845.346309248278 / 8.0), + REAL_CONST(43864.641252204325 / 8.0), + REAL_CONST(43883.938317232765 / 8.0), + REAL_CONST(43903.237503866971 / 8.0), + REAL_CONST(43922.538811640596 / 8.0), + REAL_CONST(43941.842240087513 / 8.0), + REAL_CONST(43961.147788741881 / 8.0), + REAL_CONST(43980.455457138101 / 8.0), + REAL_CONST(43999.765244810835 / 8.0), + REAL_CONST(44019.077151295001 / 8.0), + REAL_CONST(44038.391176125755 / 8.0), + REAL_CONST(44057.70731883854 / 8.0), + REAL_CONST(44077.02557896902 / 8.0), + REAL_CONST(44096.345956053141 / 8.0), + REAL_CONST(44115.668449627083 / 8.0), + REAL_CONST(44134.993059227287 / 8.0), + REAL_CONST(44154.319784390456 / 8.0), + REAL_CONST(44173.648624653535 / 8.0), + REAL_CONST(44192.979579553728 / 8.0), + REAL_CONST(44212.312648628489 / 8.0), + REAL_CONST(44231.647831415532 / 8.0), + REAL_CONST(44250.985127452805 / 8.0), + REAL_CONST(44270.324536278538 / 8.0), + REAL_CONST(44289.666057431183 / 8.0), + REAL_CONST(44309.009690449464 / 8.0), + REAL_CONST(44328.355434872348 / 8.0), + REAL_CONST(44347.703290239064 / 8.0), + REAL_CONST(44367.053256089079 / 8.0), + REAL_CONST(44386.405331962109 / 8.0), + REAL_CONST(44405.759517398139 / 8.0), + REAL_CONST(44425.115811937387 / 8.0), + REAL_CONST(44444.474215120332 / 8.0), + REAL_CONST(44463.834726487694 / 8.0), + REAL_CONST(44483.197345580462 / 8.0), + REAL_CONST(44502.562071939843 / 8.0), + REAL_CONST(44521.928905107328 / 8.0), + REAL_CONST(44541.297844624634 / 8.0), + REAL_CONST(44560.668890033732 / 8.0), + REAL_CONST(44580.042040876848 / 8.0), + REAL_CONST(44599.417296696454 / 8.0), + REAL_CONST(44618.794657035272 / 8.0), + REAL_CONST(44638.174121436256 / 8.0), + REAL_CONST(44657.555689442641 / 8.0), + REAL_CONST(44676.939360597877 / 8.0), + REAL_CONST(44696.325134445673 / 8.0), + REAL_CONST(44715.713010530002 / 8.0), + REAL_CONST(44735.102988395054 / 8.0), + REAL_CONST(44754.495067585296 / 8.0), + REAL_CONST(44773.88924764542 / 8.0), + REAL_CONST(44793.285528120374 / 8.0), + REAL_CONST(44812.683908555344 / 8.0), + REAL_CONST(44832.084388495779 / 8.0), + REAL_CONST(44851.486967487363 / 8.0), + REAL_CONST(44870.891645076015 / 8.0), + REAL_CONST(44890.298420807922 / 8.0), + REAL_CONST(44909.707294229491 / 8.0), + REAL_CONST(44929.118264887409 / 8.0), + REAL_CONST(44948.531332328566 / 8.0), + REAL_CONST(44967.946496100136 / 8.0), + REAL_CONST(44987.363755749502 / 8.0), + REAL_CONST(45006.783110824319 / 8.0), + REAL_CONST(45026.204560872473 / 8.0), + REAL_CONST(45045.628105442098 / 8.0), + REAL_CONST(45065.053744081561 / 8.0), + REAL_CONST(45084.48147633949 / 8.0), + REAL_CONST(45103.911301764747 / 8.0), + REAL_CONST(45123.343219906426 / 8.0), + REAL_CONST(45142.777230313885 / 8.0), + REAL_CONST(45162.21333253671 / 8.0), + REAL_CONST(45181.651526124733 / 8.0), + REAL_CONST(45201.091810628037 / 8.0), + REAL_CONST(45220.534185596924 / 8.0), + REAL_CONST(45239.978650581965 / 8.0), + REAL_CONST(45259.425205133957 / 8.0), + REAL_CONST(45278.873848803938 / 8.0), + REAL_CONST(45298.324581143192 / 8.0), + REAL_CONST(45317.777401703235 / 8.0), + REAL_CONST(45337.232310035848 / 8.0), + REAL_CONST(45356.68930569302 / 8.0), + REAL_CONST(45376.148388226997 / 8.0), + REAL_CONST(45395.60955719027 / 8.0), + REAL_CONST(45415.072812135557 / 8.0), + REAL_CONST(45434.538152615823 / 8.0), + REAL_CONST(45454.005578184282 / 8.0), + REAL_CONST(45473.475088394356 / 8.0), + REAL_CONST(45492.946682799746 / 8.0), + REAL_CONST(45512.420360954362 / 8.0), + REAL_CONST(45531.896122412363 / 8.0), + REAL_CONST(45551.373966728155 / 8.0), + REAL_CONST(45570.853893456362 / 8.0), + REAL_CONST(45590.33590215187 / 8.0), + REAL_CONST(45609.819992369776 / 8.0), + REAL_CONST(45629.306163665438 / 8.0), + REAL_CONST(45648.794415594442 / 8.0), + REAL_CONST(45668.284747712612 / 8.0), + REAL_CONST(45687.777159576006 / 8.0), + REAL_CONST(45707.27165074092 / 8.0), + REAL_CONST(45726.768220763894 / 8.0), + REAL_CONST(45746.266869201696 / 8.0), + REAL_CONST(45765.767595611323 / 8.0), + REAL_CONST(45785.270399550034 / 8.0), + REAL_CONST(45804.775280575297 / 8.0), + REAL_CONST(45824.282238244828 / 8.0), + REAL_CONST(45843.79127211657 / 8.0), + REAL_CONST(45863.302381748719 / 8.0), + REAL_CONST(45882.815566699683 / 8.0), + REAL_CONST(45902.33082652813 / 8.0), + REAL_CONST(45921.848160792935 / 8.0), + REAL_CONST(45941.367569053225 / 8.0), + REAL_CONST(45960.889050868354 / 8.0), + REAL_CONST(45980.41260579793 / 8.0), + REAL_CONST(45999.938233401757 / 8.0), + REAL_CONST(46019.465933239902 / 8.0), + REAL_CONST(46038.995704872657 / 8.0), + REAL_CONST(46058.527547860547 / 8.0), + REAL_CONST(46078.06146176433 / 8.0), + REAL_CONST(46097.597446144995 / 8.0), + REAL_CONST(46117.135500563774 / 8.0), + REAL_CONST(46136.675624582109 / 8.0), + REAL_CONST(46156.217817761702 / 8.0), + REAL_CONST(46175.762079664462 / 8.0), + REAL_CONST(46195.308409852543 / 8.0), + REAL_CONST(46214.856807888333 / 8.0), + REAL_CONST(46234.407273334444 / 8.0), + REAL_CONST(46253.959805753715 / 8.0), + REAL_CONST(46273.51440470924 / 8.0), + REAL_CONST(46293.071069764315 / 8.0), + REAL_CONST(46312.629800482478 / 8.0), + REAL_CONST(46332.190596427499 / 8.0), + REAL_CONST(46351.753457163381 / 8.0), + REAL_CONST(46371.318382254351 / 8.0), + REAL_CONST(46390.885371264863 / 8.0), + REAL_CONST(46410.45442375962 / 8.0), + REAL_CONST(46430.025539303526 / 8.0), + REAL_CONST(46449.598717461733 / 8.0), + REAL_CONST(46469.17395779962 / 8.0), + REAL_CONST(46488.751259882782 / 8.0), + REAL_CONST(46508.33062327707 / 8.0), + REAL_CONST(46527.912047548532 / 8.0), + REAL_CONST(46547.495532263471 / 8.0), + REAL_CONST(46567.081076988397 / 8.0), + REAL_CONST(46586.668681290059 / 8.0), + REAL_CONST(46606.258344735434 / 8.0), + REAL_CONST(46625.850066891719 / 8.0), + REAL_CONST(46645.443847326351 / 8.0), + REAL_CONST(46665.039685606986 / 8.0), + REAL_CONST(46684.637581301497 / 8.0), + REAL_CONST(46704.237533978005 / 8.0), + REAL_CONST(46723.839543204842 / 8.0), + REAL_CONST(46743.443608550573 / 8.0), + REAL_CONST(46763.049729583989 / 8.0), + REAL_CONST(46782.657905874104 / 8.0), + REAL_CONST(46802.268136990162 / 8.0), + REAL_CONST(46821.880422501628 / 8.0), + REAL_CONST(46841.494761978196 / 8.0), + REAL_CONST(46861.111154989776 / 8.0), + REAL_CONST(46880.729601106526 / 8.0), + REAL_CONST(46900.350099898795 / 8.0), + REAL_CONST(46919.97265093719 / 8.0), + REAL_CONST(46939.597253792526 / 8.0), + REAL_CONST(46959.223908035841 / 8.0), + REAL_CONST(46978.852613238392 / 8.0), + REAL_CONST(46998.483368971691 / 8.0), + REAL_CONST(47018.11617480743 / 8.0), + REAL_CONST(47037.751030317551 / 8.0), + REAL_CONST(47057.387935074221 / 8.0), + REAL_CONST(47077.026888649809 / 8.0), + REAL_CONST(47096.66789061694 / 8.0), + REAL_CONST(47116.310940548428 / 8.0), + REAL_CONST(47135.956038017328 / 8.0), + REAL_CONST(47155.603182596918 / 8.0), + REAL_CONST(47175.252373860698 / 8.0), + REAL_CONST(47194.903611382375 / 8.0), + REAL_CONST(47214.556894735892 / 8.0), + REAL_CONST(47234.212223495422 / 8.0), + REAL_CONST(47253.869597235338 / 8.0), + REAL_CONST(47273.52901553025 / 8.0), + REAL_CONST(47293.19047795498 / 8.0), + REAL_CONST(47312.853984084577 / 8.0), + REAL_CONST(47332.519533494306 / 8.0), + REAL_CONST(47352.187125759658 / 8.0), + REAL_CONST(47371.856760456343 / 8.0), + REAL_CONST(47391.528437160297 / 8.0), + REAL_CONST(47411.202155447652 / 8.0), + REAL_CONST(47430.877914894787 / 8.0), + REAL_CONST(47450.555715078299 / 8.0), + REAL_CONST(47470.235555574982 / 8.0), + REAL_CONST(47489.917435961863 / 8.0), + REAL_CONST(47509.601355816201 / 8.0), + REAL_CONST(47529.287314715453 / 8.0), + REAL_CONST(47548.975312237308 / 8.0), + REAL_CONST(47568.665347959672 / 8.0), + REAL_CONST(47588.357421460656 / 8.0), + REAL_CONST(47608.051532318605 / 8.0), + REAL_CONST(47627.747680112072 / 8.0), + REAL_CONST(47647.445864419846 / 8.0), + REAL_CONST(47667.14608482091 / 8.0), + REAL_CONST(47686.848340894474 / 8.0), + REAL_CONST(47706.552632219973 / 8.0), + REAL_CONST(47726.258958377046 / 8.0), + REAL_CONST(47745.967318945557 / 8.0), + REAL_CONST(47765.677713505589 / 8.0), + REAL_CONST(47785.390141637428 / 8.0), + REAL_CONST(47805.104602921601 / 8.0), + REAL_CONST(47824.821096938824 / 8.0), + REAL_CONST(47844.539623270044 / 8.0), + REAL_CONST(47864.260181496429 / 8.0), + REAL_CONST(47883.982771199349 / 8.0), + REAL_CONST(47903.707391960394 / 8.0), + REAL_CONST(47923.434043361369 / 8.0), + REAL_CONST(47943.162724984308 / 8.0), + REAL_CONST(47962.893436411439 / 8.0), + REAL_CONST(47982.626177225218 / 8.0), + REAL_CONST(48002.36094700831 / 8.0), + REAL_CONST(48022.097745343599 / 8.0), + REAL_CONST(48041.836571814172 / 8.0), + REAL_CONST(48061.57742600335 / 8.0), + REAL_CONST(48081.32030749465 / 8.0), + REAL_CONST(48101.065215871815 / 8.0), + REAL_CONST(48120.81215071879 / 8.0), + REAL_CONST(48140.56111161974 / 8.0), + REAL_CONST(48160.312098159047 / 8.0), + REAL_CONST(48180.065109921306 / 8.0), + REAL_CONST(48199.820146491307 / 8.0), + REAL_CONST(48219.577207454073 / 8.0), + REAL_CONST(48239.336292394844 / 8.0), + REAL_CONST(48259.097400899045 / 8.0), + REAL_CONST(48278.860532552339 / 8.0), + REAL_CONST(48298.625686940592 / 8.0), + REAL_CONST(48318.392863649875 / 8.0), + REAL_CONST(48338.162062266485 / 8.0), + REAL_CONST(48357.933282376915 / 8.0), + REAL_CONST(48377.706523567889 / 8.0), + REAL_CONST(48397.481785426316 / 8.0), + REAL_CONST(48417.259067539344 / 8.0), + REAL_CONST(48437.038369494308 / 8.0), + REAL_CONST(48456.819690878765 / 8.0), + REAL_CONST(48476.603031280487 / 8.0), + REAL_CONST(48496.388390287451 / 8.0), + REAL_CONST(48516.175767487839 / 8.0), + REAL_CONST(48535.965162470042 / 8.0), + REAL_CONST(48555.756574822684 / 8.0), + REAL_CONST(48575.550004134566 / 8.0), + REAL_CONST(48595.345449994718 / 8.0), + REAL_CONST(48615.142911992378 / 8.0), + REAL_CONST(48634.942389716991 / 8.0), + REAL_CONST(48654.743882758201 / 8.0), + REAL_CONST(48674.547390705877 / 8.0), + REAL_CONST(48694.352913150084 / 8.0), + REAL_CONST(48714.160449681112 / 8.0), + REAL_CONST(48733.969999889443 / 8.0), + REAL_CONST(48753.781563365759 / 8.0), + REAL_CONST(48773.595139700978 / 8.0), + REAL_CONST(48793.410728486211 / 8.0), + REAL_CONST(48813.228329312769 / 8.0), + REAL_CONST(48833.047941772187 / 8.0), + REAL_CONST(48852.869565456189 / 8.0), + REAL_CONST(48872.693199956717 / 8.0), + REAL_CONST(48892.518844865925 / 8.0), + REAL_CONST(48912.346499776155 / 8.0), + REAL_CONST(48932.176164279976 / 8.0), + REAL_CONST(48952.007837970152 / 8.0), + REAL_CONST(48971.841520439666 / 8.0), + REAL_CONST(48991.677211281676 / 8.0), + REAL_CONST(49011.514910089587 / 8.0), + REAL_CONST(49031.354616456978 / 8.0), + REAL_CONST(49051.196329977654 / 8.0), + REAL_CONST(49071.04005024561 / 8.0), + REAL_CONST(49090.885776855059 / 8.0), + REAL_CONST(49110.733509400408 / 8.0), + REAL_CONST(49130.583247476279 / 8.0), + REAL_CONST(49150.434990677488 / 8.0), + REAL_CONST(49170.288738599062 / 8.0), + REAL_CONST(49190.144490836232 / 8.0), + REAL_CONST(49210.002246984441 / 8.0), + REAL_CONST(49229.86200663932 / 8.0), + REAL_CONST(49249.723769396718 / 8.0), + REAL_CONST(49269.587534852675 / 8.0), + REAL_CONST(49289.453302603448 / 8.0), + REAL_CONST(49309.32107224549 / 8.0), + REAL_CONST(49329.190843375451 / 8.0), + REAL_CONST(49349.062615590192 / 8.0), + REAL_CONST(49368.936388486785 / 8.0), + REAL_CONST(49388.812161662492 / 8.0), + REAL_CONST(49408.689934714785 / 8.0), + REAL_CONST(49428.569707241324 / 8.0), + REAL_CONST(49448.45147883999 / 8.0), + REAL_CONST(49468.335249108866 / 8.0), + REAL_CONST(49488.22101764621 / 8.0), + REAL_CONST(49508.108784050521 / 8.0), + REAL_CONST(49527.99854792047 / 8.0), + REAL_CONST(49547.890308854934 / 8.0), + REAL_CONST(49567.784066453009 / 8.0), + REAL_CONST(49587.679820313977 / 8.0), + REAL_CONST(49607.57757003732 / 8.0), + REAL_CONST(49627.477315222721 / 8.0), + REAL_CONST(49647.379055470075 / 8.0), + REAL_CONST(49667.28279037946 / 8.0), + REAL_CONST(49687.188519551179 / 8.0), + REAL_CONST(49707.096242585707 / 8.0), + REAL_CONST(49727.005959083741 / 8.0), + REAL_CONST(49746.917668646165 / 8.0), + REAL_CONST(49766.831370874068 / 8.0), + REAL_CONST(49786.747065368734 / 8.0), + REAL_CONST(49806.66475173166 / 8.0), + REAL_CONST(49826.584429564515 / 8.0), + REAL_CONST(49846.506098469203 / 8.0), + REAL_CONST(49866.429758047794 / 8.0), + REAL_CONST(49886.355407902578 / 8.0), + REAL_CONST(49906.283047636032 / 8.0), + REAL_CONST(49926.212676850846 / 8.0), + REAL_CONST(49946.144295149883 / 8.0), + REAL_CONST(49966.077902136225 / 8.0), + REAL_CONST(49986.013497413151 / 8.0), + REAL_CONST(50005.951080584135 / 8.0), + REAL_CONST(50025.890651252834 / 8.0), + REAL_CONST(50045.832209023123 / 8.0), + REAL_CONST(50065.775753499074 / 8.0), + REAL_CONST(50085.721284284933 / 8.0), + REAL_CONST(50105.668800985164 / 8.0), + REAL_CONST(50125.618303204428 / 8.0), + REAL_CONST(50145.569790547575 / 8.0), + REAL_CONST(50165.523262619652 / 8.0), + REAL_CONST(50185.478719025901 / 8.0), + REAL_CONST(50205.436159371769 / 8.0), + REAL_CONST(50225.395583262893 / 8.0), + REAL_CONST(50245.356990305103 / 8.0), + REAL_CONST(50265.320380104429 / 8.0), + REAL_CONST(50285.285752267104 / 8.0), + REAL_CONST(50305.253106399534 / 8.0), + REAL_CONST(50325.222442108337 / 8.0), + REAL_CONST(50345.193759000336 / 8.0), + REAL_CONST(50365.16705668252 / 8.0), + REAL_CONST(50385.142334762102 / 8.0), + REAL_CONST(50405.119592846473 / 8.0), + REAL_CONST(50425.098830543218 / 8.0), + REAL_CONST(50445.080047460127 / 8.0), + REAL_CONST(50465.063243205179 / 8.0), + REAL_CONST(50485.048417386541 / 8.0), + REAL_CONST(50505.035569612577 / 8.0), + REAL_CONST(50525.024699491856 / 8.0), + REAL_CONST(50545.015806633128 / 8.0), + REAL_CONST(50565.008890645338 / 8.0), + REAL_CONST(50585.003951137631 / 8.0), + REAL_CONST(50605.00098771933 / 8.0), + REAL_CONST(50624.999999999971 / 8.0), + REAL_CONST(50645.000987589265 / 8.0), + REAL_CONST(50665.003950097132 / 8.0), + REAL_CONST(50685.008887133677 / 8.0), + REAL_CONST(50705.015798309192 / 8.0), + REAL_CONST(50725.024683234165 / 8.0), + REAL_CONST(50745.035541519283 / 8.0), + REAL_CONST(50765.048372775411 / 8.0), + REAL_CONST(50785.063176613621 / 8.0), + REAL_CONST(50805.079952645159 / 8.0), + REAL_CONST(50825.098700481489 / 8.0), + REAL_CONST(50845.119419734241 / 8.0), + REAL_CONST(50865.142110015244 / 8.0), + REAL_CONST(50885.166770936521 / 8.0), + REAL_CONST(50905.193402110279 / 8.0), + REAL_CONST(50925.222003148934 / 8.0), + REAL_CONST(50945.252573665071 / 8.0), + REAL_CONST(50965.285113271471 / 8.0), + REAL_CONST(50985.319621581119 / 8.0), + REAL_CONST(51005.356098207172 / 8.0), + REAL_CONST(51025.394542762981 / 8.0), + REAL_CONST(51045.434954862096 / 8.0), + REAL_CONST(51065.477334118244 / 8.0), + REAL_CONST(51085.521680145357 / 8.0), + REAL_CONST(51105.567992557546 / 8.0), + REAL_CONST(51125.616270969113 / 8.0), + REAL_CONST(51145.66651499454 / 8.0), + REAL_CONST(51165.718724248516 / 8.0), + REAL_CONST(51185.772898345916 / 8.0), + REAL_CONST(51205.829036901778 / 8.0), + REAL_CONST(51225.887139531362 / 8.0), + REAL_CONST(51245.947205850105 / 8.0), + REAL_CONST(51266.009235473619 / 8.0), + REAL_CONST(51286.073228017718 / 8.0), + REAL_CONST(51306.139183098399 / 8.0), + REAL_CONST(51326.207100331856 / 8.0), + REAL_CONST(51346.276979334456 / 8.0), + REAL_CONST(51366.348819722756 / 8.0), + REAL_CONST(51386.42262111351 / 8.0), + REAL_CONST(51406.498383123653 / 8.0), + REAL_CONST(51426.57610537031 / 8.0), + REAL_CONST(51446.655787470787 / 8.0), + REAL_CONST(51466.737429042587 / 8.0), + REAL_CONST(51486.82102970338 / 8.0), + REAL_CONST(51506.906589071048 / 8.0), + REAL_CONST(51526.994106763632 / 8.0), + REAL_CONST(51547.083582399391 / 8.0), + REAL_CONST(51567.175015596738 / 8.0), + REAL_CONST(51587.268405974297 / 8.0), + REAL_CONST(51607.363753150858 / 8.0), + REAL_CONST(51627.461056745415 / 8.0), + REAL_CONST(51647.56031637713 / 8.0), + REAL_CONST(51667.661531665362 / 8.0), + REAL_CONST(51687.764702229651 / 8.0), + REAL_CONST(51707.869827689727 / 8.0), + REAL_CONST(51727.976907665499 / 8.0), + REAL_CONST(51748.085941777055 / 8.0), + REAL_CONST(51768.196929644677 / 8.0), + REAL_CONST(51788.309870888836 / 8.0), + REAL_CONST(51808.42476513017 / 8.0), + REAL_CONST(51828.541611989524 / 8.0), + REAL_CONST(51848.660411087905 / 8.0), + REAL_CONST(51868.781162046515 / 8.0), + REAL_CONST(51888.90386448674 / 8.0), + REAL_CONST(51909.028518030143 / 8.0), + REAL_CONST(51929.155122298485 / 8.0), + REAL_CONST(51949.283676913685 / 8.0), + REAL_CONST(51969.414181497872 / 8.0), + REAL_CONST(51989.546635673345 / 8.0), + REAL_CONST(52009.681039062583 / 8.0), + REAL_CONST(52029.817391288263 / 8.0), + REAL_CONST(52049.955691973213 / 8.0), + REAL_CONST(52070.095940740481 / 8.0), + REAL_CONST(52090.238137213273 / 8.0), + REAL_CONST(52110.382281014987 / 8.0), + REAL_CONST(52130.5283717692 / 8.0), + REAL_CONST(52150.676409099666 / 8.0), + REAL_CONST(52170.826392630333 / 8.0), + REAL_CONST(52190.97832198532 / 8.0), + REAL_CONST(52211.132196788931 / 8.0), + REAL_CONST(52231.288016665654 / 8.0), + REAL_CONST(52251.445781240145 / 8.0), + REAL_CONST(52271.60549013727 / 8.0), + REAL_CONST(52291.76714298204 / 8.0), + REAL_CONST(52311.930739399664 / 8.0), + REAL_CONST(52332.096279015546 / 8.0), + REAL_CONST(52352.263761455244 / 8.0), + REAL_CONST(52372.433186344519 / 8.0), + REAL_CONST(52392.604553309284 / 8.0), + REAL_CONST(52412.777861975665 / 8.0), + REAL_CONST(52432.953111969946 / 8.0), + REAL_CONST(52453.130302918595 / 8.0), + REAL_CONST(52473.309434448267 / 8.0), + REAL_CONST(52493.490506185793 / 8.0), + REAL_CONST(52513.67351775818 / 8.0), + REAL_CONST(52533.858468792605 / 8.0), + REAL_CONST(52554.045358916446 / 8.0), + REAL_CONST(52574.234187757254 / 8.0), + REAL_CONST(52594.42495494274 / 8.0), + REAL_CONST(52614.617660100812 / 8.0), + REAL_CONST(52634.812302859558 / 8.0), + REAL_CONST(52655.008882847229 / 8.0), + REAL_CONST(52675.20739969227 / 8.0), + REAL_CONST(52695.407853023295 / 8.0), + REAL_CONST(52715.610242469098 / 8.0), + REAL_CONST(52735.814567658657 / 8.0), + REAL_CONST(52756.02082822111 / 8.0), + REAL_CONST(52776.229023785803 / 8.0), + REAL_CONST(52796.439153982225 / 8.0), + REAL_CONST(52816.651218440056 / 8.0), + REAL_CONST(52836.865216789171 / 8.0), + REAL_CONST(52857.081148659599 / 8.0), + REAL_CONST(52877.29901368155 / 8.0), + REAL_CONST(52897.518811485425 / 8.0), + REAL_CONST(52917.740541701773 / 8.0), + REAL_CONST(52937.964203961354 / 8.0), + REAL_CONST(52958.18979789508 / 8.0), + REAL_CONST(52978.417323134046 / 8.0), + REAL_CONST(52998.646779309529 / 8.0), + REAL_CONST(53018.878166052978 / 8.0), + REAL_CONST(53039.111482996006 / 8.0), + REAL_CONST(53059.346729770419 / 8.0), + REAL_CONST(53079.583906008193 / 8.0), + REAL_CONST(53099.823011341483 / 8.0), + REAL_CONST(53120.0640454026 / 8.0), + REAL_CONST(53140.307007824063 / 8.0), + REAL_CONST(53160.551898238533 / 8.0), + REAL_CONST(53180.79871627887 / 8.0), + REAL_CONST(53201.047461578091 / 8.0), + REAL_CONST(53221.2981337694 / 8.0), + REAL_CONST(53241.550732486176 / 8.0), + REAL_CONST(53261.805257361964 / 8.0), + REAL_CONST(53282.061708030487 / 8.0), + REAL_CONST(53302.32008412564 / 8.0), + REAL_CONST(53322.580385281493 / 8.0), + REAL_CONST(53342.842611132299 / 8.0), + REAL_CONST(53363.106761312469 / 8.0), + REAL_CONST(53383.372835456597 / 8.0), + REAL_CONST(53403.640833199453 / 8.0), + REAL_CONST(53423.910754175973 / 8.0), + REAL_CONST(53444.18259802126 / 8.0), + REAL_CONST(53464.456364370613 / 8.0), + REAL_CONST(53484.732052859479 / 8.0), + REAL_CONST(53505.009663123499 / 8.0), + REAL_CONST(53525.289194798468 / 8.0), + REAL_CONST(53545.570647520362 / 8.0), + REAL_CONST(53565.854020925333 / 8.0), + REAL_CONST(53586.139314649699 / 8.0), + REAL_CONST(53606.426528329954 / 8.0), + REAL_CONST(53626.715661602764 / 8.0), + REAL_CONST(53647.006714104959 / 8.0), + REAL_CONST(53667.299685473547 / 8.0), + REAL_CONST(53687.59457534572 / 8.0), + REAL_CONST(53707.891383358816 / 8.0), + REAL_CONST(53728.190109150361 / 8.0), + REAL_CONST(53748.490752358055 / 8.0), + REAL_CONST(53768.793312619753 / 8.0), + REAL_CONST(53789.09778957349 / 8.0), + REAL_CONST(53809.404182857485 / 8.0), + REAL_CONST(53829.712492110106 / 8.0), + REAL_CONST(53850.022716969899 / 8.0), + REAL_CONST(53870.334857075584 / 8.0), + REAL_CONST(53890.648912066055 / 8.0), + REAL_CONST(53910.964881580367 / 8.0), + REAL_CONST(53931.28276525774 / 8.0), + REAL_CONST(53951.602562737586 / 8.0), + REAL_CONST(53971.924273659461 / 8.0), + REAL_CONST(53992.24789766311 / 8.0), + REAL_CONST(54012.57343438844 / 8.0), + REAL_CONST(54032.90088347553 / 8.0), + REAL_CONST(54053.23024456462 / 8.0), + REAL_CONST(54073.561517296133 / 8.0), + REAL_CONST(54093.894701310644 / 8.0), + REAL_CONST(54114.22979624891 / 8.0), + REAL_CONST(54134.566801751855 / 8.0), + REAL_CONST(54154.90571746057 / 8.0), + REAL_CONST(54175.246543016314 / 8.0), + REAL_CONST(54195.589278060506 / 8.0), + REAL_CONST(54215.933922234755 / 8.0), + REAL_CONST(54236.280475180814 / 8.0), + REAL_CONST(54256.628936540626 / 8.0), + REAL_CONST(54276.97930595628 / 8.0), + REAL_CONST(54297.331583070045 / 8.0), + REAL_CONST(54317.685767524359 / 8.0), + REAL_CONST(54338.041858961828 / 8.0), + REAL_CONST(54358.399857025215 / 8.0), + REAL_CONST(54378.759761357462 / 8.0), + REAL_CONST(54399.121571601667 / 8.0), + REAL_CONST(54419.485287401105 / 8.0), + REAL_CONST(54439.850908399218 / 8.0), + REAL_CONST(54460.218434239614 / 8.0), + REAL_CONST(54480.587864566056 / 8.0), + REAL_CONST(54500.95919902248 / 8.0), + REAL_CONST(54521.332437252997 / 8.0), + REAL_CONST(54541.707578901878 / 8.0), + REAL_CONST(54562.084623613555 / 8.0), + REAL_CONST(54582.46357103264 / 8.0), + REAL_CONST(54602.844420803893 / 8.0), + REAL_CONST(54623.227172572246 / 8.0), + REAL_CONST(54643.611825982807 / 8.0), + REAL_CONST(54663.998380680838 / 8.0), + REAL_CONST(54684.386836311773 / 8.0), + REAL_CONST(54704.777192521207 / 8.0), + REAL_CONST(54725.169448954897 / 8.0), + REAL_CONST(54745.563605258772 / 8.0), + REAL_CONST(54765.959661078923 / 8.0), + REAL_CONST(54786.357616061614 / 8.0), + REAL_CONST(54806.757469853255 / 8.0), + REAL_CONST(54827.159222100439 / 8.0), + REAL_CONST(54847.562872449904 / 8.0), + REAL_CONST(54867.968420548583 / 8.0), + REAL_CONST(54888.375866043534 / 8.0), + REAL_CONST(54908.785208582012 / 8.0), + REAL_CONST(54929.196447811417 / 8.0), + REAL_CONST(54949.609583379322 / 8.0), + REAL_CONST(54970.024614933463 / 8.0), + REAL_CONST(54990.441542121727 / 8.0), + REAL_CONST(55010.86036459219 / 8.0), + REAL_CONST(55031.28108199306 / 8.0), + REAL_CONST(55051.703693972733 / 8.0), + REAL_CONST(55072.128200179759 / 8.0), + REAL_CONST(55092.554600262847 / 8.0), + REAL_CONST(55112.982893870874 / 8.0), + REAL_CONST(55133.413080652877 / 8.0), + REAL_CONST(55153.845160258061 / 8.0), + REAL_CONST(55174.279132335789 / 8.0), + REAL_CONST(55194.714996535586 / 8.0), + REAL_CONST(55215.152752507143 / 8.0), + REAL_CONST(55235.592399900306 / 8.0), + REAL_CONST(55256.033938365079 / 8.0), + REAL_CONST(55276.477367551655 / 8.0), + REAL_CONST(55296.92268711036 / 8.0), + REAL_CONST(55317.369896691685 / 8.0), + REAL_CONST(55337.818995946305 / 8.0), + REAL_CONST(55358.269984525024 / 8.0), + REAL_CONST(55378.72286207883 / 8.0), + REAL_CONST(55399.177628258869 / 8.0), + REAL_CONST(55419.634282716441 / 8.0), + REAL_CONST(55440.092825103013 / 8.0), + REAL_CONST(55460.553255070205 / 8.0), + REAL_CONST(55481.015572269804 / 8.0), + REAL_CONST(55501.479776353764 / 8.0), + REAL_CONST(55521.945866974187 / 8.0), + REAL_CONST(55542.413843783339 / 8.0), + REAL_CONST(55562.883706433655 / 8.0), + REAL_CONST(55583.355454577715 / 8.0), + REAL_CONST(55603.82908786826 / 8.0), + REAL_CONST(55624.304605958219 / 8.0), + REAL_CONST(55644.782008500639 / 8.0), + REAL_CONST(55665.261295148754 / 8.0), + REAL_CONST(55685.742465555952 / 8.0), + REAL_CONST(55706.225519375774 / 8.0), + REAL_CONST(55726.710456261928 / 8.0), + REAL_CONST(55747.197275868275 / 8.0), + REAL_CONST(55767.685977848843 / 8.0), + REAL_CONST(55788.176561857814 / 8.0), + REAL_CONST(55808.669027549528 / 8.0), + REAL_CONST(55829.163374578478 / 8.0), + REAL_CONST(55849.659602599328 / 8.0), + REAL_CONST(55870.157711266889 / 8.0), + REAL_CONST(55890.657700236145 / 8.0), + REAL_CONST(55911.159569162221 / 8.0), + REAL_CONST(55931.663317700411 / 8.0), + REAL_CONST(55952.168945506164 / 8.0), + REAL_CONST(55972.676452235086 / 8.0), + REAL_CONST(55993.185837542944 / 8.0), + REAL_CONST(56013.697101085651 / 8.0), + REAL_CONST(56034.210242519301 / 8.0), + REAL_CONST(56054.72526150012 / 8.0), + REAL_CONST(56075.242157684508 / 8.0), + REAL_CONST(56095.760930729011 / 8.0), + REAL_CONST(56116.281580290342 / 8.0), + REAL_CONST(56136.804106025367 / 8.0), + REAL_CONST(56157.328507591104 / 8.0), + REAL_CONST(56177.85478464474 / 8.0), + REAL_CONST(56198.382936843598 / 8.0), + REAL_CONST(56218.912963845185 / 8.0), + REAL_CONST(56239.444865307138 / 8.0), + REAL_CONST(56259.978640887268 / 8.0), + REAL_CONST(56280.514290243525 / 8.0), + REAL_CONST(56301.051813034042 / 8.0), + REAL_CONST(56321.591208917082 / 8.0), + REAL_CONST(56342.13247755108 / 8.0), + REAL_CONST(56362.675618594607 / 8.0), + REAL_CONST(56383.220631706419 / 8.0), + REAL_CONST(56403.767516545398 / 8.0), + REAL_CONST(56424.316272770608 / 8.0), + REAL_CONST(56444.866900041241 / 8.0), + REAL_CONST(56465.419398016667 / 8.0), + REAL_CONST(56485.973766356394 / 8.0), + REAL_CONST(56506.530004720102 / 8.0), + REAL_CONST(56527.088112767611 / 8.0), + REAL_CONST(56547.648090158902 / 8.0), + REAL_CONST(56568.209936554107 / 8.0), + REAL_CONST(56588.773651613519 / 8.0), + REAL_CONST(56609.339234997584 / 8.0), + REAL_CONST(56629.9066863669 / 8.0), + REAL_CONST(56650.47600538221 / 8.0), + REAL_CONST(56671.04719170442 / 8.0), + REAL_CONST(56691.620244994599 / 8.0), + REAL_CONST(56712.195164913959 / 8.0), + REAL_CONST(56732.771951123868 / 8.0), + REAL_CONST(56753.350603285835 / 8.0), + REAL_CONST(56773.931121061541 / 8.0), + REAL_CONST(56794.513504112823 / 8.0), + REAL_CONST(56815.097752101647 / 8.0), + REAL_CONST(56835.683864690152 / 8.0), + REAL_CONST(56856.271841540627 / 8.0), + REAL_CONST(56876.86168231551 / 8.0), + REAL_CONST(56897.453386677393 / 8.0), + REAL_CONST(56918.046954289028 / 8.0), + REAL_CONST(56938.642384813298 / 8.0), + REAL_CONST(56959.239677913261 / 8.0), + REAL_CONST(56979.838833252121 / 8.0), + REAL_CONST(57000.439850493225 / 8.0), + REAL_CONST(57021.04272930009 / 8.0), + REAL_CONST(57041.647469336371 / 8.0), + REAL_CONST(57062.254070265873 / 8.0), + REAL_CONST(57082.862531752558 / 8.0), + REAL_CONST(57103.472853460553 / 8.0), + REAL_CONST(57124.085035054108 / 8.0), + REAL_CONST(57144.699076197649 / 8.0), + REAL_CONST(57165.314976555739 / 8.0), + REAL_CONST(57185.932735793103 / 8.0), + REAL_CONST(57206.552353574611 / 8.0), + REAL_CONST(57227.173829565276 / 8.0), + REAL_CONST(57247.797163430281 / 8.0), + REAL_CONST(57268.42235483494 / 8.0), + REAL_CONST(57289.049403444733 / 8.0), + REAL_CONST(57309.678308925286 / 8.0), + REAL_CONST(57330.30907094237 / 8.0), + REAL_CONST(57350.941689161911 / 8.0), + REAL_CONST(57371.576163249985 / 8.0), + REAL_CONST(57392.212492872815 / 8.0), + REAL_CONST(57412.850677696784 / 8.0), + REAL_CONST(57433.490717388406 / 8.0), + REAL_CONST(57454.132611614368 / 8.0), + REAL_CONST(57474.776360041491 / 8.0), + REAL_CONST(57495.421962336746 / 8.0), + REAL_CONST(57516.069418167266 / 8.0), + REAL_CONST(57536.718727200314 / 8.0), + REAL_CONST(57557.36988910332 / 8.0), + REAL_CONST(57578.022903543861 / 8.0), + REAL_CONST(57598.677770189643 / 8.0), + REAL_CONST(57619.334488708548 / 8.0), + REAL_CONST(57639.993058768589 / 8.0), + REAL_CONST(57660.653480037938 / 8.0), + REAL_CONST(57681.315752184906 / 8.0), + REAL_CONST(57701.979874877965 / 8.0), + REAL_CONST(57722.64584778573 / 8.0), + REAL_CONST(57743.31367057695 / 8.0), + REAL_CONST(57763.983342920546 / 8.0), + REAL_CONST(57784.654864485572 / 8.0), + REAL_CONST(57805.328234941233 / 8.0), + REAL_CONST(57826.003453956881 / 8.0), + REAL_CONST(57846.680521202026 / 8.0), + REAL_CONST(57867.359436346305 / 8.0), + REAL_CONST(57888.040199059527 / 8.0), + REAL_CONST(57908.722809011633 / 8.0), + REAL_CONST(57929.407265872709 / 8.0), + REAL_CONST(57950.093569313001 / 8.0), + REAL_CONST(57970.781719002895 / 8.0), + REAL_CONST(57991.471714612911 / 8.0), + REAL_CONST(58012.16355581375 / 8.0), + REAL_CONST(58032.857242276223 / 8.0), + REAL_CONST(58053.552773671312 / 8.0), + REAL_CONST(58074.25014967013 / 8.0), + REAL_CONST(58094.949369943948 / 8.0), + REAL_CONST(58115.650434164185 / 8.0), + REAL_CONST(58136.353342002389 / 8.0), + REAL_CONST(58157.058093130276 / 8.0), + REAL_CONST(58177.764687219693 / 8.0), + REAL_CONST(58198.47312394264 / 8.0), + REAL_CONST(58219.183402971255 / 8.0), + REAL_CONST(58239.895523977837 / 8.0), + REAL_CONST(58260.609486634821 / 8.0), + REAL_CONST(58281.325290614775 / 8.0), + REAL_CONST(58302.042935590434 / 8.0), + REAL_CONST(58322.762421234678 / 8.0), + REAL_CONST(58343.483747220511 / 8.0), + REAL_CONST(58364.206913221096 / 8.0), + REAL_CONST(58384.931918909751 / 8.0), + REAL_CONST(58405.658763959924 / 8.0), + REAL_CONST(58426.3874480452 / 8.0), + REAL_CONST(58447.117970839339 / 8.0), + REAL_CONST(58467.85033201622 / 8.0), + REAL_CONST(58488.584531249864 / 8.0), + REAL_CONST(58509.320568214462 / 8.0), + REAL_CONST(58530.058442584334 / 8.0), + REAL_CONST(58550.798154033931 / 8.0), + REAL_CONST(58571.539702237875 / 8.0), + REAL_CONST(58592.283086870906 / 8.0), + REAL_CONST(58613.028307607929 / 8.0), + REAL_CONST(58633.775364123983 / 8.0), + REAL_CONST(58654.52425609425 / 8.0), + REAL_CONST(58675.274983194053 / 8.0), + REAL_CONST(58696.027545098877 / 8.0), + REAL_CONST(58716.781941484325 / 8.0), + REAL_CONST(58737.538172026158 / 8.0), + REAL_CONST(58758.296236400274 / 8.0), + REAL_CONST(58779.056134282728 / 8.0), + REAL_CONST(58799.817865349694 / 8.0), + REAL_CONST(58820.581429277503 / 8.0), + REAL_CONST(58841.346825742643 / 8.0), + REAL_CONST(58862.114054421712 / 8.0), + REAL_CONST(58882.883114991484 / 8.0), + REAL_CONST(58903.654007128847 / 8.0), + REAL_CONST(58924.426730510851 / 8.0), + REAL_CONST(58945.201284814684 / 8.0), + REAL_CONST(58965.977669717664 / 8.0), + REAL_CONST(58986.755884897269 / 8.0), + REAL_CONST(59007.535930031117 / 8.0), + REAL_CONST(59028.317804796949 / 8.0), + REAL_CONST(59049.101508872664 / 8.0), + REAL_CONST(59069.887041936301 / 8.0), + REAL_CONST(59090.674403666046 / 8.0), + REAL_CONST(59111.463593740213 / 8.0), + REAL_CONST(59132.254611837263 / 8.0), + REAL_CONST(59153.047457635803 / 8.0), + REAL_CONST(59173.84213081457 / 8.0), + REAL_CONST(59194.638631052461 / 8.0), + REAL_CONST(59215.436958028506 / 8.0), + REAL_CONST(59236.237111421855 / 8.0), + REAL_CONST(59257.039090911829 / 8.0), + REAL_CONST(59277.842896177877 / 8.0), + REAL_CONST(59298.648526899589 / 8.0), + REAL_CONST(59319.455982756685 / 8.0), + REAL_CONST(59340.26526342905 / 8.0), + REAL_CONST(59361.076368596696 / 8.0), + REAL_CONST(59381.889297939757 / 8.0), + REAL_CONST(59402.704051138542 / 8.0), + REAL_CONST(59423.520627873484 / 8.0), + REAL_CONST(59444.339027825139 / 8.0), + REAL_CONST(59465.159250674224 / 8.0), + REAL_CONST(59485.9812961016 / 8.0), + REAL_CONST(59506.805163788253 / 8.0), + REAL_CONST(59527.630853415307 / 8.0), + REAL_CONST(59548.458364664046 / 8.0), + REAL_CONST(59569.287697215863 / 8.0), + REAL_CONST(59590.118850752311 / 8.0), + REAL_CONST(59610.951824955089 / 8.0), + REAL_CONST(59631.786619506012 / 8.0), + REAL_CONST(59652.623234087048 / 8.0), + REAL_CONST(59673.461668380311 / 8.0), + REAL_CONST(59694.301922068029 / 8.0), + REAL_CONST(59715.143994832593 / 8.0), + REAL_CONST(59735.987886356525 / 8.0), + REAL_CONST(59756.833596322482 / 8.0), + REAL_CONST(59777.681124413255 / 8.0), + REAL_CONST(59798.530470311794 / 8.0), + REAL_CONST(59819.381633701159 / 8.0), + REAL_CONST(59840.234614264569 / 8.0), + REAL_CONST(59861.089411685381 / 8.0), + REAL_CONST(59881.94602564707 / 8.0), + REAL_CONST(59902.804455833269 / 8.0), + REAL_CONST(59923.664701927737 / 8.0), + REAL_CONST(59944.526763614384 / 8.0), + REAL_CONST(59965.390640577243 / 8.0), + REAL_CONST(59986.256332500488 / 8.0), + REAL_CONST(60007.123839068438 / 8.0), + REAL_CONST(60027.993159965539 / 8.0), + REAL_CONST(60048.864294876381 / 8.0), + REAL_CONST(60069.737243485688 / 8.0), + REAL_CONST(60090.612005478324 / 8.0), + REAL_CONST(60111.488580539284 / 8.0), + REAL_CONST(60132.366968353708 / 8.0), + REAL_CONST(60153.247168606867 / 8.0), + REAL_CONST(60174.129180984164 / 8.0), + REAL_CONST(60195.013005171153 / 8.0), + REAL_CONST(60215.898640853513 / 8.0), + REAL_CONST(60236.786087717061 / 8.0), + REAL_CONST(60257.675345447751 / 8.0), + REAL_CONST(60278.566413731671 / 8.0), + REAL_CONST(60299.459292255044 / 8.0), + REAL_CONST(60320.353980704247 / 8.0), + REAL_CONST(60341.25047876576 / 8.0), + REAL_CONST(60362.148786126229 / 8.0), + REAL_CONST(60383.048902472423 / 8.0), + REAL_CONST(60403.950827491237 / 8.0), + REAL_CONST(60424.854560869717 / 8.0), + REAL_CONST(60445.76010229504 / 8.0), + REAL_CONST(60466.667451454516 / 8.0), + REAL_CONST(60487.57660803559 / 8.0), + REAL_CONST(60508.487571725847 / 8.0), + REAL_CONST(60529.400342212997 / 8.0), + REAL_CONST(60550.314919184893 / 8.0), + REAL_CONST(60571.231302329521 / 8.0), + REAL_CONST(60592.149491335003 / 8.0), + REAL_CONST(60613.069485889588 / 8.0), + REAL_CONST(60633.991285681674 / 8.0), + REAL_CONST(60654.914890399785 / 8.0), + REAL_CONST(60675.840299732568 / 8.0), + REAL_CONST(60696.767513368832 / 8.0), + REAL_CONST(60717.696530997484 / 8.0), + REAL_CONST(60738.627352307602 / 8.0), + REAL_CONST(60759.55997698837 / 8.0), + REAL_CONST(60780.494404729128 / 8.0), + REAL_CONST(60801.430635219323 / 8.0), + REAL_CONST(60822.368668148556 / 8.0), + REAL_CONST(60843.308503206565 / 8.0), + REAL_CONST(60864.250140083204 / 8.0), + REAL_CONST(60885.193578468468 / 8.0), + REAL_CONST(60906.138818052495 / 8.0), + REAL_CONST(60927.085858525541 / 8.0), + REAL_CONST(60948.034699578006 / 8.0), + REAL_CONST(60968.985340900421 / 8.0), + REAL_CONST(60989.937782183442 / 8.0), + REAL_CONST(61010.892023117864 / 8.0), + REAL_CONST(61031.848063394616 / 8.0), + REAL_CONST(61052.805902704764 / 8.0), + REAL_CONST(61073.765540739492 / 8.0), + REAL_CONST(61094.726977190134 / 8.0), + REAL_CONST(61115.690211748137 / 8.0), + REAL_CONST(61136.655244105103 / 8.0), + REAL_CONST(61157.622073952742 / 8.0), + REAL_CONST(61178.590700982917 / 8.0), + REAL_CONST(61199.561124887616 / 8.0), + REAL_CONST(61220.533345358948 / 8.0), + REAL_CONST(61241.507362089171 / 8.0), + REAL_CONST(61262.483174770663 / 8.0), + REAL_CONST(61283.460783095943 / 8.0), + REAL_CONST(61304.440186757645 / 8.0), + REAL_CONST(61325.421385448557 / 8.0), + REAL_CONST(61346.404378861582 / 8.0), + REAL_CONST(61367.389166689762 / 8.0), + REAL_CONST(61388.375748626262 / 8.0), + REAL_CONST(61409.364124364387 / 8.0), + REAL_CONST(61430.354293597571 / 8.0), + REAL_CONST(61451.346256019373 / 8.0), + REAL_CONST(61472.340011323497 / 8.0), + REAL_CONST(61493.335559203762 / 8.0), + REAL_CONST(61514.332899354122 / 8.0), + REAL_CONST(61535.332031468672 / 8.0), + REAL_CONST(61556.332955241618 / 8.0), + REAL_CONST(61577.335670367313 / 8.0), + REAL_CONST(61598.340176540238 / 8.0), + REAL_CONST(61619.346473454993 / 8.0), + REAL_CONST(61640.354560806329 / 8.0), + REAL_CONST(61661.3644382891 / 8.0), + REAL_CONST(61682.376105598312 / 8.0), + REAL_CONST(61703.389562429089 / 8.0), + REAL_CONST(61724.404808476691 / 8.0), + REAL_CONST(61745.42184343651 / 8.0), + REAL_CONST(61766.440667004063 / 8.0), + REAL_CONST(61787.461278874987 / 8.0), + REAL_CONST(61808.483678745069 / 8.0), + REAL_CONST(61829.507866310203 / 8.0), + REAL_CONST(61850.533841266435 / 8.0), + REAL_CONST(61871.561603309929 / 8.0), + REAL_CONST(61892.591152136971 / 8.0), + REAL_CONST(61913.622487443987 / 8.0), + REAL_CONST(61934.655608927525 / 8.0), + REAL_CONST(61955.690516284267 / 8.0), + REAL_CONST(61976.727209211022 / 8.0), + REAL_CONST(61997.765687404724 / 8.0), + REAL_CONST(62018.805950562448 / 8.0), + REAL_CONST(62039.847998381381 / 8.0), + REAL_CONST(62060.891830558845 / 8.0), + REAL_CONST(62081.93744679229 / 8.0), + REAL_CONST(62102.984846779298 / 8.0), + REAL_CONST(62124.034030217575 / 8.0), + REAL_CONST(62145.084996804966 / 8.0), + REAL_CONST(62166.137746239416 / 8.0), + REAL_CONST(62187.19227821903 / 8.0), + REAL_CONST(62208.248592442025 / 8.0), + REAL_CONST(62229.306688606739 / 8.0), + REAL_CONST(62250.366566411656 / 8.0), + REAL_CONST(62271.428225555377 / 8.0), + REAL_CONST(62292.491665736627 / 8.0), + REAL_CONST(62313.556886654267 / 8.0), + REAL_CONST(62334.623888007271 / 8.0), + REAL_CONST(62355.692669494762 / 8.0), + REAL_CONST(62376.763230815974 / 8.0), + REAL_CONST(62397.835571670272 / 8.0), + REAL_CONST(62418.909691757144 / 8.0), + REAL_CONST(62439.98559077621 / 8.0), + REAL_CONST(62461.063268427228 / 8.0), + REAL_CONST(62482.142724410049 / 8.0), + REAL_CONST(62503.223958424685 / 8.0), + REAL_CONST(62524.306970171267 / 8.0), + REAL_CONST(62545.39175935003 / 8.0), + REAL_CONST(62566.478325661366 / 8.0), + REAL_CONST(62587.566668805768 / 8.0), + REAL_CONST(62608.656788483881 / 8.0), + REAL_CONST(62629.748684396451 / 8.0), + REAL_CONST(62650.842356244357 / 8.0), + REAL_CONST(62671.937803728622 / 8.0), + REAL_CONST(62693.035026550366 / 8.0), + REAL_CONST(62714.134024410858 / 8.0), + REAL_CONST(62735.234797011479 / 8.0), + REAL_CONST(62756.337344053733 / 8.0), + REAL_CONST(62777.441665239276 / 8.0), + REAL_CONST(62798.547760269852 / 8.0), + REAL_CONST(62819.655628847358 / 8.0), + REAL_CONST(62840.765270673801 / 8.0), + REAL_CONST(62861.876685451323 / 8.0), + REAL_CONST(62882.989872882186 / 8.0), + REAL_CONST(62904.104832668774 / 8.0), + REAL_CONST(62925.221564513602 / 8.0), + REAL_CONST(62946.340068119309 / 8.0), + REAL_CONST(62967.460343188657 / 8.0), + REAL_CONST(62988.582389424526 / 8.0), + REAL_CONST(63009.70620652994 / 8.0), + REAL_CONST(63030.831794208025 / 8.0), + REAL_CONST(63051.959152162039 / 8.0), + REAL_CONST(63073.08828009537 / 8.0), + REAL_CONST(63094.219177711529 / 8.0), + REAL_CONST(63115.351844714154 / 8.0), + REAL_CONST(63136.486280806988 / 8.0), + REAL_CONST(63157.622485693922 / 8.0), + REAL_CONST(63178.760459078956 / 8.0), + REAL_CONST(63199.900200666219 / 8.0), + REAL_CONST(63221.041710159967 / 8.0), + REAL_CONST(63242.184987264569 / 8.0), + REAL_CONST(63263.330031684534 / 8.0), + REAL_CONST(63284.476843124474 / 8.0), + REAL_CONST(63305.625421289144 / 8.0), + REAL_CONST(63326.775765883409 / 8.0), + REAL_CONST(63347.927876612259 / 8.0), + REAL_CONST(63369.081753180813 / 8.0), + REAL_CONST(63390.237395294316 / 8.0), + REAL_CONST(63411.39480265812 / 8.0), + REAL_CONST(63432.553974977716 / 8.0), + REAL_CONST(63453.714911958712 / 8.0), + REAL_CONST(63474.877613306839 / 8.0), + REAL_CONST(63496.042078727944 / 8.0), + REAL_CONST(63517.208307927998 / 8.0), + REAL_CONST(63538.376300613119 / 8.0), + REAL_CONST(63559.546056489504 / 8.0), + REAL_CONST(63580.717575263516 / 8.0), + REAL_CONST(63601.890856641607 / 8.0), + REAL_CONST(63623.065900330374 / 8.0), + REAL_CONST(63644.242706036515 / 8.0), + REAL_CONST(63665.421273466869 / 8.0), + REAL_CONST(63686.601602328381 / 8.0), + REAL_CONST(63707.783692328136 / 8.0), + REAL_CONST(63728.967543173334 / 8.0), + REAL_CONST(63750.153154571279 / 8.0), + REAL_CONST(63771.340526229418 / 8.0), + REAL_CONST(63792.529657855317 / 8.0), + REAL_CONST(63813.720549156649 / 8.0), + REAL_CONST(63834.913199841227 / 8.0), + REAL_CONST(63856.107609616978 / 8.0), + REAL_CONST(63877.303778191941 / 8.0), + REAL_CONST(63898.501705274284 / 8.0), + REAL_CONST(63919.7013905723 / 8.0), + REAL_CONST(63940.902833794404 / 8.0), + REAL_CONST(63962.106034649114 / 8.0), + REAL_CONST(63983.310992845094 / 8.0), + REAL_CONST(64004.517708091109 / 8.0), + REAL_CONST(64025.726180096048 / 8.0), + REAL_CONST(64046.936408568938 / 8.0), + REAL_CONST(64068.1483932189 / 8.0), + REAL_CONST(64089.362133755196 / 8.0), + REAL_CONST(64110.577629887193 / 8.0), + REAL_CONST(64131.794881324393 / 8.0), + REAL_CONST(64153.013887776404 / 8.0), + REAL_CONST(64174.234648952966 / 8.0), + REAL_CONST(64195.457164563937 / 8.0), + REAL_CONST(64216.681434319289 / 8.0), + REAL_CONST(64237.907457929112 / 8.0), + REAL_CONST(64259.135235103626 / 8.0), + REAL_CONST(64280.36476555316 / 8.0), + REAL_CONST(64301.596048988169 / 8.0), + REAL_CONST(64322.829085119236 / 8.0), + REAL_CONST(64344.06387365704 / 8.0), + REAL_CONST(64365.300414312398 / 8.0), + REAL_CONST(64386.538706796251 / 8.0), + REAL_CONST(64407.778750819634 / 8.0), + REAL_CONST(64429.020546093721 / 8.0), + REAL_CONST(64450.26409232981 / 8.0), + REAL_CONST(64471.509389239291 / 8.0), + REAL_CONST(64492.756436533709 / 8.0), + REAL_CONST(64514.005233924705 / 8.0), + REAL_CONST(64535.255781124033 / 8.0), + REAL_CONST(64556.50807784358 / 8.0), + REAL_CONST(64577.762123795357 / 8.0), + REAL_CONST(64599.017918691468 / 8.0), + REAL_CONST(64620.275462244172 / 8.0), + REAL_CONST(64641.534754165805 / 8.0), + REAL_CONST(64662.795794168844 / 8.0), + REAL_CONST(64684.058581965895 / 8.0), + REAL_CONST(64705.323117269661 / 8.0), + REAL_CONST(64726.589399792974 / 8.0), + REAL_CONST(64747.857429248776 / 8.0), + REAL_CONST(64769.127205350138 / 8.0), + REAL_CONST(64790.398727810236 / 8.0), + REAL_CONST(64811.671996342375 / 8.0), + REAL_CONST(64832.947010659969 / 8.0), + REAL_CONST(64854.223770476558 / 8.0), + REAL_CONST(64875.502275505794 / 8.0), + REAL_CONST(64896.782525461451 / 8.0), + REAL_CONST(64918.064520057414 / 8.0), + REAL_CONST(64939.348259007682 / 8.0), + REAL_CONST(64960.633742026388 / 8.0), + REAL_CONST(64981.920968827762 / 8.0), + REAL_CONST(65003.209939126165 / 8.0), + REAL_CONST(65024.500652636067 / 8.0), + REAL_CONST(65045.793109072067 / 8.0), + REAL_CONST(65067.087308148861 / 8.0), + REAL_CONST(65088.383249581282 / 8.0), + REAL_CONST(65109.680933084259 / 8.0), + REAL_CONST(65130.980358372864 / 8.0), + REAL_CONST(65152.28152516226 / 8.0), + REAL_CONST(65173.584433167736 / 8.0), + REAL_CONST(65194.889082104703 / 8.0), + REAL_CONST(65216.195471688683 / 8.0), + REAL_CONST(65237.503601635319 / 8.0), + REAL_CONST(65258.813471660353 / 8.0), + REAL_CONST(65280.125081479666 / 8.0), + REAL_CONST(65301.438430809241 / 8.0), + REAL_CONST(65322.753519365178 / 8.0), + REAL_CONST(65344.070346863708 / 8.0), + REAL_CONST(65365.388913021146 / 8.0), + REAL_CONST(65386.709217553958 / 8.0), + REAL_CONST(65408.031260178701 / 8.0), + REAL_CONST(65429.355040612056 / 8.0), + REAL_CONST(65450.680558570821 / 8.0), + REAL_CONST(65472.00781377191 / 8.0), + REAL_CONST(65493.336805932355 / 8.0), + REAL_CONST(65514.66753476928 / 8.0), + REAL_CONST(65535.999999999956 / 8.0), + REAL_CONST(65557.334201341757 / 8.0), + REAL_CONST(65578.670138512171 / 8.0), + REAL_CONST(65600.007811228788 / 8.0), + REAL_CONST(65621.347219209332 / 8.0), + REAL_CONST(65642.688362171626 / 8.0), + REAL_CONST(65664.031239833639 / 8.0), + REAL_CONST(65685.375851913413 / 8.0), + REAL_CONST(65706.722198129137 / 8.0), + REAL_CONST(65728.070278199084 / 8.0), + REAL_CONST(65749.420091841661 / 8.0), + REAL_CONST(65770.771638775404 / 8.0), + REAL_CONST(65792.124918718939 / 8.0), + REAL_CONST(65813.479931391004 / 8.0), + REAL_CONST(65834.836676510458 / 8.0), + REAL_CONST(65856.195153796303 / 8.0), + REAL_CONST(65877.5553629676 / 8.0), + REAL_CONST(65898.917303743554 / 8.0), + REAL_CONST(65920.280975843489 / 8.0), + REAL_CONST(65941.646378986843 / 8.0), + REAL_CONST(65963.013512893158 / 8.0), + REAL_CONST(65984.382377282076 / 8.0), + REAL_CONST(66005.752971873386 / 8.0), + REAL_CONST(66027.125296386963 / 8.0), + REAL_CONST(66048.499350542799 / 8.0), + REAL_CONST(66069.875134061018 / 8.0), + REAL_CONST(66091.252646661844 / 8.0), + REAL_CONST(66112.631888065618 / 8.0), + REAL_CONST(66134.01285799277 / 8.0), + REAL_CONST(66155.395556163887 / 8.0), + REAL_CONST(66176.779982299631 / 8.0), + REAL_CONST(66198.166136120795 / 8.0), + REAL_CONST(66219.554017348273 / 8.0), + REAL_CONST(66240.943625703105 / 8.0), + REAL_CONST(66262.334960906388 / 8.0), + REAL_CONST(66283.728022679396 / 8.0), + REAL_CONST(66305.122810743444 / 8.0), + REAL_CONST(66326.519324820023 / 8.0), + REAL_CONST(66347.917564630698 / 8.0), + REAL_CONST(66369.317529897162 / 8.0), + REAL_CONST(66390.719220341227 / 8.0), + REAL_CONST(66412.122635684791 / 8.0), + REAL_CONST(66433.527775649884 / 8.0), + REAL_CONST(66454.934639958636 / 8.0), + REAL_CONST(66476.343228333324 / 8.0), + REAL_CONST(66497.753540496284 / 8.0), + REAL_CONST(66519.165576169995 / 8.0), + REAL_CONST(66540.57933507704 / 8.0), + REAL_CONST(66561.994816940118 / 8.0), + REAL_CONST(66583.412021482043 / 8.0), + REAL_CONST(66604.830948425733 / 8.0), + REAL_CONST(66626.251597494222 / 8.0), + REAL_CONST(66647.673968410629 / 8.0), + REAL_CONST(66669.098060898235 / 8.0), + REAL_CONST(66690.523874680381 / 8.0), + REAL_CONST(66711.951409480564 / 8.0), + REAL_CONST(66733.380665022371 / 8.0), + REAL_CONST(66754.811641029475 / 8.0), + REAL_CONST(66776.244337225711 / 8.0), + REAL_CONST(66797.678753334985 / 8.0), + REAL_CONST(66819.11488908132 / 8.0), + REAL_CONST(66840.552744188884 / 8.0), + REAL_CONST(66861.992318381905 / 8.0), + REAL_CONST(66883.433611384738 / 8.0), + REAL_CONST(66904.876622921889 / 8.0), + REAL_CONST(66926.321352717903 / 8.0), + REAL_CONST(66947.767800497502 / 8.0), + REAL_CONST(66969.215965985466 / 8.0), + REAL_CONST(66990.665848906734 / 8.0), + REAL_CONST(67012.117448986304 / 8.0), + REAL_CONST(67033.570765949335 / 8.0), + REAL_CONST(67055.025799521056 / 8.0), + REAL_CONST(67076.482549426815 / 8.0), + REAL_CONST(67097.941015392076 / 8.0), + REAL_CONST(67119.401197142433 / 8.0), + REAL_CONST(67140.863094403554 / 8.0), + REAL_CONST(67162.326706901222 / 8.0), + REAL_CONST(67183.792034361351 / 8.0), + REAL_CONST(67205.259076509959 / 8.0), + REAL_CONST(67226.72783307315 / 8.0), + REAL_CONST(67248.198303777172 / 8.0), + REAL_CONST(67269.670488348347 / 8.0), + REAL_CONST(67291.144386513144 / 8.0), + REAL_CONST(67312.619997998088 / 8.0), + REAL_CONST(67334.09732252988 / 8.0), + REAL_CONST(67355.576359835293 / 8.0), + REAL_CONST(67377.057109641188 / 8.0), + REAL_CONST(67398.53957167457 / 8.0), + REAL_CONST(67420.023745662547 / 8.0), + REAL_CONST(67441.50963133233 / 8.0), + REAL_CONST(67462.99722841123 / 8.0), + REAL_CONST(67484.486536626689 / 8.0), + REAL_CONST(67505.977555706224 / 8.0), + REAL_CONST(67527.470285377494 / 8.0), + REAL_CONST(67548.964725368263 / 8.0), + REAL_CONST(67570.460875406367 / 8.0), + REAL_CONST(67591.9587352198 / 8.0), + REAL_CONST(67613.458304536631 / 8.0), + REAL_CONST(67634.95958308503 / 8.0), + REAL_CONST(67656.462570593329 / 8.0), + REAL_CONST(67677.967266789899 / 8.0), + REAL_CONST(67699.473671403248 / 8.0), + REAL_CONST(67720.981784162024 / 8.0), + REAL_CONST(67742.491604794923 / 8.0), + REAL_CONST(67764.003133030797 / 8.0), + REAL_CONST(67785.516368598575 / 8.0), + REAL_CONST(67807.031311227314 / 8.0), + REAL_CONST(67828.547960646174 / 8.0), + REAL_CONST(67850.066316584402 / 8.0), + REAL_CONST(67871.58637877139 / 8.0), + REAL_CONST(67893.108146936589 / 8.0), + REAL_CONST(67914.63162080961 / 8.0), + REAL_CONST(67936.156800120138 / 8.0), + REAL_CONST(67957.683684597971 / 8.0), + REAL_CONST(67979.212273973011 / 8.0), + REAL_CONST(68000.742567975263 / 8.0), + REAL_CONST(68022.274566334876 / 8.0), + REAL_CONST(68043.808268782057 / 8.0), + REAL_CONST(68065.343675047145 / 8.0), + REAL_CONST(68086.880784860579 / 8.0), + REAL_CONST(68108.419597952918 / 8.0), + REAL_CONST(68129.960114054789 / 8.0), + REAL_CONST(68151.502332896969 / 8.0), + REAL_CONST(68173.04625421032 / 8.0), + REAL_CONST(68194.591877725834 / 8.0), + REAL_CONST(68216.139203174564 / 8.0), + REAL_CONST(68237.688230287706 / 8.0), + REAL_CONST(68259.238958796544 / 8.0), + REAL_CONST(68280.791388432481 / 8.0), + REAL_CONST(68302.345518927032 / 8.0), + REAL_CONST(68323.901350011787 / 8.0), + REAL_CONST(68345.458881418483 / 8.0), + REAL_CONST(68367.018112878912 / 8.0), + REAL_CONST(68388.579044125028 / 8.0), + REAL_CONST(68410.141674888844 / 8.0), + REAL_CONST(68431.706004902502 / 8.0), + REAL_CONST(68453.272033898262 / 8.0), + REAL_CONST(68474.839761608455 / 8.0), + REAL_CONST(68496.409187765545 / 8.0), + REAL_CONST(68517.980312102081 / 8.0), + REAL_CONST(68539.553134350732 / 8.0), + REAL_CONST(68561.127654244279 / 8.0), + REAL_CONST(68582.70387151558 / 8.0), + REAL_CONST(68604.281785897634 / 8.0), + REAL_CONST(68625.861397123503 / 8.0), + REAL_CONST(68647.44270492639 / 8.0), + REAL_CONST(68669.025709039604 / 8.0), + REAL_CONST(68690.610409196524 / 8.0), + REAL_CONST(68712.196805130661 / 8.0), + REAL_CONST(68733.784896575627 / 8.0), + REAL_CONST(68755.374683265123 / 8.0), + REAL_CONST(68776.966164932994 / 8.0), + REAL_CONST(68798.559341313128 / 8.0), + REAL_CONST(68820.154212139591 / 8.0), + REAL_CONST(68841.750777146473 / 8.0), + REAL_CONST(68863.349036068044 / 8.0), + REAL_CONST(68884.948988638629 / 8.0), + REAL_CONST(68906.550634592684 / 8.0), + REAL_CONST(68928.153973664739 / 8.0), + REAL_CONST(68949.75900558944 / 8.0), + REAL_CONST(68971.365730101577 / 8.0), + REAL_CONST(68992.974146935987 / 8.0), + REAL_CONST(69014.584255827634 / 8.0), + REAL_CONST(69036.196056511588 / 8.0), + REAL_CONST(69057.809548723017 / 8.0), + REAL_CONST(69079.424732197207 / 8.0), + REAL_CONST(69101.041606669532 / 8.0), + REAL_CONST(69122.660171875468 / 8.0), + REAL_CONST(69144.280427550606 / 8.0), + REAL_CONST(69165.902373430625 / 8.0), + REAL_CONST(69187.526009251334 / 8.0), + REAL_CONST(69209.151334748618 / 8.0), + REAL_CONST(69230.778349658474 / 8.0), + REAL_CONST(69252.40705371699 / 8.0), + REAL_CONST(69274.037446660412 / 8.0), + REAL_CONST(69295.669528225 / 8.0), + REAL_CONST(69317.303298147192 / 8.0), + REAL_CONST(69338.938756163494 / 8.0), + REAL_CONST(69360.575902010532 / 8.0), + REAL_CONST(69382.214735425005 / 8.0), + REAL_CONST(69403.855256143754 / 8.0), + REAL_CONST(69425.497463903681 / 8.0), + REAL_CONST(69447.141358441833 / 8.0), + REAL_CONST(69468.78693949533 / 8.0), + REAL_CONST(69490.434206801394 / 8.0), + REAL_CONST(69512.083160097391 / 8.0), + REAL_CONST(69533.733799120717 / 8.0), + REAL_CONST(69555.386123608929 / 8.0), + REAL_CONST(69577.04013329967 / 8.0), + REAL_CONST(69598.695827930685 / 8.0), + REAL_CONST(69620.353207239794 / 8.0), + REAL_CONST(69642.012270964973 / 8.0), + REAL_CONST(69663.67301884426 / 8.0), + REAL_CONST(69685.335450615792 / 8.0), + REAL_CONST(69706.999566017839 / 8.0), + REAL_CONST(69728.665364788743 / 8.0), + REAL_CONST(69750.332846666963 / 8.0), + REAL_CONST(69772.002011391058 / 8.0), + REAL_CONST(69793.672858699691 / 8.0), + REAL_CONST(69815.345388331611 / 8.0), + REAL_CONST(69837.019600025669 / 8.0), + REAL_CONST(69858.695493520849 / 8.0), + REAL_CONST(69880.373068556204 / 8.0), + REAL_CONST(69902.052324870907 / 8.0), + REAL_CONST(69923.733262204216 / 8.0), + REAL_CONST(69945.415880295492 / 8.0), + REAL_CONST(69967.100178884211 / 8.0), + REAL_CONST(69988.786157709939 / 8.0), + REAL_CONST(70010.473816512356 / 8.0), + REAL_CONST(70032.163155031216 / 8.0), + REAL_CONST(70053.854173006403 / 8.0), + REAL_CONST(70075.546870177874 / 8.0), + REAL_CONST(70097.241246285717 / 8.0), + REAL_CONST(70118.937301070109 / 8.0), + REAL_CONST(70140.635034271298 / 8.0), + REAL_CONST(70162.334445629691 / 8.0), + REAL_CONST(70184.035534885741 / 8.0), + REAL_CONST(70205.738301780017 / 8.0), + REAL_CONST(70227.442746053217 / 8.0), + REAL_CONST(70249.1488674461 / 8.0), + REAL_CONST(70270.856665699539 / 8.0), + REAL_CONST(70292.566140554511 / 8.0), + REAL_CONST(70314.277291752107 / 8.0), + REAL_CONST(70335.990119033493 / 8.0), + REAL_CONST(70357.704622139936 / 8.0), + REAL_CONST(70379.420800812819 / 8.0), + REAL_CONST(70401.138654793613 / 8.0), + REAL_CONST(70422.85818382389 / 8.0), + REAL_CONST(70444.579387645339 / 8.0), + REAL_CONST(70466.302265999722 / 8.0), + REAL_CONST(70488.026818628918 / 8.0), + REAL_CONST(70509.753045274876 / 8.0), + REAL_CONST(70531.480945679708 / 8.0), + REAL_CONST(70553.210519585555 / 8.0), + REAL_CONST(70574.941766734701 / 8.0), + REAL_CONST(70596.674686869505 / 8.0), + REAL_CONST(70618.409279732456 / 8.0), + REAL_CONST(70640.145545066101 / 8.0), + REAL_CONST(70661.883482613106 / 8.0), + REAL_CONST(70683.623092116264 / 8.0), + REAL_CONST(70705.364373318414 / 8.0), + REAL_CONST(70727.107325962526 / 8.0), + REAL_CONST(70748.851949791671 / 8.0), + REAL_CONST(70770.598244549008 / 8.0), + REAL_CONST(70792.346209977783 / 8.0), + REAL_CONST(70814.095845821372 / 8.0), + REAL_CONST(70835.847151823225 / 8.0), + REAL_CONST(70857.600127726895 / 8.0), + REAL_CONST(70879.354773276034 / 8.0), + REAL_CONST(70901.111088214413 / 8.0), + REAL_CONST(70922.869072285859 / 8.0), + REAL_CONST(70944.628725234332 / 8.0), + REAL_CONST(70966.390046803877 / 8.0), + REAL_CONST(70988.153036738629 / 8.0), + REAL_CONST(71009.917694782853 / 8.0), + REAL_CONST(71031.684020680885 / 8.0), + REAL_CONST(71053.45201417715 / 8.0), + REAL_CONST(71075.221675016204 / 8.0), + REAL_CONST(71096.993002942661 / 8.0), + REAL_CONST(71118.765997701266 / 8.0), + REAL_CONST(71140.540659036851 / 8.0), + REAL_CONST(71162.316986694335 / 8.0), + REAL_CONST(71184.09498041874 / 8.0), + REAL_CONST(71205.874639955218 / 8.0), + REAL_CONST(71227.655965048951 / 8.0), + REAL_CONST(71249.438955445294 / 8.0), + REAL_CONST(71271.223610889632 / 8.0), + REAL_CONST(71293.009931127483 / 8.0), + REAL_CONST(71314.797915904477 / 8.0), + REAL_CONST(71336.587564966307 / 8.0), + REAL_CONST(71358.378878058764 / 8.0), + REAL_CONST(71380.171854927772 / 8.0), + REAL_CONST(71401.966495319313 / 8.0), + REAL_CONST(71423.762798979486 / 8.0), + REAL_CONST(71445.560765654489 / 8.0), + REAL_CONST(71467.360395090596 / 8.0), + REAL_CONST(71489.161687034211 / 8.0), + REAL_CONST(71510.964641231811 / 8.0), + REAL_CONST(71532.769257429973 / 8.0), + REAL_CONST(71554.575535375348 / 8.0), + REAL_CONST(71576.383474814749 / 8.0), + REAL_CONST(71598.19307549503 / 8.0), + REAL_CONST(71620.004337163133 / 8.0), + REAL_CONST(71641.817259566145 / 8.0), + REAL_CONST(71663.631842451214 / 8.0), + REAL_CONST(71685.4480855656 / 8.0), + REAL_CONST(71707.26598865664 / 8.0), + REAL_CONST(71729.085551471784 / 8.0), + REAL_CONST(71750.906773758586 / 8.0), + REAL_CONST(71772.729655264673 / 8.0), + REAL_CONST(71794.554195737772 / 8.0), + REAL_CONST(71816.380394925713 / 8.0), + REAL_CONST(71838.208252576442 / 8.0), + REAL_CONST(71860.037768437964 / 8.0), + REAL_CONST(71881.868942258385 / 8.0), + REAL_CONST(71903.701773785942 / 8.0), + REAL_CONST(71925.536262768932 / 8.0), + REAL_CONST(71947.372408955751 / 8.0), + REAL_CONST(71969.210212094898 / 8.0), + REAL_CONST(71991.049671934976 / 8.0), + REAL_CONST(72012.890788224686 / 8.0), + REAL_CONST(72034.73356071279 / 8.0), + REAL_CONST(72056.577989148165 / 8.0), + REAL_CONST(72078.424073279821 / 8.0), + REAL_CONST(72100.271812856794 / 8.0), + REAL_CONST(72122.121207628254 / 8.0), + REAL_CONST(72143.97225734347 / 8.0), + REAL_CONST(72165.824961751801 / 8.0), + REAL_CONST(72187.679320602692 / 8.0), + REAL_CONST(72209.53533364569 / 8.0), + REAL_CONST(72231.393000630429 / 8.0), + REAL_CONST(72253.252321306645 / 8.0), + REAL_CONST(72275.113295424177 / 8.0), + REAL_CONST(72296.975922732949 / 8.0), + REAL_CONST(72318.840202982959 / 8.0), + REAL_CONST(72340.706135924338 / 8.0), + REAL_CONST(72362.573721307272 / 8.0), + REAL_CONST(72384.442958882093 / 8.0), + REAL_CONST(72406.313848399179 / 8.0), + REAL_CONST(72428.186389609036 / 8.0), + REAL_CONST(72450.060582262216 / 8.0), + REAL_CONST(72471.936426109431 / 8.0), + REAL_CONST(72493.813920901433 / 8.0), + REAL_CONST(72515.693066389096 / 8.0), + REAL_CONST(72537.573862323392 / 8.0), + REAL_CONST(72559.456308455352 / 8.0), + REAL_CONST(72581.340404536139 / 8.0), + REAL_CONST(72603.226150316987 / 8.0), + REAL_CONST(72625.113545549248 / 8.0), + REAL_CONST(72647.002589984331 / 8.0), + REAL_CONST(72668.893283373764 / 8.0), + REAL_CONST(72690.785625469172 / 8.0), + REAL_CONST(72712.679616022273 / 8.0), + REAL_CONST(72734.575254784853 / 8.0), + REAL_CONST(72756.472541508803 / 8.0), + REAL_CONST(72778.371475946144 / 8.0), + REAL_CONST(72800.272057848939 / 8.0), + REAL_CONST(72822.174286969355 / 8.0), + REAL_CONST(72844.07816305969 / 8.0), + REAL_CONST(72865.983685872285 / 8.0), + REAL_CONST(72887.890855159596 / 8.0), + REAL_CONST(72909.799670674183 / 8.0), + REAL_CONST(72931.710132168693 / 8.0), + REAL_CONST(72953.622239395845 / 8.0), + REAL_CONST(72975.535992108475 / 8.0), + REAL_CONST(72997.451390059519 / 8.0), + REAL_CONST(73019.368433001961 / 8.0), + REAL_CONST(73041.287120688925 / 8.0), + REAL_CONST(73063.207452873612 / 8.0), + REAL_CONST(73085.129429309294 / 8.0), + REAL_CONST(73107.053049749389 / 8.0), + REAL_CONST(73128.978313947344 / 8.0), + REAL_CONST(73150.905221656736 / 8.0), + REAL_CONST(73172.833772631217 / 8.0), + REAL_CONST(73194.763966624567 / 8.0), + REAL_CONST(73216.695803390612 / 8.0), + REAL_CONST(73238.62928268328 / 8.0), + REAL_CONST(73260.564404256627 / 8.0), + REAL_CONST(73282.501167864757 / 8.0), + REAL_CONST(73304.439573261901 / 8.0), + REAL_CONST(73326.379620202337 / 8.0), + REAL_CONST(73348.321308440485 / 8.0), + REAL_CONST(73370.264637730841 / 8.0), + REAL_CONST(73392.209607827957 / 8.0), + REAL_CONST(73414.156218486532 / 8.0), + REAL_CONST(73436.104469461323 / 8.0), + REAL_CONST(73458.054360507173 / 8.0), + REAL_CONST(73480.005891379056 / 8.0), + REAL_CONST(73501.959061831993 / 8.0), + REAL_CONST(73523.913871621116 / 8.0), + REAL_CONST(73545.870320501665 / 8.0), + REAL_CONST(73567.828408228932 / 8.0), + REAL_CONST(73589.78813455833 / 8.0), + REAL_CONST(73611.749499245358 / 8.0), + REAL_CONST(73633.712502045615 / 8.0), + REAL_CONST(73655.677142714747 / 8.0), + REAL_CONST(73677.643421008557 / 8.0), + REAL_CONST(73699.611336682879 / 8.0), + REAL_CONST(73721.580889493693 / 8.0), + REAL_CONST(73743.552079197019 / 8.0), + REAL_CONST(73765.524905548999 / 8.0), + REAL_CONST(73787.499368305856 / 8.0), + REAL_CONST(73809.475467223907 / 8.0), + REAL_CONST(73831.453202059551 / 8.0), + REAL_CONST(73853.432572569291 / 8.0), + REAL_CONST(73875.413578509717 / 8.0), + REAL_CONST(73897.396219637507 / 8.0), + REAL_CONST(73919.380495709411 / 8.0), + REAL_CONST(73941.36640648231 / 8.0), + REAL_CONST(73963.353951713143 / 8.0), + REAL_CONST(73985.343131158952 / 8.0), + REAL_CONST(74007.333944576865 / 8.0), + REAL_CONST(74029.326391724098 / 8.0), + REAL_CONST(74051.320472357969 / 8.0), + REAL_CONST(74073.316186235883 / 8.0), + REAL_CONST(74095.313533115303 / 8.0), + REAL_CONST(74117.312512753837 / 8.0), + REAL_CONST(74139.313124909138 / 8.0), + REAL_CONST(74161.315369338976 / 8.0), + REAL_CONST(74183.319245801191 / 8.0), + REAL_CONST(74205.324754053727 / 8.0), + REAL_CONST(74227.331893854629 / 8.0), + REAL_CONST(74249.340664961986 / 8.0), + REAL_CONST(74271.351067134034 / 8.0), + REAL_CONST(74293.363100129049 / 8.0), + REAL_CONST(74315.376763705441 / 8.0), + REAL_CONST(74337.392057621662 / 8.0), + REAL_CONST(74359.408981636298 / 8.0), + REAL_CONST(74381.427535508003 / 8.0), + REAL_CONST(74403.447718995507 / 8.0), + REAL_CONST(74425.469531857671 / 8.0), + REAL_CONST(74447.492973853383 / 8.0), + REAL_CONST(74469.518044741693 / 8.0), + REAL_CONST(74491.54474428168 / 8.0), + REAL_CONST(74513.573072232539 / 8.0), + REAL_CONST(74535.603028353551 / 8.0), + REAL_CONST(74557.634612404087 / 8.0), + REAL_CONST(74579.667824143602 / 8.0), + REAL_CONST(74601.702663331642 / 8.0), + REAL_CONST(74623.739129727837 / 8.0), + REAL_CONST(74645.777223091936 / 8.0), + REAL_CONST(74667.816943183716 / 8.0), + REAL_CONST(74689.858289763113 / 8.0), + REAL_CONST(74711.901262590094 / 8.0), + REAL_CONST(74733.945861424741 / 8.0), + REAL_CONST(74755.992086027225 / 8.0), + REAL_CONST(74778.039936157802 / 8.0), + REAL_CONST(74800.089411576817 / 8.0), + REAL_CONST(74822.140512044702 / 8.0), + REAL_CONST(74844.193237321961 / 8.0), + REAL_CONST(74866.24758716923 / 8.0), + REAL_CONST(74888.303561347187 / 8.0), + REAL_CONST(74910.36115961663 / 8.0), + REAL_CONST(74932.420381738411 / 8.0), + REAL_CONST(74954.481227473516 / 8.0), + REAL_CONST(74976.543696582972 / 8.0), + REAL_CONST(74998.607788827925 / 8.0), + REAL_CONST(75020.673503969607 / 8.0), + REAL_CONST(75042.740841769322 / 8.0), + REAL_CONST(75064.809801988464 / 8.0), + REAL_CONST(75086.88038438854 / 8.0), + REAL_CONST(75108.952588731103 / 8.0), + REAL_CONST(75131.026414777836 / 8.0), + REAL_CONST(75153.101862290467 / 8.0), + REAL_CONST(75175.178931030852 / 8.0), + REAL_CONST(75197.257620760924 / 8.0), + REAL_CONST(75219.33793124267 / 8.0), + REAL_CONST(75241.419862238225 / 8.0), + REAL_CONST(75263.503413509738 / 8.0), + REAL_CONST(75285.588584819503 / 8.0), + REAL_CONST(75307.675375929874 / 8.0), + REAL_CONST(75329.763786603318 / 8.0), + REAL_CONST(75351.853816602365 / 8.0), + REAL_CONST(75373.945465689612 / 8.0), + REAL_CONST(75396.038733627807 / 8.0), + REAL_CONST(75418.133620179724 / 8.0), + REAL_CONST(75440.230125108254 / 8.0), + REAL_CONST(75462.32824817636 / 8.0), + REAL_CONST(75484.427989147109 / 8.0), + REAL_CONST(75506.529347783653 / 8.0), + REAL_CONST(75528.63232384919 / 8.0), + REAL_CONST(75550.736917107075 / 8.0), + REAL_CONST(75572.843127320695 / 8.0), + REAL_CONST(75594.950954253538 / 8.0), + REAL_CONST(75617.060397669193 / 8.0), + REAL_CONST(75639.171457331307 / 8.0), + REAL_CONST(75661.284133003646 / 8.0), + REAL_CONST(75683.398424450032 / 8.0), + REAL_CONST(75705.514331434402 / 8.0), + REAL_CONST(75727.631853720741 / 8.0), + REAL_CONST(75749.750991073175 / 8.0), + REAL_CONST(75771.871743255862 / 8.0), + REAL_CONST(75793.994110033076 / 8.0), + REAL_CONST(75816.118091169177 / 8.0), + REAL_CONST(75838.243686428585 / 8.0), + REAL_CONST(75860.370895575848 / 8.0), + REAL_CONST(75882.499718375562 / 8.0), + REAL_CONST(75904.630154592422 / 8.0), + REAL_CONST(75926.762203991224 / 8.0), + REAL_CONST(75948.895866336825 / 8.0), + REAL_CONST(75971.031141394182 / 8.0), + REAL_CONST(75993.168028928325 / 8.0), + REAL_CONST(76015.306528704401 / 8.0), + REAL_CONST(76037.4466404876 / 8.0), + REAL_CONST(76059.588364043215 / 8.0), + REAL_CONST(76081.731699136653 / 8.0), + REAL_CONST(76103.876645533353 / 8.0), + REAL_CONST(76126.023202998884 / 8.0), + REAL_CONST(76148.171371298871 / 8.0), + REAL_CONST(76170.321150199044 / 8.0), + REAL_CONST(76192.472539465205 / 8.0), + REAL_CONST(76214.625538863256 / 8.0), + REAL_CONST(76236.780148159174 / 8.0), + REAL_CONST(76258.936367119008 / 8.0), + REAL_CONST(76281.094195508922 / 8.0), + REAL_CONST(76303.253633095141 / 8.0), + REAL_CONST(76325.414679643975 / 8.0), + REAL_CONST(76347.577334921851 / 8.0), + REAL_CONST(76369.741598695226 / 8.0), + REAL_CONST(76391.907470730686 / 8.0), + REAL_CONST(76414.074950794879 / 8.0), + REAL_CONST(76436.244038654564 / 8.0), + REAL_CONST(76458.414734076548 / 8.0), + REAL_CONST(76480.587036827754 / 8.0), + REAL_CONST(76502.760946675175 / 8.0), + REAL_CONST(76524.936463385893 / 8.0), + REAL_CONST(76547.11358672705 / 8.0), + REAL_CONST(76569.292316465915 / 8.0), + REAL_CONST(76591.472652369819 / 8.0), + REAL_CONST(76613.654594206164 / 8.0), + REAL_CONST(76635.838141742468 / 8.0), + REAL_CONST(76658.023294746308 / 8.0), + REAL_CONST(76680.210052985349 / 8.0), + REAL_CONST(76702.398416227341 / 8.0), + REAL_CONST(76724.588384240138 / 8.0), + REAL_CONST(76746.779956791637 / 8.0), + REAL_CONST(76768.973133649866 / 8.0), + REAL_CONST(76791.167914582897 / 8.0), + REAL_CONST(76813.364299358902 / 8.0), + REAL_CONST(76835.562287746157 / 8.0), + REAL_CONST(76857.761879512967 / 8.0), + REAL_CONST(76879.963074427797 / 8.0), + REAL_CONST(76902.165872259109 / 8.0), + REAL_CONST(76924.37027277553 / 8.0), + REAL_CONST(76946.576275745727 / 8.0), + REAL_CONST(76968.783880938441 / 8.0), + REAL_CONST(76990.993088122515 / 8.0), + REAL_CONST(77013.203897066895 / 8.0), + REAL_CONST(77035.416307540567 / 8.0), + REAL_CONST(77057.630319312622 / 8.0), + REAL_CONST(77079.845932152239 / 8.0), + REAL_CONST(77102.063145828695 / 8.0), + REAL_CONST(77124.281960111301 / 8.0), + REAL_CONST(77146.50237476948 / 8.0), + REAL_CONST(77168.724389572759 / 8.0), + REAL_CONST(77190.948004290723 / 8.0), + REAL_CONST(77213.173218693031 / 8.0), + REAL_CONST(77235.400032549442 / 8.0), + REAL_CONST(77257.628445629802 / 8.0), + REAL_CONST(77279.858457704031 / 8.0), + REAL_CONST(77302.090068542122 / 8.0), + REAL_CONST(77324.323277914169 / 8.0), + REAL_CONST(77346.558085590339 / 8.0), + REAL_CONST(77368.794491340886 / 8.0), + REAL_CONST(77391.032494936138 / 8.0), + REAL_CONST(77413.272096146524 / 8.0), + REAL_CONST(77435.51329474253 / 8.0), + REAL_CONST(77457.756090494731 / 8.0), + REAL_CONST(77480.000483173804 / 8.0), + REAL_CONST(77502.246472550498 / 8.0), + REAL_CONST(77524.494058395634 / 8.0), + REAL_CONST(77546.743240480107 / 8.0), + REAL_CONST(77568.994018574944 / 8.0), + REAL_CONST(77591.246392451198 / 8.0), + REAL_CONST(77613.500361880026 / 8.0), + REAL_CONST(77635.755926632657 / 8.0), + REAL_CONST(77658.013086480438 / 8.0), + REAL_CONST(77680.271841194757 / 8.0), + REAL_CONST(77702.532190547092 / 8.0), + REAL_CONST(77724.794134309021 / 8.0), + REAL_CONST(77747.057672252195 / 8.0), + REAL_CONST(77769.322804148323 / 8.0), + REAL_CONST(77791.589529769248 / 8.0), + REAL_CONST(77813.857848886837 / 8.0), + REAL_CONST(77836.127761273063 / 8.0), + REAL_CONST(77858.399266699998 / 8.0), + REAL_CONST(77880.67236493979 / 8.0), + REAL_CONST(77902.947055764627 / 8.0), + REAL_CONST(77925.223338946831 / 8.0), + REAL_CONST(77947.50121425878 / 8.0), + REAL_CONST(77969.780681472927 / 8.0), + REAL_CONST(77992.061740361838 / 8.0), + REAL_CONST(78014.344390698127 / 8.0), + REAL_CONST(78036.628632254491 / 8.0), + REAL_CONST(78058.914464803747 / 8.0), + REAL_CONST(78081.201888118725 / 8.0), + REAL_CONST(78103.490901972415 / 8.0), + REAL_CONST(78125.781506137821 / 8.0), + REAL_CONST(78148.073700388064 / 8.0), + REAL_CONST(78170.367484496339 / 8.0), + REAL_CONST(78192.662858235926 / 8.0), + REAL_CONST(78214.959821380166 / 8.0), + REAL_CONST(78237.258373702498 / 8.0), + REAL_CONST(78259.558514976452 / 8.0), + REAL_CONST(78281.860244975614 / 8.0), + REAL_CONST(78304.163563473659 / 8.0), + REAL_CONST(78326.468470244363 / 8.0), + REAL_CONST(78348.77496506153 / 8.0), + REAL_CONST(78371.083047699125 / 8.0), + REAL_CONST(78393.392717931114 / 8.0), + REAL_CONST(78415.703975531578 / 8.0), + REAL_CONST(78438.016820274701 / 8.0), + REAL_CONST(78460.331251934695 / 8.0), + REAL_CONST(78482.647270285903 / 8.0), + REAL_CONST(78504.964875102727 / 8.0), + REAL_CONST(78527.284066159627 / 8.0), + REAL_CONST(78549.604843231195 / 8.0), + REAL_CONST(78571.927206092048 / 8.0), + REAL_CONST(78594.251154516911 / 8.0), + REAL_CONST(78616.576688280606 / 8.0), + REAL_CONST(78638.903807157985 / 8.0), + REAL_CONST(78661.232510924034 / 8.0), + REAL_CONST(78683.562799353778 / 8.0), + REAL_CONST(78705.894672222363 / 8.0), + REAL_CONST(78728.228129304945 / 8.0), + REAL_CONST(78750.563170376859 / 8.0), + REAL_CONST(78772.899795213423 / 8.0), + REAL_CONST(78795.238003590101 / 8.0), + REAL_CONST(78817.577795282399 / 8.0), + REAL_CONST(78839.919170065928 / 8.0), + REAL_CONST(78862.262127716356 / 8.0), + REAL_CONST(78884.606668009452 / 8.0), + REAL_CONST(78906.952790721043 / 8.0), + REAL_CONST(78929.300495627045 / 8.0), + REAL_CONST(78951.64978250346 / 8.0), + REAL_CONST(78974.000651126378 / 8.0), + REAL_CONST(78996.353101271932 / 8.0), + REAL_CONST(79018.707132716358 / 8.0), + REAL_CONST(79041.062745235977 / 8.0), + REAL_CONST(79063.41993860717 / 8.0), + REAL_CONST(79085.778712606436 / 8.0), + REAL_CONST(79108.139067010285 / 8.0), + REAL_CONST(79130.501001595389 / 8.0), + REAL_CONST(79152.864516138419 / 8.0), + REAL_CONST(79175.22961041618 / 8.0), + REAL_CONST(79197.596284205531 / 8.0), + REAL_CONST(79219.96453728342 / 8.0), + REAL_CONST(79242.33436942687 / 8.0), + REAL_CONST(79264.705780412987 / 8.0), + REAL_CONST(79287.078770018954 / 8.0), + REAL_CONST(79309.453338022009 / 8.0), + REAL_CONST(79331.829484199508 / 8.0), + REAL_CONST(79354.207208328866 / 8.0), + REAL_CONST(79376.586510187582 / 8.0), + REAL_CONST(79398.967389553218 / 8.0), + REAL_CONST(79421.349846203433 / 8.0), + REAL_CONST(79443.733879915948 / 8.0), + REAL_CONST(79466.119490468584 / 8.0), + REAL_CONST(79488.50667763922 / 8.0), + REAL_CONST(79510.895441205823 / 8.0), + REAL_CONST(79533.285780946433 / 8.0), + REAL_CONST(79555.677696639163 / 8.0), + REAL_CONST(79578.071188062226 / 8.0), + REAL_CONST(79600.466254993895 / 8.0), + REAL_CONST(79622.862897212515 / 8.0), + REAL_CONST(79645.261114496549 / 8.0), + REAL_CONST(79667.660906624471 / 8.0), + REAL_CONST(79690.062273374875 / 8.0), + REAL_CONST(79712.465214526455 / 8.0), + REAL_CONST(79734.869729857935 / 8.0), + REAL_CONST(79757.275819148126 / 8.0), + REAL_CONST(79779.683482175955 / 8.0), + REAL_CONST(79802.092718720378 / 8.0), + REAL_CONST(79824.503528560454 / 8.0), + REAL_CONST(79846.915911475327 / 8.0), + REAL_CONST(79869.329867244203 / 8.0), + REAL_CONST(79891.745395646343 / 8.0), + REAL_CONST(79914.162496461155 / 8.0), + REAL_CONST(79936.581169468045 / 8.0), + REAL_CONST(79959.001414446553 / 8.0), + REAL_CONST(79981.423231176261 / 8.0), + REAL_CONST(80003.846619436852 / 8.0), + REAL_CONST(80026.271579008084 / 8.0), + REAL_CONST(80048.698109669771 / 8.0), + REAL_CONST(80071.12621120183 / 8.0), + REAL_CONST(80093.555883384237 / 8.0), + REAL_CONST(80115.987125997053 / 8.0), + REAL_CONST(80138.419938820414 / 8.0), + REAL_CONST(80160.854321634528 / 8.0), + REAL_CONST(80183.290274219689 / 8.0), + REAL_CONST(80205.727796356281 / 8.0), + REAL_CONST(80228.166887824715 / 8.0), + REAL_CONST(80250.607548405547 / 8.0), + REAL_CONST(80273.049777879336 / 8.0), + REAL_CONST(80295.493576026798 / 8.0), + REAL_CONST(80317.938942628651 / 8.0), + REAL_CONST(80340.385877465727 / 8.0), + REAL_CONST(80362.834380318949 / 8.0), + REAL_CONST(80385.28445096928 / 8.0), + REAL_CONST(80407.736089197788 / 8.0), + REAL_CONST(80430.189294785596 / 8.0), + REAL_CONST(80452.644067513917 / 8.0), + REAL_CONST(80475.100407164035 / 8.0), + REAL_CONST(80497.558313517322 / 8.0), + REAL_CONST(80520.017786355209 / 8.0), + REAL_CONST(80542.478825459213 / 8.0), + REAL_CONST(80564.941430610925 / 8.0), + REAL_CONST(80587.405601592007 / 8.0), + REAL_CONST(80609.871338184195 / 8.0), + REAL_CONST(80632.338640169342 / 8.0), + REAL_CONST(80654.8075073293 / 8.0), + REAL_CONST(80677.277939446067 / 8.0), + REAL_CONST(80699.749936301683 / 8.0), + REAL_CONST(80722.223497678278 / 8.0), + REAL_CONST(80744.698623358039 / 8.0), + REAL_CONST(80767.17531312324 / 8.0), + REAL_CONST(80789.653566756242 / 8.0), + REAL_CONST(80812.133384039465 / 8.0), + REAL_CONST(80834.614764755403 / 8.0), + REAL_CONST(80857.097708686648 / 8.0), + REAL_CONST(80879.582215615854 / 8.0), + REAL_CONST(80902.068285325731 / 8.0), + REAL_CONST(80924.555917599093 / 8.0), + REAL_CONST(80947.045112218824 / 8.0), + REAL_CONST(80969.535868967869 / 8.0), + REAL_CONST(80992.028187629272 / 8.0), + REAL_CONST(81014.522067986123 / 8.0), + REAL_CONST(81037.017509821613 / 8.0), + REAL_CONST(81059.514512919006 / 8.0), + REAL_CONST(81082.013077061609 / 8.0), + REAL_CONST(81104.513202032831 / 8.0), + REAL_CONST(81127.014887616184 / 8.0), + REAL_CONST(81149.518133595193 / 8.0), + REAL_CONST(81172.022939753486 / 8.0), + REAL_CONST(81194.529305874807 / 8.0), + REAL_CONST(81217.037231742899 / 8.0), + REAL_CONST(81239.546717141639 / 8.0), + REAL_CONST(81262.057761854958 / 8.0), + REAL_CONST(81284.570365666848 / 8.0), + REAL_CONST(81307.084528361403 / 8.0), + REAL_CONST(81329.600249722775 / 8.0), + REAL_CONST(81352.117529535186 / 8.0), + REAL_CONST(81374.636367582949 / 8.0), + REAL_CONST(81397.156763650448 / 8.0), + REAL_CONST(81419.678717522125 / 8.0), + REAL_CONST(81442.202228982511 / 8.0), + REAL_CONST(81464.727297816222 / 8.0), + REAL_CONST(81487.253923807933 / 8.0), + REAL_CONST(81509.782106742379 / 8.0), + REAL_CONST(81532.311846404409 / 8.0), + REAL_CONST(81554.843142578902 / 8.0), + REAL_CONST(81577.375995050839 / 8.0), + REAL_CONST(81599.910403605274 / 8.0), + REAL_CONST(81622.446368027333 / 8.0), + REAL_CONST(81644.983888102215 / 8.0), + REAL_CONST(81667.522963615178 / 8.0), + REAL_CONST(81690.063594351581 / 8.0), + REAL_CONST(81712.605780096841 / 8.0), + REAL_CONST(81735.149520636449 / 8.0), + REAL_CONST(81757.694815755967 / 8.0), + REAL_CONST(81780.241665241047 / 8.0), + REAL_CONST(81802.79006887741 / 8.0), + REAL_CONST(81825.340026450824 / 8.0), + REAL_CONST(81847.891537747171 / 8.0), + REAL_CONST(81870.444602552379 / 8.0), + REAL_CONST(81892.999220652477 / 8.0), + REAL_CONST(81915.555391833506 / 8.0), + REAL_CONST(81938.113115881672 / 8.0), + REAL_CONST(81960.672392583176 / 8.0), + REAL_CONST(81983.233221724338 / 8.0), + REAL_CONST(82005.795603091537 / 8.0), + REAL_CONST(82028.359536471224 / 8.0), + REAL_CONST(82050.925021649906 / 8.0), + REAL_CONST(82073.492058414209 / 8.0), + REAL_CONST(82096.060646550788 / 8.0), + REAL_CONST(82118.630785846399 / 8.0), + REAL_CONST(82141.202476087841 / 8.0), + REAL_CONST(82163.775717062032 / 8.0), + REAL_CONST(82186.35050855593 / 8.0), + REAL_CONST(82208.926850356569 / 8.0), + REAL_CONST(82231.504742251054 / 8.0), + REAL_CONST(82254.084184026578 / 8.0), + REAL_CONST(82276.665175470393 / 8.0), + REAL_CONST(82299.24771636985 / 8.0), + REAL_CONST(82321.831806512317 / 8.0), + REAL_CONST(82344.417445685307 / 8.0), + REAL_CONST(82367.004633676348 / 8.0), + REAL_CONST(82389.593370273054 / 8.0), + REAL_CONST(82412.183655263143 / 8.0), + REAL_CONST(82434.775488434374 / 8.0), + REAL_CONST(82457.368869574595 / 8.0), + REAL_CONST(82479.963798471697 / 8.0), + REAL_CONST(82502.560274913689 / 8.0), + REAL_CONST(82525.158298688606 / 8.0), + REAL_CONST(82547.757869584602 / 8.0), + REAL_CONST(82570.35898738986 / 8.0), + REAL_CONST(82592.961651892678 / 8.0), + REAL_CONST(82615.565862881398 / 8.0), + REAL_CONST(82638.171620144421 / 8.0), + REAL_CONST(82660.778923470265 / 8.0), + REAL_CONST(82683.387772647475 / 8.0), + REAL_CONST(82705.998167464713 / 8.0), + REAL_CONST(82728.610107710658 / 8.0), + REAL_CONST(82751.223593174116 / 8.0), + REAL_CONST(82773.83862364394 / 8.0), + REAL_CONST(82796.45519890904 / 8.0), + REAL_CONST(82819.073318758441 / 8.0), + REAL_CONST(82841.692982981185 / 8.0), + REAL_CONST(82864.314191366429 / 8.0), + REAL_CONST(82886.936943703375 / 8.0), + REAL_CONST(82909.561239781324 / 8.0), + REAL_CONST(82932.187079389638 / 8.0), + REAL_CONST(82954.814462317736 / 8.0), + REAL_CONST(82977.443388355125 / 8.0), + REAL_CONST(83000.073857291369 / 8.0), + REAL_CONST(83022.70586891612 / 8.0), + REAL_CONST(83045.339423019104 / 8.0), + REAL_CONST(83067.974519390089 / 8.0), + REAL_CONST(83090.611157818959 / 8.0), + REAL_CONST(83113.249338095629 / 8.0), + REAL_CONST(83135.8890600101 / 8.0), + REAL_CONST(83158.530323352461 / 8.0), + REAL_CONST(83181.173127912858 / 8.0), + REAL_CONST(83203.817473481497 / 8.0), + REAL_CONST(83226.463359848669 / 8.0), + REAL_CONST(83249.11078680474 / 8.0), + REAL_CONST(83271.759754140134 / 8.0), + REAL_CONST(83294.410261645375 / 8.0), + REAL_CONST(83317.062309111003 / 8.0), + REAL_CONST(83339.715896327703 / 8.0), + REAL_CONST(83362.371023086147 / 8.0), + REAL_CONST(83385.027689177165 / 8.0), + REAL_CONST(83407.685894391587 / 8.0), + REAL_CONST(83430.345638520361 / 8.0), + REAL_CONST(83453.006921354478 / 8.0), + REAL_CONST(83475.669742685001 / 8.0), + REAL_CONST(83498.334102303095 / 8.0), + REAL_CONST(83520.999999999942 / 8.0), + REAL_CONST(83543.667435566866 / 8.0), + REAL_CONST(83566.336408795192 / 8.0), + REAL_CONST(83589.006919476349 / 8.0), + REAL_CONST(83611.678967401851 / 8.0), + REAL_CONST(83634.352552363242 / 8.0), + REAL_CONST(83657.027674152167 / 8.0), + REAL_CONST(83679.704332560359 / 8.0), + REAL_CONST(83702.382527379552 / 8.0), + REAL_CONST(83725.062258401638 / 8.0), + REAL_CONST(83747.743525418511 / 8.0), + REAL_CONST(83770.42632822218 / 8.0), + REAL_CONST(83793.110666604684 / 8.0), + REAL_CONST(83815.796540358162 / 8.0), + REAL_CONST(83838.483949274829 / 8.0), + REAL_CONST(83861.172893146941 / 8.0), + REAL_CONST(83883.863371766842 / 8.0), + REAL_CONST(83906.555384926964 / 8.0), + REAL_CONST(83929.248932419752 / 8.0), + REAL_CONST(83951.944014037799 / 8.0), + REAL_CONST(83974.640629573696 / 8.0), + REAL_CONST(83997.338778820151 / 8.0), + REAL_CONST(84020.038461569929 / 8.0), + REAL_CONST(84042.739677615857 / 8.0), + REAL_CONST(84065.442426750829 / 8.0), + REAL_CONST(84088.146708767847 / 8.0), + REAL_CONST(84110.852523459922 / 8.0), + REAL_CONST(84133.559870620171 / 8.0), + REAL_CONST(84156.268750041796 / 8.0), + REAL_CONST(84178.979161518029 / 8.0), + REAL_CONST(84201.691104842204 / 8.0), + REAL_CONST(84224.404579807713 / 8.0), + REAL_CONST(84247.119586208006 / 8.0), + REAL_CONST(84269.83612383662 / 8.0), + REAL_CONST(84292.55419248715 / 8.0), + REAL_CONST(84315.273791953281 / 8.0), + REAL_CONST(84337.994922028738 / 8.0), + REAL_CONST(84360.717582507335 / 8.0), + REAL_CONST(84383.441773182945 / 8.0), + REAL_CONST(84406.167493849513 / 8.0), + REAL_CONST(84428.894744301069 / 8.0), + REAL_CONST(84451.623524331691 / 8.0), + REAL_CONST(84474.353833735542 / 8.0), + REAL_CONST(84497.085672306828 / 8.0), + REAL_CONST(84519.819039839858 / 8.0), + REAL_CONST(84542.553936128999 / 8.0), + REAL_CONST(84565.290360968676 / 8.0), + REAL_CONST(84588.028314153402 / 8.0), + REAL_CONST(84610.767795477717 / 8.0), + REAL_CONST(84633.508804736295 / 8.0), + REAL_CONST(84656.251341723822 / 8.0), + REAL_CONST(84678.995406235073 / 8.0), + REAL_CONST(84701.740998064924 / 8.0), + REAL_CONST(84724.488117008252 / 8.0), + REAL_CONST(84747.236762860062 / 8.0), + REAL_CONST(84769.986935415407 / 8.0), + REAL_CONST(84792.73863446941 / 8.0), + REAL_CONST(84815.491859817252 / 8.0), + REAL_CONST(84838.246611254188 / 8.0), + REAL_CONST(84861.002888575575 / 8.0), + REAL_CONST(84883.760691576768 / 8.0), + REAL_CONST(84906.520020053256 / 8.0), + REAL_CONST(84929.28087380057 / 8.0), + REAL_CONST(84952.043252614312 / 8.0), + REAL_CONST(84974.807156290146 / 8.0), + REAL_CONST(84997.572584623806 / 8.0), + REAL_CONST(85020.339537411113 / 8.0), + REAL_CONST(85043.108014447949 / 8.0), + REAL_CONST(85065.878015530237 / 8.0), + REAL_CONST(85088.649540453989 / 8.0), + REAL_CONST(85111.422589015303 / 8.0), + REAL_CONST(85134.197161010321 / 8.0), + REAL_CONST(85156.973256235244 / 8.0), + REAL_CONST(85179.750874486374 / 8.0), + REAL_CONST(85202.530015560071 / 8.0), + REAL_CONST(85225.310679252725 / 8.0), + REAL_CONST(85248.092865360857 / 8.0), + REAL_CONST(85270.876573681016 / 8.0), + REAL_CONST(85293.661804009811 / 8.0), + REAL_CONST(85316.448556143951 / 8.0), + REAL_CONST(85339.236829880188 / 8.0), + REAL_CONST(85362.026625015351 / 8.0), + REAL_CONST(85384.817941346351 / 8.0), + REAL_CONST(85407.610778670132 / 8.0), + REAL_CONST(85430.405136783724 / 8.0), + REAL_CONST(85453.201015484257 / 8.0), + REAL_CONST(85475.998414568865 / 8.0), + REAL_CONST(85498.797333834795 / 8.0), + REAL_CONST(85521.597773079353 / 8.0), + REAL_CONST(85544.399732099904 / 8.0), + REAL_CONST(85567.203210693886 / 8.0), + REAL_CONST(85590.008208658808 / 8.0), + REAL_CONST(85612.814725792239 / 8.0), + REAL_CONST(85635.62276189182 / 8.0), + REAL_CONST(85658.432316755265 / 8.0), + REAL_CONST(85681.243390180331 / 8.0), + REAL_CONST(85704.055981964877 / 8.0), + REAL_CONST(85726.870091906807 / 8.0), + REAL_CONST(85749.685719804082 / 8.0), + REAL_CONST(85772.502865454764 / 8.0), + REAL_CONST(85795.321528656961 / 8.0), + REAL_CONST(85818.141709208852 / 8.0), + REAL_CONST(85840.963406908675 / 8.0), + REAL_CONST(85863.78662155474 / 8.0), + REAL_CONST(85886.611352945445 / 8.0), + REAL_CONST(85909.437600879217 / 8.0), + REAL_CONST(85932.26536515457 / 8.0), + REAL_CONST(85955.094645570091 / 8.0), + REAL_CONST(85977.92544192441 / 8.0), + REAL_CONST(86000.757754016275 / 8.0), + REAL_CONST(86023.591581644432 / 8.0), + REAL_CONST(86046.426924607746 / 8.0), + REAL_CONST(86069.263782705122 / 8.0), + REAL_CONST(86092.102155735556 / 8.0), + REAL_CONST(86114.942043498071 / 8.0), + REAL_CONST(86137.783445791807 / 8.0), + REAL_CONST(86160.626362415918 / 8.0), + REAL_CONST(86183.470793169676 / 8.0), + REAL_CONST(86206.316737852379 / 8.0), + REAL_CONST(86229.164196263402 / 8.0), + REAL_CONST(86252.013168202204 / 8.0), + REAL_CONST(86274.863653468303 / 8.0), + REAL_CONST(86297.715651861261 / 8.0), + REAL_CONST(86320.569163180728 / 8.0), + REAL_CONST(86343.424187226425 / 8.0), + REAL_CONST(86366.280723798132 / 8.0), + REAL_CONST(86389.138772695675 / 8.0), + REAL_CONST(86411.998333718977 / 8.0), + REAL_CONST(86434.859406668009 / 8.0), + REAL_CONST(86457.721991342827 / 8.0), + REAL_CONST(86480.586087543532 / 8.0), + REAL_CONST(86503.451695070296 / 8.0), + REAL_CONST(86526.318813723352 / 8.0), + REAL_CONST(86549.187443303032 / 8.0), + REAL_CONST(86572.057583609683 / 8.0), + REAL_CONST(86594.929234443756 / 8.0), + REAL_CONST(86617.802395605773 / 8.0), + REAL_CONST(86640.677066896271 / 8.0), + REAL_CONST(86663.553248115903 / 8.0), + REAL_CONST(86686.43093906538 / 8.0), + REAL_CONST(86709.310139545443 / 8.0), + REAL_CONST(86732.190849356964 / 8.0), + REAL_CONST(86755.073068300815 / 8.0), + REAL_CONST(86777.956796177954 / 8.0), + REAL_CONST(86800.842032789442 / 8.0), + REAL_CONST(86823.728777936354 / 8.0), + REAL_CONST(86846.617031419853 / 8.0), + REAL_CONST(86869.506793041175 / 8.0), + REAL_CONST(86892.398062601613 / 8.0), + REAL_CONST(86915.290839902518 / 8.0), + REAL_CONST(86938.185124745316 / 8.0), + REAL_CONST(86961.080916931489 / 8.0), + REAL_CONST(86983.978216262592 / 8.0), + REAL_CONST(87006.87702254027 / 8.0), + REAL_CONST(87029.777335566177 / 8.0), + REAL_CONST(87052.67915514209 / 8.0), + REAL_CONST(87075.582481069796 / 8.0), + REAL_CONST(87098.487313151185 / 8.0), + REAL_CONST(87121.39365118822 / 8.0), + REAL_CONST(87144.301494982894 / 8.0), + REAL_CONST(87167.210844337285 / 8.0), + REAL_CONST(87190.121699053532 / 8.0), + REAL_CONST(87213.034058933845 / 8.0), + REAL_CONST(87235.947923780506 / 8.0), + REAL_CONST(87258.863293395829 / 8.0), + REAL_CONST(87281.780167582241 / 8.0), + REAL_CONST(87304.698546142172 / 8.0), + REAL_CONST(87327.618428878181 / 8.0), + REAL_CONST(87350.539815592856 / 8.0), + REAL_CONST(87373.462706088845 / 8.0), + REAL_CONST(87396.387100168897 / 8.0), + REAL_CONST(87419.312997635774 / 8.0), + REAL_CONST(87442.240398292357 / 8.0), + REAL_CONST(87465.16930194154 / 8.0), + REAL_CONST(87488.099708386319 / 8.0), + REAL_CONST(87511.031617429733 / 8.0), + REAL_CONST(87533.965028874911 / 8.0), + REAL_CONST(87556.899942525008 / 8.0), + REAL_CONST(87579.836358183282 / 8.0), + REAL_CONST(87602.774275653021 / 8.0), + REAL_CONST(87625.713694737613 / 8.0), + REAL_CONST(87648.654615240492 / 8.0), + REAL_CONST(87671.597036965148 / 8.0), + REAL_CONST(87694.540959715145 / 8.0), + REAL_CONST(87717.486383294105 / 8.0), + REAL_CONST(87740.433307505737 / 8.0), + REAL_CONST(87763.381732153779 / 8.0), + REAL_CONST(87786.331657042057 / 8.0), + REAL_CONST(87809.283081974456 / 8.0), + REAL_CONST(87832.236006754916 / 8.0), + REAL_CONST(87855.190431187453 / 8.0), + REAL_CONST(87878.146355076155 / 8.0), + REAL_CONST(87901.103778225151 / 8.0), + REAL_CONST(87924.062700438633 / 8.0), + REAL_CONST(87947.023121520891 / 8.0), + REAL_CONST(87969.985041276246 / 8.0), + REAL_CONST(87992.948459509105 / 8.0), + REAL_CONST(88015.913376023906 / 8.0), + REAL_CONST(88038.879790625171 / 8.0), + REAL_CONST(88061.847703117513 / 8.0), + REAL_CONST(88084.817113305573 / 8.0), + REAL_CONST(88107.788020994049 / 8.0), + REAL_CONST(88130.760425987726 / 8.0), + REAL_CONST(88153.734328091465 / 8.0), + REAL_CONST(88176.709727110137 / 8.0), + REAL_CONST(88199.686622848749 / 8.0), + REAL_CONST(88222.665015112303 / 8.0), + REAL_CONST(88245.644903705906 / 8.0), + REAL_CONST(88268.626288434709 / 8.0), + REAL_CONST(88291.609169103947 / 8.0), + REAL_CONST(88314.593545518903 / 8.0), + REAL_CONST(88337.579417484914 / 8.0), + REAL_CONST(88360.566784807408 / 8.0), + REAL_CONST(88383.555647291854 / 8.0), + REAL_CONST(88406.546004743795 / 8.0), + REAL_CONST(88429.537856968818 / 8.0), + REAL_CONST(88452.531203772611 / 8.0), + REAL_CONST(88475.52604496089 / 8.0), + REAL_CONST(88498.522380339447 / 8.0), + REAL_CONST(88521.52020971413 / 8.0), + REAL_CONST(88544.519532890874 / 8.0), + REAL_CONST(88567.520349675644 / 8.0), + REAL_CONST(88590.522659874507 / 8.0), + REAL_CONST(88613.526463293543 / 8.0), + REAL_CONST(88636.531759738922 / 8.0), + REAL_CONST(88659.538549016899 / 8.0), + REAL_CONST(88682.546830933745 / 8.0), + REAL_CONST(88705.556605295846 / 8.0), + REAL_CONST(88728.567871909589 / 8.0), + REAL_CONST(88751.580630581491 / 8.0), + REAL_CONST(88774.594881118086 / 8.0), + REAL_CONST(88797.610623325963 / 8.0), + REAL_CONST(88820.62785701183 / 8.0), + REAL_CONST(88843.646581982393 / 8.0), + REAL_CONST(88866.666798044462 / 8.0), + REAL_CONST(88889.688505004888 / 8.0), + REAL_CONST(88912.711702670611 / 8.0), + REAL_CONST(88935.7363908486 / 8.0), + REAL_CONST(88958.762569345898 / 8.0), + REAL_CONST(88981.790237969632 / 8.0), + REAL_CONST(89004.81939652696 / 8.0), + REAL_CONST(89027.850044825114 / 8.0), + REAL_CONST(89050.882182671412 / 8.0), + REAL_CONST(89073.9158098732 / 8.0), + REAL_CONST(89096.950926237885 / 8.0), + REAL_CONST(89119.987531572973 / 8.0), + REAL_CONST(89143.025625686001 / 8.0), + REAL_CONST(89166.065208384563 / 8.0), + REAL_CONST(89189.106279476357 / 8.0), + REAL_CONST(89212.148838769106 / 8.0), + REAL_CONST(89235.192886070581 / 8.0), + REAL_CONST(89258.238421188667 / 8.0), + REAL_CONST(89281.285443931265 / 8.0), + REAL_CONST(89304.333954106376 / 8.0), + REAL_CONST(89327.383951522017 / 8.0), + REAL_CONST(89350.435435986306 / 8.0), + REAL_CONST(89373.488407307406 / 8.0), + REAL_CONST(89396.542865293537 / 8.0), + REAL_CONST(89419.598809753006 / 8.0), + REAL_CONST(89442.656240494165 / 8.0), + REAL_CONST(89465.715157325409 / 8.0), + REAL_CONST(89488.775560055219 / 8.0), + REAL_CONST(89511.837448492137 / 8.0), + REAL_CONST(89534.900822444746 / 8.0), + REAL_CONST(89557.965681721733 / 8.0), + REAL_CONST(89581.032026131812 / 8.0), + REAL_CONST(89604.099855483742 / 8.0), + REAL_CONST(89627.169169586399 / 8.0), + REAL_CONST(89650.239968248672 / 8.0), + REAL_CONST(89673.312251279538 / 8.0), + REAL_CONST(89696.386018488018 / 8.0), + REAL_CONST(89719.461269683205 / 8.0), + REAL_CONST(89742.53800467425 / 8.0), + REAL_CONST(89765.616223270365 / 8.0), + REAL_CONST(89788.69592528083 / 8.0), + REAL_CONST(89811.777110514988 / 8.0), + REAL_CONST(89834.859778782207 / 8.0), + REAL_CONST(89857.943929891975 / 8.0), + REAL_CONST(89881.029563653807 / 8.0), + REAL_CONST(89904.116679877261 / 8.0), + REAL_CONST(89927.205278372014 / 8.0), + REAL_CONST(89950.29535894774 / 8.0), + REAL_CONST(89973.386921414218 / 8.0), + REAL_CONST(89996.479965581268 / 8.0), + REAL_CONST(90019.574491258769 / 8.0), + REAL_CONST(90042.670498256688 / 8.0), + REAL_CONST(90065.767986385021 / 8.0), + REAL_CONST(90088.866955453836 / 8.0), + REAL_CONST(90111.967405273259 / 8.0), + REAL_CONST(90135.069335653476 / 8.0), + REAL_CONST(90158.172746404758 / 8.0), + REAL_CONST(90181.277637337407 / 8.0), + REAL_CONST(90204.384008261797 / 8.0), + REAL_CONST(90227.49185898836 / 8.0), + REAL_CONST(90250.601189327586 / 8.0), + REAL_CONST(90273.711999090039 / 8.0), + REAL_CONST(90296.824288086325 / 8.0), + REAL_CONST(90319.938056127125 / 8.0), + REAL_CONST(90343.053303023189 / 8.0), + REAL_CONST(90366.170028585286 / 8.0), + REAL_CONST(90389.288232624298 / 8.0), + REAL_CONST(90412.407914951138 / 8.0), + REAL_CONST(90435.529075376777 / 8.0), + REAL_CONST(90458.651713712257 / 8.0), + REAL_CONST(90481.775829768681 / 8.0), + REAL_CONST(90504.901423357209 / 8.0), + REAL_CONST(90528.028494289058 / 8.0), + REAL_CONST(90551.157042375504 / 8.0), + REAL_CONST(90574.287067427911 / 8.0), + REAL_CONST(90597.418569257643 / 8.0), + REAL_CONST(90620.551547676194 / 8.0), + REAL_CONST(90643.686002495073 / 8.0), + REAL_CONST(90666.821933525847 / 8.0), + REAL_CONST(90689.959340580186 / 8.0), + REAL_CONST(90713.098223469773 / 8.0), + REAL_CONST(90736.238582006365 / 8.0), + REAL_CONST(90759.380416001804 / 8.0), + REAL_CONST(90782.523725267951 / 8.0), + REAL_CONST(90805.668509616764 / 8.0), + REAL_CONST(90828.814768860233 / 8.0), + REAL_CONST(90851.962502810435 / 8.0), + REAL_CONST(90875.11171127946 / 8.0), + REAL_CONST(90898.262394079517 / 8.0), + REAL_CONST(90921.414551022855 / 8.0), + REAL_CONST(90944.568181921743 / 8.0), + REAL_CONST(90967.72328658856 / 8.0), + REAL_CONST(90990.879864835719 / 8.0), + REAL_CONST(91014.037916475718 / 8.0), + REAL_CONST(91037.19744132107 / 8.0), + REAL_CONST(91060.358439184391 / 8.0), + REAL_CONST(91083.520909878338 / 8.0), + REAL_CONST(91106.684853215629 / 8.0), + REAL_CONST(91129.850269009039 / 8.0), + REAL_CONST(91153.017157071401 / 8.0), + REAL_CONST(91176.185517215621 / 8.0), + REAL_CONST(91199.355349254649 / 8.0), + REAL_CONST(91222.526653001492 / 8.0), + REAL_CONST(91245.699428269247 / 8.0), + REAL_CONST(91268.873674871036 / 8.0), + REAL_CONST(91292.049392620058 / 8.0), + REAL_CONST(91315.226581329553 / 8.0), + REAL_CONST(91338.405240812834 / 8.0), + REAL_CONST(91361.585370883287 / 8.0), + REAL_CONST(91384.766971354344 / 8.0), + REAL_CONST(91407.950042039476 / 8.0), + REAL_CONST(91431.134582752245 / 8.0), + REAL_CONST(91454.320593306256 / 8.0), + REAL_CONST(91477.508073515171 / 8.0), + REAL_CONST(91500.697023192712 / 8.0), + REAL_CONST(91523.887442152685 / 8.0), + REAL_CONST(91547.07933020893 / 8.0), + REAL_CONST(91570.272687175326 / 8.0), + REAL_CONST(91593.467512865856 / 8.0), + REAL_CONST(91616.663807094534 / 8.0), + REAL_CONST(91639.861569675442 / 8.0), + REAL_CONST(91663.060800422725 / 8.0), + REAL_CONST(91686.261499150554 / 8.0), + REAL_CONST(91709.463665673218 / 8.0), + REAL_CONST(91732.66729980502 / 8.0), + REAL_CONST(91755.872401360321 / 8.0), + REAL_CONST(91779.078970153569 / 8.0), + REAL_CONST(91802.287005999257 / 8.0), + REAL_CONST(91825.49650871192 / 8.0), + REAL_CONST(91848.707478106167 / 8.0), + REAL_CONST(91871.91991399668 / 8.0), + REAL_CONST(91895.133816198169 / 8.0), + REAL_CONST(91918.349184525418 / 8.0), + REAL_CONST(91941.566018793281 / 8.0), + REAL_CONST(91964.784318816659 / 8.0), + REAL_CONST(91988.004084410495 / 8.0), + REAL_CONST(92011.22531538982 / 8.0), + REAL_CONST(92034.448011569708 / 8.0), + REAL_CONST(92057.672172765277 / 8.0), + REAL_CONST(92080.897798791746 / 8.0), + REAL_CONST(92104.124889464365 / 8.0), + REAL_CONST(92127.353444598411 / 8.0), + REAL_CONST(92150.58346400928 / 8.0), + REAL_CONST(92173.814947512379 / 8.0), + REAL_CONST(92197.04789492322 / 8.0), + REAL_CONST(92220.282306057314 / 8.0), + REAL_CONST(92243.518180730272 / 8.0), + REAL_CONST(92266.755518757753 / 8.0), + REAL_CONST(92289.994319955469 / 8.0), + REAL_CONST(92313.234584139194 / 8.0), + REAL_CONST(92336.476311124774 / 8.0), + REAL_CONST(92359.719500728082 / 8.0), + REAL_CONST(92382.964152765067 / 8.0), + REAL_CONST(92406.210267051734 / 8.0), + REAL_CONST(92429.457843404161 / 8.0), + REAL_CONST(92452.706881638471 / 8.0), + REAL_CONST(92475.957381570814 / 8.0), + REAL_CONST(92499.209343017443 / 8.0), + REAL_CONST(92522.462765794655 / 8.0), + REAL_CONST(92545.717649718805 / 8.0), + REAL_CONST(92568.973994606305 / 8.0), + REAL_CONST(92592.231800273614 / 8.0), + REAL_CONST(92615.491066537259 / 8.0), + REAL_CONST(92638.751793213814 / 8.0), + REAL_CONST(92662.01398011994 / 8.0), + REAL_CONST(92685.277627072326 / 8.0), + REAL_CONST(92708.54273388772 / 8.0), + REAL_CONST(92731.809300382942 / 8.0), + REAL_CONST(92755.077326374871 / 8.0), + REAL_CONST(92778.346811680414 / 8.0), + REAL_CONST(92801.617756116568 / 8.0), + REAL_CONST(92824.890159500384 / 8.0), + REAL_CONST(92848.164021648947 / 8.0), + REAL_CONST(92871.439342379424 / 8.0), + REAL_CONST(92894.716121509016 / 8.0), + REAL_CONST(92917.994358855023 / 8.0), + REAL_CONST(92941.274054234746 / 8.0), + REAL_CONST(92964.555207465572 / 8.0), + REAL_CONST(92987.837818364962 / 8.0), + REAL_CONST(93011.121886750407 / 8.0), + REAL_CONST(93034.407412439468 / 8.0), + REAL_CONST(93057.694395249753 / 8.0), + REAL_CONST(93080.982834998955 / 8.0), + REAL_CONST(93104.272731504767 / 8.0), + REAL_CONST(93127.564084584999 / 8.0), + REAL_CONST(93150.856894057491 / 8.0), + REAL_CONST(93174.15115974014 / 8.0), + REAL_CONST(93197.446881450916 / 8.0), + REAL_CONST(93220.744059007804 / 8.0), + REAL_CONST(93244.04269222889 / 8.0), + REAL_CONST(93267.342780932304 / 8.0), + REAL_CONST(93290.644324936235 / 8.0), + REAL_CONST(93313.947324058914 / 8.0), + REAL_CONST(93337.251778118633 / 8.0), + REAL_CONST(93360.557686933767 / 8.0), + REAL_CONST(93383.865050322696 / 8.0), + REAL_CONST(93407.173868103928 / 8.0), + REAL_CONST(93430.484140095941 / 8.0), + REAL_CONST(93453.795866117362 / 8.0), + REAL_CONST(93477.109045986799 / 8.0), + REAL_CONST(93500.423679522952 / 8.0), + REAL_CONST(93523.739766544561 / 8.0), + REAL_CONST(93547.057306870454 / 8.0), + REAL_CONST(93570.376300319491 / 8.0), + REAL_CONST(93593.696746710571 / 8.0), + REAL_CONST(93617.018645862699 / 8.0), + REAL_CONST(93640.341997594893 / 8.0), + REAL_CONST(93663.666801726242 / 8.0), + REAL_CONST(93686.993058075881 / 8.0), + REAL_CONST(93710.320766463032 / 8.0), + REAL_CONST(93733.64992670693 / 8.0), + REAL_CONST(93756.980538626914 / 8.0), + REAL_CONST(93780.312602042337 / 8.0), + REAL_CONST(93803.646116772637 / 8.0), + REAL_CONST(93826.981082637285 / 8.0), + REAL_CONST(93850.317499455836 / 8.0), + REAL_CONST(93873.655367047861 / 8.0), + REAL_CONST(93896.994685233032 / 8.0), + REAL_CONST(93920.335453831038 / 8.0), + REAL_CONST(93943.677672661666 / 8.0), + REAL_CONST(93967.021341544707 / 8.0), + REAL_CONST(93990.366460300051 / 8.0), + REAL_CONST(94013.713028747632 / 8.0), + REAL_CONST(94037.061046707429 / 8.0), + REAL_CONST(94060.410513999494 / 8.0), + REAL_CONST(94083.761430443905 / 8.0), + REAL_CONST(94107.113795860845 / 8.0), + REAL_CONST(94130.467610070496 / 8.0), + REAL_CONST(94153.822872893157 / 8.0), + REAL_CONST(94177.179584149111 / 8.0), + REAL_CONST(94200.537743658759 / 8.0), + REAL_CONST(94223.897351242529 / 8.0), + REAL_CONST(94247.25840672091 / 8.0), + REAL_CONST(94270.620909914433 / 8.0), + REAL_CONST(94293.98486064373 / 8.0), + REAL_CONST(94317.350258729421 / 8.0), + REAL_CONST(94340.71710399224 / 8.0), + REAL_CONST(94364.085396252936 / 8.0), + REAL_CONST(94387.455135332348 / 8.0), + REAL_CONST(94410.82632105134 / 8.0), + REAL_CONST(94434.198953230851 / 8.0), + REAL_CONST(94457.573031691878 / 8.0), + REAL_CONST(94480.948556255447 / 8.0), + REAL_CONST(94504.325526742658 / 8.0), + REAL_CONST(94527.70394297468 / 8.0), + REAL_CONST(94551.083804772716 / 8.0), + REAL_CONST(94574.465111958023 / 8.0), + REAL_CONST(94597.847864351934 / 8.0), + REAL_CONST(94621.232061775823 / 8.0), + REAL_CONST(94644.617704051096 / 8.0), + REAL_CONST(94668.004790999272 / 8.0), + REAL_CONST(94691.393322441872 / 8.0), + REAL_CONST(94714.783298200506 / 8.0), + REAL_CONST(94738.174718096794 / 8.0), + REAL_CONST(94761.567581952477 / 8.0), + REAL_CONST(94784.961889589307 / 8.0), + REAL_CONST(94808.357640829097 / 8.0), + REAL_CONST(94831.754835493703 / 8.0), + REAL_CONST(94855.153473405066 / 8.0), + REAL_CONST(94878.553554385173 / 8.0), + REAL_CONST(94901.955078256055 / 8.0), + REAL_CONST(94925.358044839784 / 8.0), + REAL_CONST(94948.762453958523 / 8.0), + REAL_CONST(94972.168305434476 / 8.0), + REAL_CONST(94995.575599089891 / 8.0), + REAL_CONST(95018.984334747074 / 8.0), + REAL_CONST(95042.394512228391 / 8.0), + REAL_CONST(95065.806131356265 / 8.0), + REAL_CONST(95089.219191953176 / 8.0), + REAL_CONST(95112.633693841635 / 8.0), + REAL_CONST(95136.04963684424 / 8.0), + REAL_CONST(95159.467020783617 / 8.0), + REAL_CONST(95182.885845482466 / 8.0), + REAL_CONST(95206.306110763529 / 8.0), + REAL_CONST(95229.727816449609 / 8.0), + REAL_CONST(95253.150962363579 / 8.0), + REAL_CONST(95276.575548328314 / 8.0), + REAL_CONST(95300.001574166803 / 8.0), + REAL_CONST(95323.429039702052 / 8.0), + REAL_CONST(95346.857944757154 / 8.0), + REAL_CONST(95370.288289155214 / 8.0), + REAL_CONST(95393.720072719429 / 8.0), + REAL_CONST(95417.153295273019 / 8.0), + REAL_CONST(95440.587956639298 / 8.0), + REAL_CONST(95464.024056641589 / 8.0), + REAL_CONST(95487.461595103305 / 8.0), + REAL_CONST(95510.900571847902 / 8.0), + REAL_CONST(95534.340986698866 / 8.0), + REAL_CONST(95557.782839479783 / 8.0), + REAL_CONST(95581.226130014256 / 8.0), + REAL_CONST(95604.670858125959 / 8.0), + REAL_CONST(95628.117023638595 / 8.0), + REAL_CONST(95651.564626375985 / 8.0), + REAL_CONST(95675.013666161918 / 8.0), + REAL_CONST(95698.464142820303 / 8.0), + REAL_CONST(95721.916056175076 / 8.0), + REAL_CONST(95745.369406050231 / 8.0), + REAL_CONST(95768.824192269807 / 8.0), + REAL_CONST(95792.280414657915 / 8.0), + REAL_CONST(95815.738073038709 / 8.0), + REAL_CONST(95839.197167236387 / 8.0), + REAL_CONST(95862.657697075221 / 8.0), + REAL_CONST(95886.11966237954 / 8.0), + REAL_CONST(95909.583062973688 / 8.0), + REAL_CONST(95933.047898682111 / 8.0), + REAL_CONST(95956.514169329268 / 8.0), + REAL_CONST(95979.981874739708 / 8.0), + REAL_CONST(96003.451014738006 / 8.0), + REAL_CONST(96026.921589148798 / 8.0), + REAL_CONST(96050.393597796792 / 8.0), + REAL_CONST(96073.867040506724 / 8.0), + REAL_CONST(96097.341917103375 / 8.0), + REAL_CONST(96120.818227411626 / 8.0), + REAL_CONST(96144.295971256375 / 8.0), + REAL_CONST(96167.775148462577 / 8.0), + REAL_CONST(96191.255758855244 / 8.0), + REAL_CONST(96214.737802259449 / 8.0), + REAL_CONST(96238.221278500292 / 8.0), + REAL_CONST(96261.70618740299 / 8.0), + REAL_CONST(96285.192528792715 / 8.0), + REAL_CONST(96308.680302494788 / 8.0), + REAL_CONST(96332.169508334526 / 8.0), + REAL_CONST(96355.660146137321 / 8.0), + REAL_CONST(96379.152215728609 / 8.0), + REAL_CONST(96402.645716933868 / 8.0), + REAL_CONST(96426.14064957868 / 8.0), + REAL_CONST(96449.637013488609 / 8.0), + REAL_CONST(96473.134808489311 / 8.0), + REAL_CONST(96496.63403440651 / 8.0), + REAL_CONST(96520.134691065963 / 8.0), + REAL_CONST(96543.636778293469 / 8.0), + REAL_CONST(96567.140295914898 / 8.0), + REAL_CONST(96590.645243756153 / 8.0), + REAL_CONST(96614.151621643221 / 8.0), + REAL_CONST(96637.659429402134 / 8.0), + REAL_CONST(96661.168666858954 / 8.0), + REAL_CONST(96684.679333839798 / 8.0), + REAL_CONST(96708.191430170875 / 8.0), + REAL_CONST(96731.70495567839 / 8.0), + REAL_CONST(96755.219910188665 / 8.0), + REAL_CONST(96778.736293528011 / 8.0), + REAL_CONST(96802.254105522836 / 8.0), + REAL_CONST(96825.77334599958 / 8.0), + REAL_CONST(96849.29401478474 / 8.0), + REAL_CONST(96872.816111704873 / 8.0), + REAL_CONST(96896.339636586577 / 8.0), + REAL_CONST(96919.864589256511 / 8.0), + REAL_CONST(96943.390969541389 / 8.0), + REAL_CONST(96966.918777267958 / 8.0), + REAL_CONST(96990.448012263048 / 8.0), + REAL_CONST(97013.978674353522 / 8.0), + REAL_CONST(97037.510763366285 / 8.0), + REAL_CONST(97061.044279128328 / 8.0), + REAL_CONST(97084.579221466673 / 8.0), + REAL_CONST(97108.115590208385 / 8.0), + REAL_CONST(97131.653385180587 / 8.0), + REAL_CONST(97155.19260621049 / 8.0), + REAL_CONST(97178.733253125291 / 8.0), + REAL_CONST(97202.2753257523 / 8.0), + REAL_CONST(97225.81882391886 / 8.0), + REAL_CONST(97249.363747452342 / 8.0), + REAL_CONST(97272.910096180189 / 8.0), + REAL_CONST(97296.457869929916 / 8.0), + REAL_CONST(97320.007068529041 / 8.0), + REAL_CONST(97343.557691805196 / 8.0), + REAL_CONST(97367.109739586012 / 8.0), + REAL_CONST(97390.663211699197 / 8.0), + REAL_CONST(97414.218107972498 / 8.0), + REAL_CONST(97437.774428233737 / 8.0), + REAL_CONST(97461.332172310766 / 8.0), + REAL_CONST(97484.891340031507 / 8.0), + REAL_CONST(97508.451931223899 / 8.0), + REAL_CONST(97532.013945715982 / 8.0), + REAL_CONST(97555.577383335811 / 8.0), + REAL_CONST(97579.142243911512 / 8.0), + REAL_CONST(97602.708527271257 / 8.0), + REAL_CONST(97626.276233243261 / 8.0), + REAL_CONST(97649.845361655811 / 8.0), + REAL_CONST(97673.415912337223 / 8.0), + REAL_CONST(97696.987885115886 / 8.0), + REAL_CONST(97720.561279820206 / 8.0), + REAL_CONST(97744.1360962787 / 8.0), + REAL_CONST(97767.712334319876 / 8.0), + REAL_CONST(97791.289993772341 / 8.0), + REAL_CONST(97814.869074464703 / 8.0), + REAL_CONST(97838.449576225685 / 8.0), + REAL_CONST(97862.031498883996 / 8.0), + REAL_CONST(97885.614842268449 / 8.0), + REAL_CONST(97909.199606207883 / 8.0), + REAL_CONST(97932.785790531183 / 8.0), + REAL_CONST(97956.37339506732 / 8.0), + REAL_CONST(97979.962419645264 / 8.0), + REAL_CONST(98003.552864094076 / 8.0), + REAL_CONST(98027.144728242856 / 8.0), + REAL_CONST(98050.738011920766 / 8.0), + REAL_CONST(98074.332714956996 / 8.0), + REAL_CONST(98097.928837180807 / 8.0), + REAL_CONST(98121.526378421506 / 8.0), + REAL_CONST(98145.125338508456 / 8.0), + REAL_CONST(98168.725717271067 / 8.0), + REAL_CONST(98192.327514538789 / 8.0), + REAL_CONST(98215.930730141132 / 8.0), + REAL_CONST(98239.535363907664 / 8.0), + REAL_CONST(98263.141415668011 / 8.0), + REAL_CONST(98286.748885251814 / 8.0), + REAL_CONST(98310.357772488816 / 8.0), + REAL_CONST(98333.968077208759 / 8.0), + REAL_CONST(98357.579799241488 / 8.0), + REAL_CONST(98381.192938416847 / 8.0), + REAL_CONST(98404.807494564782 / 8.0), + REAL_CONST(98428.42346751524 / 8.0), + REAL_CONST(98452.040857098269 / 8.0), + REAL_CONST(98475.659663143917 / 8.0), + REAL_CONST(98499.27988548232 / 8.0), + REAL_CONST(98522.901523943656 / 8.0), + REAL_CONST(98546.524578358163 / 8.0), + REAL_CONST(98570.149048556093 / 8.0), + REAL_CONST(98593.774934367786 / 8.0), + REAL_CONST(98617.402235623624 / 8.0), + REAL_CONST(98641.030952154048 / 8.0), + REAL_CONST(98664.661083789513 / 8.0), + REAL_CONST(98688.292630360564 / 8.0), + REAL_CONST(98711.925591697771 / 8.0), + REAL_CONST(98735.559967631794 / 8.0), + REAL_CONST(98759.195757993293 / 8.0), + REAL_CONST(98782.832962613014 / 8.0), + REAL_CONST(98806.471581321734 / 8.0), + REAL_CONST(98830.111613950285 / 8.0), + REAL_CONST(98853.753060329575 / 8.0), + REAL_CONST(98877.39592029051 / 8.0), + REAL_CONST(98901.040193664099 / 8.0), + REAL_CONST(98924.68588028138 / 8.0), + REAL_CONST(98948.33297997342 / 8.0), + REAL_CONST(98971.981492571387 / 8.0), + REAL_CONST(98995.63141790645 / 8.0), + REAL_CONST(99019.282755809851 / 8.0), + REAL_CONST(99042.935506112874 / 8.0), + REAL_CONST(99066.589668646877 / 8.0), + REAL_CONST(99090.245243243233 / 8.0), + REAL_CONST(99113.902229733401 / 8.0), + REAL_CONST(99137.560627948857 / 8.0), + REAL_CONST(99161.220437721131 / 8.0), + REAL_CONST(99184.881658881859 / 8.0), + REAL_CONST(99208.544291262631 / 8.0), + REAL_CONST(99232.208334695169 / 8.0), + REAL_CONST(99255.87378901121 / 8.0), + REAL_CONST(99279.540654042547 / 8.0), + REAL_CONST(99303.208929621018 / 8.0), + REAL_CONST(99326.878615578535 / 8.0), + REAL_CONST(99350.549711746993 / 8.0), + REAL_CONST(99374.222217958435 / 8.0), + REAL_CONST(99397.896134044888 / 8.0), + REAL_CONST(99421.571459838422 / 8.0), + REAL_CONST(99445.248195171211 / 8.0), + REAL_CONST(99468.926339875441 / 8.0), + REAL_CONST(99492.605893783344 / 8.0), + REAL_CONST(99516.286856727209 / 8.0), + REAL_CONST(99539.969228539398 / 8.0), + REAL_CONST(99563.653009052287 / 8.0), + REAL_CONST(99587.338198098325 / 8.0), + REAL_CONST(99611.024795510006 / 8.0), + REAL_CONST(99634.712801119866 / 8.0), + REAL_CONST(99658.402214760499 / 8.0), + REAL_CONST(99682.093036264545 / 8.0), + REAL_CONST(99705.785265464699 / 8.0), + REAL_CONST(99729.478902193689 / 8.0), + REAL_CONST(99753.173946284325 / 8.0), + REAL_CONST(99776.870397569437 / 8.0), + REAL_CONST(99800.56825588191 / 8.0), + REAL_CONST(99824.267521054688 / 8.0), + REAL_CONST(99847.968192920773 / 8.0), + REAL_CONST(99871.670271313182 / 8.0), + REAL_CONST(99895.373756065004 / 8.0), + REAL_CONST(99919.078647009388 / 8.0), + REAL_CONST(99942.78494397951 / 8.0), + REAL_CONST(99966.492646808634 / 8.0), + REAL_CONST(99990.20175533001 / 8.0), + REAL_CONST(100013.91226937699 / 8.0), + REAL_CONST(100037.62418878295 / 8.0), + REAL_CONST(100061.33751338134 / 8.0), + REAL_CONST(100085.05224300563 / 8.0), + REAL_CONST(100108.76837748935 / 8.0), + REAL_CONST(100132.4859166661 / 8.0), + REAL_CONST(100156.2048603695 / 8.0), + REAL_CONST(100179.92520843323 / 8.0), + REAL_CONST(100203.64696069101 / 8.0), + REAL_CONST(100227.37011697664 / 8.0), + REAL_CONST(100251.09467712394 / 8.0), + REAL_CONST(100274.82064096678 / 8.0), + REAL_CONST(100298.54800833909 / 8.0), + REAL_CONST(100322.27677907483 / 8.0), + REAL_CONST(100346.00695300807 / 8.0), + REAL_CONST(100369.73852997283 / 8.0), + REAL_CONST(100393.47150980328 / 8.0), + REAL_CONST(100417.20589233354 / 8.0), + REAL_CONST(100440.94167739789 / 8.0), + REAL_CONST(100464.67886483055 / 8.0), + REAL_CONST(100488.41745446586 / 8.0), + REAL_CONST(100512.1574461382 / 8.0), + REAL_CONST(100535.89883968196 / 8.0), + REAL_CONST(100559.64163493161 / 8.0), + REAL_CONST(100583.38583172169 / 8.0), + REAL_CONST(100607.13142988674 / 8.0), + REAL_CONST(100630.87842926137 / 8.0), + REAL_CONST(100654.62682968024 / 8.0), + REAL_CONST(100678.37663097809 / 8.0), + REAL_CONST(100702.12783298964 / 8.0), + REAL_CONST(100725.88043554971 / 8.0), + REAL_CONST(100749.63443849317 / 8.0), + REAL_CONST(100773.38984165489 / 8.0), + REAL_CONST(100797.14664486986 / 8.0), + REAL_CONST(100820.90484797307 / 8.0), + REAL_CONST(100844.66445079957 / 8.0), + REAL_CONST(100868.42545318443 / 8.0), + REAL_CONST(100892.18785496285 / 8.0), + REAL_CONST(100915.95165596998 / 8.0), + REAL_CONST(100939.71685604109 / 8.0), + REAL_CONST(100963.48345501146 / 8.0), + REAL_CONST(100987.25145271645 / 8.0), + REAL_CONST(101011.02084899142 / 8.0), + REAL_CONST(101034.79164367182 / 8.0), + REAL_CONST(101058.56383659317 / 8.0), + REAL_CONST(101082.33742759094 / 8.0), + REAL_CONST(101106.11241650078 / 8.0), + REAL_CONST(101129.88880315828 / 8.0), + REAL_CONST(101153.66658739912 / 8.0), + REAL_CONST(101177.44576905905 / 8.0), + REAL_CONST(101201.22634797383 / 8.0), + REAL_CONST(101225.00832397929 / 8.0), + REAL_CONST(101248.7916969113 / 8.0), + REAL_CONST(101272.57646660579 / 8.0), + REAL_CONST(101296.36263289873 / 8.0), + REAL_CONST(101320.15019562612 / 8.0), + REAL_CONST(101343.93915462404 / 8.0), + REAL_CONST(101367.7295097286 / 8.0), + REAL_CONST(101391.52126077596 / 8.0), + REAL_CONST(101415.31440760233 / 8.0), + REAL_CONST(101439.10895004397 / 8.0), + REAL_CONST(101462.9048879372 / 8.0), + REAL_CONST(101486.70222111834 / 8.0), + REAL_CONST(101510.50094942382 / 8.0), + REAL_CONST(101534.30107269008 / 8.0), + REAL_CONST(101558.10259075361 / 8.0), + REAL_CONST(101581.90550345098 / 8.0), + REAL_CONST(101605.70981061876 / 8.0), + REAL_CONST(101629.5155120936 / 8.0), + REAL_CONST(101653.32260771218 / 8.0), + REAL_CONST(101677.13109731126 / 8.0), + REAL_CONST(101700.9409807276 / 8.0), + REAL_CONST(101724.75225779804 / 8.0), + REAL_CONST(101748.56492835947 / 8.0), + REAL_CONST(101772.37899224881 / 8.0), + REAL_CONST(101796.19444930303 / 8.0), + REAL_CONST(101820.01129935916 / 8.0), + REAL_CONST(101843.82954225427 / 8.0), + REAL_CONST(101867.64917782549 / 8.0), + REAL_CONST(101891.47020590997 / 8.0), + REAL_CONST(101915.29262634492 / 8.0), + REAL_CONST(101939.11643896763 / 8.0), + REAL_CONST(101962.94164361537 / 8.0), + REAL_CONST(101986.76824012553 / 8.0), + REAL_CONST(102010.59622833549 / 8.0), + REAL_CONST(102034.42560808272 / 8.0), + REAL_CONST(102058.25637920471 / 8.0), + REAL_CONST(102082.08854153901 / 8.0), + REAL_CONST(102105.9220949232 / 8.0), + REAL_CONST(102129.75703919494 / 8.0), + REAL_CONST(102153.59337419191 / 8.0), + REAL_CONST(102177.43109975185 / 8.0), + REAL_CONST(102201.27021571253 / 8.0), + REAL_CONST(102225.1107219118 / 8.0), + REAL_CONST(102248.95261818753 / 8.0), + REAL_CONST(102272.79590437764 / 8.0), + REAL_CONST(102296.64058032009 / 8.0), + REAL_CONST(102320.48664585294 / 8.0), + REAL_CONST(102344.33410081422 / 8.0), + REAL_CONST(102368.18294504205 / 8.0), + REAL_CONST(102392.03317837461 / 8.0), + REAL_CONST(102415.88480065008 / 8.0), + REAL_CONST(102439.73781170673 / 8.0), + REAL_CONST(102463.59221138287 / 8.0), + REAL_CONST(102487.44799951684 / 8.0), + REAL_CONST(102511.30517594704 / 8.0), + REAL_CONST(102535.1637405119 / 8.0), + REAL_CONST(102559.02369304992 / 8.0), + REAL_CONST(102582.88503339965 / 8.0), + REAL_CONST(102606.74776139967 / 8.0), + REAL_CONST(102630.61187688859 / 8.0), + REAL_CONST(102654.4773797051 / 8.0), + REAL_CONST(102678.34426968795 / 8.0), + REAL_CONST(102702.21254667587 / 8.0), + REAL_CONST(102726.08221050771 / 8.0), + REAL_CONST(102749.95326102231 / 8.0), + REAL_CONST(102773.8256980586 / 8.0), + REAL_CONST(102797.69952145554 / 8.0), + REAL_CONST(102821.57473105213 / 8.0), + REAL_CONST(102845.45132668741 / 8.0), + REAL_CONST(102869.32930820051 / 8.0), + REAL_CONST(102893.20867543056 / 8.0), + REAL_CONST(102917.08942821674 / 8.0), + REAL_CONST(102940.97156639832 / 8.0), + REAL_CONST(102964.85508981455 / 8.0), + REAL_CONST(102988.73999830478 / 8.0), + REAL_CONST(103012.6262917084 / 8.0), + REAL_CONST(103036.51396986481 / 8.0), + REAL_CONST(103060.40303261351 / 8.0), + REAL_CONST(103084.293479794 / 8.0), + REAL_CONST(103108.18531124585 / 8.0), + REAL_CONST(103132.07852680866 / 8.0), + REAL_CONST(103155.97312632212 / 8.0), + REAL_CONST(103179.8691096259 / 8.0), + REAL_CONST(103203.76647655977 / 8.0), + REAL_CONST(103227.66522696352 / 8.0), + REAL_CONST(103251.56536067701 / 8.0), + REAL_CONST(103275.46687754011 / 8.0), + REAL_CONST(103299.36977739276 / 8.0), + REAL_CONST(103323.27406007495 / 8.0), + REAL_CONST(103347.1797254267 / 8.0), + REAL_CONST(103371.0867732881 / 8.0), + REAL_CONST(103394.99520349925 / 8.0), + REAL_CONST(103418.90501590034 / 8.0), + REAL_CONST(103442.81621033157 / 8.0), + REAL_CONST(103466.72878663319 / 8.0), + REAL_CONST(103490.64274464553 / 8.0), + REAL_CONST(103514.55808420894 / 8.0), + REAL_CONST(103538.4748051638 / 8.0), + REAL_CONST(103562.39290735057 / 8.0), + REAL_CONST(103586.31239060973 / 8.0), + REAL_CONST(103610.23325478184 / 8.0), + REAL_CONST(103634.15549970744 / 8.0), + REAL_CONST(103658.07912522719 / 8.0), + REAL_CONST(103682.00413118176 / 8.0), + REAL_CONST(103705.93051741188 / 8.0), + REAL_CONST(103729.85828375829 / 8.0), + REAL_CONST(103753.78743006183 / 8.0), + REAL_CONST(103777.71795616332 / 8.0), + REAL_CONST(103801.64986190372 / 8.0), + REAL_CONST(103825.58314712394 / 8.0), + REAL_CONST(103849.51781166498 / 8.0), + REAL_CONST(103873.4538553679 / 8.0), + REAL_CONST(103897.39127807376 / 8.0), + REAL_CONST(103921.33007962372 / 8.0), + REAL_CONST(103945.27025985894 / 8.0), + REAL_CONST(103969.21181862066 / 8.0), + REAL_CONST(103993.15475575015 / 8.0), + REAL_CONST(104017.0990710887 / 8.0), + REAL_CONST(104041.0447644777 / 8.0), + REAL_CONST(104064.99183575854 / 8.0), + REAL_CONST(104088.94028477269 / 8.0), + REAL_CONST(104112.89011136163 / 8.0), + REAL_CONST(104136.84131536692 / 8.0), + REAL_CONST(104160.79389663014 / 8.0), + REAL_CONST(104184.74785499295 / 8.0), + REAL_CONST(104208.70319029699 / 8.0), + REAL_CONST(104232.65990238401 / 8.0), + REAL_CONST(104256.61799109577 / 8.0), + REAL_CONST(104280.57745627411 / 8.0), + REAL_CONST(104304.53829776087 / 8.0), + REAL_CONST(104328.50051539797 / 8.0), + REAL_CONST(104352.46410902737 / 8.0), + REAL_CONST(104376.42907849104 / 8.0), + REAL_CONST(104400.39542363105 / 8.0), + REAL_CONST(104424.36314428948 / 8.0), + REAL_CONST(104448.33224030846 / 8.0), + REAL_CONST(104472.3027115302 / 8.0), + REAL_CONST(104496.27455779689 / 8.0), + REAL_CONST(104520.24777895081 / 8.0), + REAL_CONST(104544.22237483428 / 8.0), + REAL_CONST(104568.19834528965 / 8.0), + REAL_CONST(104592.17569015936 / 8.0), + REAL_CONST(104616.15440928582 / 8.0), + REAL_CONST(104640.13450251156 / 8.0), + REAL_CONST(104664.1159696791 / 8.0), + REAL_CONST(104688.09881063103 / 8.0), + REAL_CONST(104712.08302520998 / 8.0), + REAL_CONST(104736.06861325864 / 8.0), + REAL_CONST(104760.05557461972 / 8.0), + REAL_CONST(104784.043909136 / 8.0), + REAL_CONST(104808.03361665027 / 8.0), + REAL_CONST(104832.0246970054 / 8.0), + REAL_CONST(104856.01715004431 / 8.0), + REAL_CONST(104880.01097560991 / 8.0), + REAL_CONST(104904.00617354522 / 8.0), + REAL_CONST(104928.00274369326 / 8.0), + REAL_CONST(104952.00068589712 / 8.0), + REAL_CONST(104975.99999999993 / 8.0), + REAL_CONST(105000.00068584486 / 8.0), + REAL_CONST(105024.00274327511 / 8.0), + REAL_CONST(105048.00617213396 / 8.0), + REAL_CONST(105072.0109722647 / 8.0), + REAL_CONST(105096.0171435107 / 8.0), + REAL_CONST(105120.02468571534 / 8.0), + REAL_CONST(105144.03359872208 / 8.0), + REAL_CONST(105168.04388237436 / 8.0), + REAL_CONST(105192.05553651576 / 8.0), + REAL_CONST(105216.06856098982 / 8.0), + REAL_CONST(105240.08295564017 / 8.0), + REAL_CONST(105264.09872031047 / 8.0), + REAL_CONST(105288.11585484444 / 8.0), + REAL_CONST(105312.13435908582 / 8.0), + REAL_CONST(105336.1542328784 / 8.0), + REAL_CONST(105360.17547606604 / 8.0), + REAL_CONST(105384.19808849262 / 8.0), + REAL_CONST(105408.22207000206 / 8.0), + REAL_CONST(105432.24742043833 / 8.0), + REAL_CONST(105456.27413964548 / 8.0), + REAL_CONST(105480.30222746753 / 8.0), + REAL_CONST(105504.33168374863 / 8.0), + REAL_CONST(105528.36250833291 / 8.0), + REAL_CONST(105552.39470106458 / 8.0), + REAL_CONST(105576.42826178786 / 8.0), + REAL_CONST(105600.46319034706 / 8.0), + REAL_CONST(105624.49948658649 / 8.0), + REAL_CONST(105648.53715035053 / 8.0), + REAL_CONST(105672.5761814836 / 8.0), + REAL_CONST(105696.61657983017 / 8.0), + REAL_CONST(105720.65834523473 / 8.0), + REAL_CONST(105744.70147754184 / 8.0), + REAL_CONST(105768.7459765961 / 8.0), + REAL_CONST(105792.79184224214 / 8.0), + REAL_CONST(105816.83907432464 / 8.0), + REAL_CONST(105840.88767268835 / 8.0), + REAL_CONST(105864.93763717801 / 8.0), + REAL_CONST(105888.98896763846 / 8.0), + REAL_CONST(105913.04166391456 / 8.0), + REAL_CONST(105937.09572585119 / 8.0), + REAL_CONST(105961.15115329332 / 8.0), + REAL_CONST(105985.20794608595 / 8.0), + REAL_CONST(106009.26610407409 / 8.0), + REAL_CONST(106033.32562710284 / 8.0), + REAL_CONST(106057.38651501729 / 8.0), + REAL_CONST(106081.44876766266 / 8.0), + REAL_CONST(106105.51238488412 / 8.0), + REAL_CONST(106129.57736652695 / 8.0), + REAL_CONST(106153.64371243643 / 8.0), + REAL_CONST(106177.71142245791 / 8.0), + REAL_CONST(106201.78049643678 / 8.0), + REAL_CONST(106225.85093421848 / 8.0), + REAL_CONST(106249.92273564848 / 8.0), + REAL_CONST(106273.99590057228 / 8.0), + REAL_CONST(106298.07042883546 / 8.0), + REAL_CONST(106322.14632028362 / 8.0), + REAL_CONST(106346.22357476239 / 8.0), + REAL_CONST(106370.30219211751 / 8.0), + REAL_CONST(106394.38217219469 / 8.0), + REAL_CONST(106418.46351483969 / 8.0), + REAL_CONST(106442.54621989837 / 8.0), + REAL_CONST(106466.63028721658 / 8.0), + REAL_CONST(106490.71571664025 / 8.0), + REAL_CONST(106514.80250801529 / 8.0), + REAL_CONST(106538.89066118775 / 8.0), + REAL_CONST(106562.98017600364 / 8.0), + REAL_CONST(106587.07105230905 / 8.0), + REAL_CONST(106611.16328995011 / 8.0), + REAL_CONST(106635.25688877302 / 8.0), + REAL_CONST(106659.35184862395 / 8.0), + REAL_CONST(106683.44816934918 / 8.0), + REAL_CONST(106707.54585079502 / 8.0), + REAL_CONST(106731.64489280782 / 8.0), + REAL_CONST(106755.74529523395 / 8.0), + REAL_CONST(106779.84705791986 / 8.0), + REAL_CONST(106803.95018071201 / 8.0), + REAL_CONST(106828.05466345693 / 8.0), + REAL_CONST(106852.16050600118 / 8.0), + REAL_CONST(106876.26770819137 / 8.0), + REAL_CONST(106900.37626987413 / 8.0), + REAL_CONST(106924.48619089619 / 8.0), + REAL_CONST(106948.59747110425 / 8.0), + REAL_CONST(106972.71011034511 / 8.0), + REAL_CONST(106996.82410846559 / 8.0), + REAL_CONST(107020.93946531253 / 8.0), + REAL_CONST(107045.05618073288 / 8.0), + REAL_CONST(107069.17425457356 / 8.0), + REAL_CONST(107093.29368668159 / 8.0), + REAL_CONST(107117.41447690397 / 8.0), + REAL_CONST(107141.53662508781 / 8.0), + REAL_CONST(107165.66013108024 / 8.0), + REAL_CONST(107189.7849947284 / 8.0), + REAL_CONST(107213.91121587952 / 8.0), + REAL_CONST(107238.03879438085 / 8.0), + REAL_CONST(107262.16773007967 / 8.0), + REAL_CONST(107286.29802282334 / 8.0), + REAL_CONST(107310.42967245923 / 8.0), + REAL_CONST(107334.56267883476 / 8.0), + REAL_CONST(107358.69704179741 / 8.0), + REAL_CONST(107382.83276119467 / 8.0), + REAL_CONST(107406.96983687414 / 8.0), + REAL_CONST(107431.10826868335 / 8.0), + REAL_CONST(107455.24805646999 / 8.0), + REAL_CONST(107479.38920008171 / 8.0), + REAL_CONST(107503.53169936626 / 8.0), + REAL_CONST(107527.67555417139 / 8.0), + REAL_CONST(107551.82076434491 / 8.0), + REAL_CONST(107575.96732973469 / 8.0), + REAL_CONST(107600.11525018861 / 8.0), + REAL_CONST(107624.26452555459 / 8.0), + REAL_CONST(107648.41515568066 / 8.0), + REAL_CONST(107672.56714041479 / 8.0), + REAL_CONST(107696.72047960508 / 8.0), + REAL_CONST(107720.87517309963 / 8.0), + REAL_CONST(107745.03122074658 / 8.0), + REAL_CONST(107769.18862239413 / 8.0), + REAL_CONST(107793.34737789053 / 8.0), + REAL_CONST(107817.50748708403 / 8.0), + REAL_CONST(107841.66894982298 / 8.0), + REAL_CONST(107865.83176595572 / 8.0), + REAL_CONST(107889.99593533068 / 8.0), + REAL_CONST(107914.16145779629 / 8.0), + REAL_CONST(107938.32833320105 / 8.0), + REAL_CONST(107962.49656139348 / 8.0), + REAL_CONST(107986.66614222217 / 8.0), + REAL_CONST(108010.83707553572 / 8.0), + REAL_CONST(108035.00936118282 / 8.0), + REAL_CONST(108059.18299901215 / 8.0), + REAL_CONST(108083.35798887245 / 8.0), + REAL_CONST(108107.53433061253 / 8.0), + REAL_CONST(108131.71202408121 / 8.0), + REAL_CONST(108155.89106912735 / 8.0), + REAL_CONST(108180.07146559987 / 8.0), + REAL_CONST(108204.25321334775 / 8.0), + REAL_CONST(108228.43631221994 / 8.0), + REAL_CONST(108252.62076206553 / 8.0), + REAL_CONST(108276.80656273357 / 8.0), + REAL_CONST(108300.99371407321 / 8.0), + REAL_CONST(108325.18221593359 / 8.0), + REAL_CONST(108349.37206816394 / 8.0), + REAL_CONST(108373.56327061349 / 8.0), + REAL_CONST(108397.75582313156 / 8.0), + REAL_CONST(108421.94972556747 / 8.0), + REAL_CONST(108446.1449777706 / 8.0), + REAL_CONST(108470.34157959036 / 8.0), + REAL_CONST(108494.53953087622 / 8.0), + REAL_CONST(108518.73883147769 / 8.0), + REAL_CONST(108542.93948124432 / 8.0), + REAL_CONST(108567.14148002568 / 8.0), + REAL_CONST(108591.34482767139 / 8.0), + REAL_CONST(108615.54952403114 / 8.0), + REAL_CONST(108639.75556895464 / 8.0), + REAL_CONST(108663.96296229165 / 8.0), + REAL_CONST(108688.17170389196 / 8.0), + REAL_CONST(108712.38179360541 / 8.0), + REAL_CONST(108736.59323128188 / 8.0), + REAL_CONST(108760.80601677128 / 8.0), + REAL_CONST(108785.02014992358 / 8.0), + REAL_CONST(108809.23563058881 / 8.0), + REAL_CONST(108833.45245861699 / 8.0), + REAL_CONST(108857.67063385822 / 8.0), + REAL_CONST(108881.89015616261 / 8.0), + REAL_CONST(108906.11102538036 / 8.0), + REAL_CONST(108930.33324136167 / 8.0), + REAL_CONST(108954.55680395682 / 8.0), + REAL_CONST(108978.78171301607 / 8.0), + REAL_CONST(109003.00796838976 / 8.0), + REAL_CONST(109027.23556992831 / 8.0), + REAL_CONST(109051.46451748211 / 8.0), + REAL_CONST(109075.69481090162 / 8.0), + REAL_CONST(109099.92645003737 / 8.0), + REAL_CONST(109124.15943473989 / 8.0), + REAL_CONST(109148.39376485976 / 8.0), + REAL_CONST(109172.62944024763 / 8.0), + REAL_CONST(109196.86646075416 / 8.0), + REAL_CONST(109221.10482623006 / 8.0), + REAL_CONST(109245.34453652608 / 8.0), + REAL_CONST(109269.58559149304 / 8.0), + REAL_CONST(109293.82799098175 / 8.0), + REAL_CONST(109318.07173484311 / 8.0), + REAL_CONST(109342.31682292801 / 8.0), + REAL_CONST(109366.56325508743 / 8.0), + REAL_CONST(109390.81103117237 / 8.0), + REAL_CONST(109415.06015103387 / 8.0), + REAL_CONST(109439.31061452301 / 8.0), + REAL_CONST(109463.56242149093 / 8.0), + REAL_CONST(109487.8155717888 / 8.0), + REAL_CONST(109512.07006526781 / 8.0), + REAL_CONST(109536.3259017792 / 8.0), + REAL_CONST(109560.58308117429 / 8.0), + REAL_CONST(109584.8416033044 / 8.0), + REAL_CONST(109609.1014680209 / 8.0), + REAL_CONST(109633.36267517522 / 8.0), + REAL_CONST(109657.62522461878 / 8.0), + REAL_CONST(109681.88911620311 / 8.0), + REAL_CONST(109706.15434977971 / 8.0), + REAL_CONST(109730.4209252002 / 8.0), + REAL_CONST(109754.68884231619 / 8.0), + REAL_CONST(109778.95810097932 / 8.0), + REAL_CONST(109803.22870104131 / 8.0), + REAL_CONST(109827.50064235389 / 8.0), + REAL_CONST(109851.77392476884 / 8.0), + REAL_CONST(109876.04854813802 / 8.0), + REAL_CONST(109900.32451231324 / 8.0), + REAL_CONST(109924.60181714644 / 8.0), + REAL_CONST(109948.88046248957 / 8.0), + REAL_CONST(109973.1604481946 / 8.0), + REAL_CONST(109997.44177411357 / 8.0), + REAL_CONST(110021.72444009855 / 8.0), + REAL_CONST(110046.00844600165 / 8.0), + REAL_CONST(110070.29379167501 / 8.0), + REAL_CONST(110094.58047697082 / 8.0), + REAL_CONST(110118.86850174134 / 8.0), + REAL_CONST(110143.15786583882 / 8.0), + REAL_CONST(110167.44856911557 / 8.0), + REAL_CONST(110191.74061142397 / 8.0), + REAL_CONST(110216.03399261639 / 8.0), + REAL_CONST(110240.32871254528 / 8.0), + REAL_CONST(110264.62477106311 / 8.0), + REAL_CONST(110288.9221680224 / 8.0), + REAL_CONST(110313.22090327571 / 8.0), + REAL_CONST(110337.52097667565 / 8.0), + REAL_CONST(110361.82238807483 / 8.0), + REAL_CONST(110386.12513732594 / 8.0), + REAL_CONST(110410.42922428172 / 8.0), + REAL_CONST(110434.73464879491 / 8.0), + REAL_CONST(110459.04141071832 / 8.0), + REAL_CONST(110483.34950990479 / 8.0), + REAL_CONST(110507.6589462072 / 8.0), + REAL_CONST(110531.96971947847 / 8.0), + REAL_CONST(110556.28182957157 / 8.0), + REAL_CONST(110580.5952763395 / 8.0), + REAL_CONST(110604.91005963532 / 8.0), + REAL_CONST(110629.22617931209 / 8.0), + REAL_CONST(110653.54363522294 / 8.0), + REAL_CONST(110677.86242722106 / 8.0), + REAL_CONST(110702.18255515963 / 8.0), + REAL_CONST(110726.50401889188 / 8.0), + REAL_CONST(110750.82681827113 / 8.0), + REAL_CONST(110775.1509531507 / 8.0), + REAL_CONST(110799.47642338395 / 8.0), + REAL_CONST(110823.80322882428 / 8.0), + REAL_CONST(110848.13136932514 / 8.0), + REAL_CONST(110872.46084474004 / 8.0), + REAL_CONST(110896.79165492248 / 8.0), + REAL_CONST(110921.12379972603 / 8.0), + REAL_CONST(110945.4572790043 / 8.0), + REAL_CONST(110969.79209261097 / 8.0), + REAL_CONST(110994.12824039967 / 8.0), + REAL_CONST(111018.46572222417 / 8.0), + REAL_CONST(111042.80453793822 / 8.0), + REAL_CONST(111067.14468739564 / 8.0), + REAL_CONST(111091.48617045028 / 8.0), + REAL_CONST(111115.82898695602 / 8.0), + REAL_CONST(111140.1731367668 / 8.0), + REAL_CONST(111164.51861973655 / 8.0), + REAL_CONST(111188.86543571933 / 8.0), + REAL_CONST(111213.21358456917 / 8.0), + REAL_CONST(111237.56306614014 / 8.0), + REAL_CONST(111261.91388028639 / 8.0), + REAL_CONST(111286.26602686207 / 8.0), + REAL_CONST(111310.61950572141 / 8.0), + REAL_CONST(111334.97431671864 / 8.0), + REAL_CONST(111359.33045970804 / 8.0), + REAL_CONST(111383.68793454397 / 8.0), + REAL_CONST(111408.04674108078 / 8.0), + REAL_CONST(111432.40687917286 / 8.0), + REAL_CONST(111456.76834867468 / 8.0), + REAL_CONST(111481.13114944073 / 8.0), + REAL_CONST(111505.49528132551 / 8.0), + REAL_CONST(111529.86074418361 / 8.0), + REAL_CONST(111554.22753786964 / 8.0), + REAL_CONST(111578.59566223821 / 8.0), + REAL_CONST(111602.96511714405 / 8.0), + REAL_CONST(111627.33590244185 / 8.0), + REAL_CONST(111651.7080179864 / 8.0), + REAL_CONST(111676.08146363248 / 8.0), + REAL_CONST(111700.45623923496 / 8.0), + REAL_CONST(111724.8323446487 / 8.0), + REAL_CONST(111749.20977972864 / 8.0), + REAL_CONST(111773.58854432974 / 8.0), + REAL_CONST(111797.96863830699 / 8.0), + REAL_CONST(111822.35006151545 / 8.0), + REAL_CONST(111846.73281381019 / 8.0), + REAL_CONST(111871.11689504632 / 8.0), + REAL_CONST(111895.50230507903 / 8.0), + REAL_CONST(111919.8890437635 / 8.0), + REAL_CONST(111944.27711095495 / 8.0), + REAL_CONST(111968.6665065087 / 8.0), + REAL_CONST(111993.05723028004 / 8.0), + REAL_CONST(112017.44928212435 / 8.0), + REAL_CONST(112041.842661897 / 8.0), + REAL_CONST(112066.23736945343 / 8.0), + REAL_CONST(112090.63340464912 / 8.0), + REAL_CONST(112115.03076733962 / 8.0), + REAL_CONST(112139.42945738042 / 8.0), + REAL_CONST(112163.82947462716 / 8.0), + REAL_CONST(112188.23081893545 / 8.0), + REAL_CONST(112212.63349016097 / 8.0), + REAL_CONST(112237.03748815943 / 8.0), + REAL_CONST(112261.44281278658 / 8.0), + REAL_CONST(112285.84946389822 / 8.0), + REAL_CONST(112310.25744135017 / 8.0), + REAL_CONST(112334.66674499828 / 8.0), + REAL_CONST(112359.07737469849 / 8.0), + REAL_CONST(112383.48933030672 / 8.0), + REAL_CONST(112407.90261167898 / 8.0), + REAL_CONST(112432.31721867126 / 8.0), + REAL_CONST(112456.73315113965 / 8.0), + REAL_CONST(112481.15040894024 / 8.0), + REAL_CONST(112505.56899192919 / 8.0), + REAL_CONST(112529.98889996267 / 8.0), + REAL_CONST(112554.41013289688 / 8.0), + REAL_CONST(112578.8326905881 / 8.0), + REAL_CONST(112603.25657289263 / 8.0), + REAL_CONST(112627.68177966679 / 8.0), + REAL_CONST(112652.10831076698 / 8.0), + REAL_CONST(112676.53616604958 / 8.0), + REAL_CONST(112700.96534537108 / 8.0), + REAL_CONST(112725.39584858794 / 8.0), + REAL_CONST(112749.82767555672 / 8.0), + REAL_CONST(112774.26082613398 / 8.0), + REAL_CONST(112798.6953001763 / 8.0), + REAL_CONST(112823.13109754038 / 8.0), + REAL_CONST(112847.56821808286 / 8.0), + REAL_CONST(112872.00666166049 / 8.0), + REAL_CONST(112896.44642813003 / 8.0), + REAL_CONST(112920.88751734827 / 8.0), + REAL_CONST(112945.32992917208 / 8.0), + REAL_CONST(112969.77366345831 / 8.0), + REAL_CONST(112994.21872006389 / 8.0), + REAL_CONST(113018.66509884578 / 8.0), + REAL_CONST(113043.11279966099 / 8.0), + REAL_CONST(113067.56182236652 / 8.0), + REAL_CONST(113092.01216681948 / 8.0), + REAL_CONST(113116.46383287695 / 8.0), + REAL_CONST(113140.9168203961 / 8.0), + REAL_CONST(113165.37112923413 / 8.0), + REAL_CONST(113189.82675924824 / 8.0), + REAL_CONST(113214.28371029573 / 8.0), + REAL_CONST(113238.74198223387 / 8.0), + REAL_CONST(113263.20157492002 / 8.0), + REAL_CONST(113287.66248821157 / 8.0), + REAL_CONST(113312.12472196593 / 8.0), + REAL_CONST(113336.58827604055 / 8.0), + REAL_CONST(113361.05315029295 / 8.0), + REAL_CONST(113385.51934458067 / 8.0), + REAL_CONST(113409.98685876124 / 8.0), + REAL_CONST(113434.45569269233 / 8.0), + REAL_CONST(113458.92584623155 / 8.0), + REAL_CONST(113483.39731923661 / 8.0), + REAL_CONST(113507.87011156522 / 8.0), + REAL_CONST(113532.34422307517 / 8.0), + REAL_CONST(113556.81965362425 / 8.0), + REAL_CONST(113581.2964030703 / 8.0), + REAL_CONST(113605.77447127122 / 8.0), + REAL_CONST(113630.25385808491 / 8.0), + REAL_CONST(113654.73456336933 / 8.0), + REAL_CONST(113679.2165869825 / 8.0), + REAL_CONST(113703.69992878241 / 8.0), + REAL_CONST(113728.18458862718 / 8.0), + REAL_CONST(113752.67056637487 / 8.0), + REAL_CONST(113777.15786188368 / 8.0), + REAL_CONST(113801.64647501177 / 8.0), + REAL_CONST(113826.13640561736 / 8.0), + REAL_CONST(113850.62765355874 / 8.0), + REAL_CONST(113875.12021869418 / 8.0), + REAL_CONST(113899.61410088204 / 8.0), + REAL_CONST(113924.1092999807 / 8.0), + REAL_CONST(113948.60581584855 / 8.0), + REAL_CONST(113973.10364834407 / 8.0), + REAL_CONST(113997.60279732574 / 8.0), + REAL_CONST(114022.1032626521 / 8.0), + REAL_CONST(114046.60504418171 / 8.0), + REAL_CONST(114071.10814177318 / 8.0), + REAL_CONST(114095.61255528514 / 8.0), + REAL_CONST(114120.11828457628 / 8.0), + REAL_CONST(114144.62532950533 / 8.0), + REAL_CONST(114169.13368993104 / 8.0), + REAL_CONST(114193.6433657122 / 8.0), + REAL_CONST(114218.15435670764 / 8.0), + REAL_CONST(114242.66666277625 / 8.0), + REAL_CONST(114267.18028377694 / 8.0), + REAL_CONST(114291.69521956862 / 8.0), + REAL_CONST(114316.21147001031 / 8.0), + REAL_CONST(114340.72903496103 / 8.0), + REAL_CONST(114365.24791427983 / 8.0), + REAL_CONST(114389.7681078258 / 8.0), + REAL_CONST(114414.2896154581 / 8.0), + REAL_CONST(114438.81243703589 / 8.0), + REAL_CONST(114463.33657241837 / 8.0), + REAL_CONST(114487.8620214648 / 8.0), + REAL_CONST(114512.38878403447 / 8.0), + REAL_CONST(114536.91685998671 / 8.0), + REAL_CONST(114561.44624918087 / 8.0), + REAL_CONST(114585.97695147636 / 8.0), + REAL_CONST(114610.5089667326 / 8.0), + REAL_CONST(114635.04229480909 / 8.0), + REAL_CONST(114659.57693556532 / 8.0), + REAL_CONST(114684.11288886084 / 8.0), + REAL_CONST(114708.65015455526 / 8.0), + REAL_CONST(114733.18873250818 / 8.0), + REAL_CONST(114757.72862257928 / 8.0), + REAL_CONST(114782.26982462825 / 8.0), + REAL_CONST(114806.81233851484 / 8.0), + REAL_CONST(114831.35616409882 / 8.0), + REAL_CONST(114855.90130123998 / 8.0), + REAL_CONST(114880.44774979822 / 8.0), + REAL_CONST(114904.99550963337 / 8.0), + REAL_CONST(114929.5445806054 / 8.0), + REAL_CONST(114954.09496257425 / 8.0), + REAL_CONST(114978.64665539992 / 8.0), + REAL_CONST(115003.19965894247 / 8.0), + REAL_CONST(115027.75397306195 / 8.0), + REAL_CONST(115052.30959761847 / 8.0), + REAL_CONST(115076.86653247218 / 8.0), + REAL_CONST(115101.42477748329 / 8.0), + REAL_CONST(115125.984332512 / 8.0), + REAL_CONST(115150.54519741859 / 8.0), + REAL_CONST(115175.10737206334 / 8.0), + REAL_CONST(115199.67085630659 / 8.0), + REAL_CONST(115224.23565000873 / 8.0), + REAL_CONST(115248.80175303014 / 8.0), + REAL_CONST(115273.3691652313 / 8.0), + REAL_CONST(115297.93788647266 / 8.0), + REAL_CONST(115322.50791661476 / 8.0), + REAL_CONST(115347.07925551817 / 8.0), + REAL_CONST(115371.65190304347 / 8.0), + REAL_CONST(115396.22585905129 / 8.0), + REAL_CONST(115420.80112340231 / 8.0), + REAL_CONST(115445.37769595724 / 8.0), + REAL_CONST(115469.95557657682 / 8.0), + REAL_CONST(115494.53476512182 / 8.0), + REAL_CONST(115519.11526145306 / 8.0), + REAL_CONST(115543.69706543141 / 8.0), + REAL_CONST(115568.28017691776 / 8.0), + REAL_CONST(115592.86459577303 / 8.0), + REAL_CONST(115617.4503218582 / 8.0), + REAL_CONST(115642.03735503425 / 8.0), + REAL_CONST(115666.62569516223 / 8.0), + REAL_CONST(115691.21534210323 / 8.0), + REAL_CONST(115715.80629571836 / 8.0), + REAL_CONST(115740.39855586876 / 8.0), + REAL_CONST(115764.99212241563 / 8.0), + REAL_CONST(115789.58699522018 / 8.0), + REAL_CONST(115814.18317414368 / 8.0), + REAL_CONST(115838.78065904744 / 8.0), + REAL_CONST(115863.37944979276 / 8.0), + REAL_CONST(115887.97954624105 / 8.0), + REAL_CONST(115912.5809482537 / 8.0), + REAL_CONST(115937.18365569216 / 8.0), + REAL_CONST(115961.78766841792 / 8.0), + REAL_CONST(115986.39298629249 / 8.0), + REAL_CONST(116010.99960917742 / 8.0), + REAL_CONST(116035.60753693432 / 8.0), + REAL_CONST(116060.21676942479 / 8.0), + REAL_CONST(116084.82730651053 / 8.0), + REAL_CONST(116109.43914805322 / 8.0), + REAL_CONST(116134.0522939146 / 8.0), + REAL_CONST(116158.66674395646 / 8.0), + REAL_CONST(116183.2824980406 / 8.0), + REAL_CONST(116207.89955602887 / 8.0), + REAL_CONST(116232.51791778316 / 8.0), + REAL_CONST(116257.13758316539 / 8.0), + REAL_CONST(116281.75855203751 / 8.0), + REAL_CONST(116306.38082426153 / 8.0), + REAL_CONST(116331.00439969949 / 8.0), + REAL_CONST(116355.62927821343 / 8.0), + REAL_CONST(116380.25545966547 / 8.0), + REAL_CONST(116404.88294391775 / 8.0), + REAL_CONST(116429.51173083246 / 8.0), + REAL_CONST(116454.14182027178 / 8.0), + REAL_CONST(116478.77321209799 / 8.0), + REAL_CONST(116503.40590617337 / 8.0), + REAL_CONST(116528.03990236025 / 8.0), + REAL_CONST(116552.67520052097 / 8.0), + REAL_CONST(116577.31180051794 / 8.0), + REAL_CONST(116601.94970221359 / 8.0), + REAL_CONST(116626.5889054704 / 8.0), + REAL_CONST(116651.22941015086 / 8.0), + REAL_CONST(116675.87121611751 / 8.0), + REAL_CONST(116700.51432323294 / 8.0), + REAL_CONST(116725.15873135976 / 8.0), + REAL_CONST(116749.8044403606 / 8.0), + REAL_CONST(116774.45145009817 / 8.0), + REAL_CONST(116799.0997604352 / 8.0), + REAL_CONST(116823.74937123443 / 8.0), + REAL_CONST(116848.40028235866 / 8.0), + REAL_CONST(116873.05249367072 / 8.0), + REAL_CONST(116897.70600503348 / 8.0), + REAL_CONST(116922.36081630984 / 8.0), + REAL_CONST(116947.01692736275 / 8.0), + REAL_CONST(116971.67433805518 / 8.0), + REAL_CONST(116996.33304825013 / 8.0), + REAL_CONST(117020.99305781067 / 8.0), + REAL_CONST(117045.65436659988 / 8.0), + REAL_CONST(117070.31697448085 / 8.0), + REAL_CONST(117094.98088131678 / 8.0), + REAL_CONST(117119.64608697082 / 8.0), + REAL_CONST(117144.31259130624 / 8.0), + REAL_CONST(117168.98039418629 / 8.0), + REAL_CONST(117193.64949547425 / 8.0), + REAL_CONST(117218.31989503348 / 8.0), + REAL_CONST(117242.99159272734 / 8.0), + REAL_CONST(117267.66458841923 / 8.0), + REAL_CONST(117292.33888197262 / 8.0), + REAL_CONST(117317.01447325097 / 8.0), + REAL_CONST(117341.6913621178 / 8.0), + REAL_CONST(117366.36954843666 / 8.0), + REAL_CONST(117391.04903207115 / 8.0), + REAL_CONST(117415.72981288488 / 8.0), + REAL_CONST(117440.41189074152 / 8.0), + REAL_CONST(117465.09526550474 / 8.0), + REAL_CONST(117489.77993703831 / 8.0), + REAL_CONST(117514.46590520597 / 8.0), + REAL_CONST(117539.15316987153 / 8.0), + REAL_CONST(117563.84173089883 / 8.0), + REAL_CONST(117588.53158815173 / 8.0), + REAL_CONST(117613.22274149416 / 8.0), + REAL_CONST(117637.91519079007 / 8.0), + REAL_CONST(117662.60893590341 / 8.0), + REAL_CONST(117687.30397669821 / 8.0), + REAL_CONST(117712.00031303853 / 8.0), + REAL_CONST(117736.69794478847 / 8.0), + REAL_CONST(117761.39687181212 / 8.0), + REAL_CONST(117786.09709397367 / 8.0), + REAL_CONST(117810.7986111373 / 8.0), + REAL_CONST(117835.50142316725 / 8.0), + REAL_CONST(117860.20552992777 / 8.0), + REAL_CONST(117884.91093128319 / 8.0), + REAL_CONST(117909.6176270978 / 8.0), + REAL_CONST(117934.32561723603 / 8.0), + REAL_CONST(117959.03490156225 / 8.0), + REAL_CONST(117983.74547994092 / 8.0), + REAL_CONST(118008.45735223651 / 8.0), + REAL_CONST(118033.17051831353 / 8.0), + REAL_CONST(118057.88497803656 / 8.0), + REAL_CONST(118082.60073127014 / 8.0), + REAL_CONST(118107.31777787894 / 8.0), + REAL_CONST(118132.03611772758 / 8.0), + REAL_CONST(118156.75575068076 / 8.0), + REAL_CONST(118181.47667660323 / 8.0), + REAL_CONST(118206.19889535972 / 8.0), + REAL_CONST(118230.92240681504 / 8.0), + REAL_CONST(118255.64721083404 / 8.0), + REAL_CONST(118280.37330728157 / 8.0), + REAL_CONST(118305.10069602253 / 8.0), + REAL_CONST(118329.82937692189 / 8.0), + REAL_CONST(118354.55934984458 / 8.0), + REAL_CONST(118379.29061465565 / 8.0), + REAL_CONST(118404.02317122012 / 8.0), + REAL_CONST(118428.75701940308 / 8.0), + REAL_CONST(118453.49215906965 / 8.0), + REAL_CONST(118478.22859008498 / 8.0), + REAL_CONST(118502.96631231424 / 8.0), + REAL_CONST(118527.70532562268 / 8.0), + REAL_CONST(118552.44562987552 / 8.0), + REAL_CONST(118577.18722493808 / 8.0), + REAL_CONST(118601.93011067568 / 8.0), + REAL_CONST(118626.67428695368 / 8.0), + REAL_CONST(118651.41975363747 / 8.0), + REAL_CONST(118676.16651059251 / 8.0), + REAL_CONST(118700.91455768423 / 8.0), + REAL_CONST(118725.66389477813 / 8.0), + REAL_CONST(118750.41452173979 / 8.0), + REAL_CONST(118775.16643843475 / 8.0), + REAL_CONST(118799.91964472862 / 8.0), + REAL_CONST(118824.67414048707 / 8.0), + REAL_CONST(118849.42992557574 / 8.0), + REAL_CONST(118874.18699986035 / 8.0), + REAL_CONST(118898.94536320666 / 8.0), + REAL_CONST(118923.70501548045 / 8.0), + REAL_CONST(118948.46595654752 / 8.0), + REAL_CONST(118973.22818627374 / 8.0), + REAL_CONST(118997.99170452499 / 8.0), + REAL_CONST(119022.7565111672 / 8.0), + REAL_CONST(119047.52260606633 / 8.0), + REAL_CONST(119072.28998908834 / 8.0), + REAL_CONST(119097.0586600993 / 8.0), + REAL_CONST(119121.82861896523 / 8.0), + REAL_CONST(119146.59986555226 / 8.0), + REAL_CONST(119171.3723997265 / 8.0), + REAL_CONST(119196.14622135412 / 8.0), + REAL_CONST(119220.92133030134 / 8.0), + REAL_CONST(119245.69772643436 / 8.0), + REAL_CONST(119270.47540961947 / 8.0), + REAL_CONST(119295.25437972297 / 8.0), + REAL_CONST(119320.03463661121 / 8.0), + REAL_CONST(119344.81618015055 / 8.0), + REAL_CONST(119369.5990102074 / 8.0), + REAL_CONST(119394.38312664822 / 8.0), + REAL_CONST(119419.16852933947 / 8.0), + REAL_CONST(119443.95521814766 / 8.0), + REAL_CONST(119468.74319293935 / 8.0), + REAL_CONST(119493.53245358112 / 8.0), + REAL_CONST(119518.32299993958 / 8.0), + REAL_CONST(119543.11483188139 / 8.0), + REAL_CONST(119567.90794927324 / 8.0), + REAL_CONST(119592.70235198183 / 8.0), + REAL_CONST(119617.49803987393 / 8.0), + REAL_CONST(119642.29501281632 / 8.0), + REAL_CONST(119667.09327067583 / 8.0), + REAL_CONST(119691.89281331931 / 8.0), + REAL_CONST(119716.69364061367 / 8.0), + REAL_CONST(119741.49575242582 / 8.0), + REAL_CONST(119766.29914862274 / 8.0), + REAL_CONST(119791.10382907141 / 8.0), + REAL_CONST(119815.90979363887 / 8.0), + REAL_CONST(119840.71704219218 / 8.0), + REAL_CONST(119865.52557459843 / 8.0), + REAL_CONST(119890.33539072477 / 8.0), + REAL_CONST(119915.14649043836 / 8.0), + REAL_CONST(119939.95887360642 / 8.0), + REAL_CONST(119964.77254009615 / 8.0), + REAL_CONST(119989.58748977486 / 8.0), + REAL_CONST(120014.40372250983 / 8.0), + REAL_CONST(120039.22123816841 / 8.0), + REAL_CONST(120064.04003661797 / 8.0), + REAL_CONST(120088.86011772591 / 8.0), + REAL_CONST(120113.6814813597 / 8.0), + REAL_CONST(120138.5041273868 / 8.0), + REAL_CONST(120163.3280556747 / 8.0), + REAL_CONST(120188.15326609099 / 8.0), + REAL_CONST(120212.97975850321 / 8.0), + REAL_CONST(120237.807532779 / 8.0), + REAL_CONST(120262.63658878599 / 8.0), + REAL_CONST(120287.46692639188 / 8.0), + REAL_CONST(120312.29854546436 / 8.0), + REAL_CONST(120337.13144587121 / 8.0), + REAL_CONST(120361.9656274802 / 8.0), + REAL_CONST(120386.80109015915 / 8.0), + REAL_CONST(120411.63783377589 / 8.0), + REAL_CONST(120436.47585819835 / 8.0), + REAL_CONST(120461.31516329442 / 8.0), + REAL_CONST(120486.15574893207 / 8.0), + REAL_CONST(120510.99761497928 / 8.0), + REAL_CONST(120535.84076130406 / 8.0), + REAL_CONST(120560.68518777451 / 8.0), + REAL_CONST(120585.53089425867 / 8.0), + REAL_CONST(120610.3778806247 / 8.0), + REAL_CONST(120635.22614674074 / 8.0), + REAL_CONST(120660.07569247499 / 8.0), + REAL_CONST(120684.92651769568 / 8.0), + REAL_CONST(120709.77862227106 / 8.0), + REAL_CONST(120734.63200606944 / 8.0), + REAL_CONST(120759.48666895913 / 8.0), + REAL_CONST(120784.3426108085 / 8.0), + REAL_CONST(120809.19983148595 / 8.0), + REAL_CONST(120834.05833085992 / 8.0), + REAL_CONST(120858.91810879884 / 8.0), + REAL_CONST(120883.77916517125 / 8.0), + REAL_CONST(120908.64149984565 / 8.0), + REAL_CONST(120933.5051126906 / 8.0), + REAL_CONST(120958.37000357473 / 8.0), + REAL_CONST(120983.23617236665 / 8.0), + REAL_CONST(121008.10361893504 / 8.0), + REAL_CONST(121032.97234314861 / 8.0), + REAL_CONST(121057.84234487606 / 8.0), + REAL_CONST(121082.71362398617 / 8.0), + REAL_CONST(121107.58618034775 / 8.0), + REAL_CONST(121132.46001382964 / 8.0), + REAL_CONST(121157.33512430069 / 8.0), + REAL_CONST(121182.21151162982 / 8.0), + REAL_CONST(121207.08917568595 / 8.0), + REAL_CONST(121231.96811633807 / 8.0), + REAL_CONST(121256.84833345517 / 8.0), + REAL_CONST(121281.72982690629 / 8.0), + REAL_CONST(121306.61259656049 / 8.0), + REAL_CONST(121331.49664228689 / 8.0), + REAL_CONST(121356.38196395461 / 8.0), + REAL_CONST(121381.26856143285 / 8.0), + REAL_CONST(121406.15643459078 / 8.0), + REAL_CONST(121431.04558329767 / 8.0), + REAL_CONST(121455.93600742276 / 8.0), + REAL_CONST(121480.82770683538 / 8.0), + REAL_CONST(121505.72068140487 / 8.0), + REAL_CONST(121530.61493100057 / 8.0), + REAL_CONST(121555.51045549192 / 8.0), + REAL_CONST(121580.40725474835 / 8.0), + REAL_CONST(121605.30532863933 / 8.0), + REAL_CONST(121630.20467703436 / 8.0), + REAL_CONST(121655.10529980299 / 8.0), + REAL_CONST(121680.00719681478 / 8.0), + REAL_CONST(121704.91036793934 / 8.0), + REAL_CONST(121729.81481304632 / 8.0), + REAL_CONST(121754.72053200539 / 8.0), + REAL_CONST(121779.62752468624 / 8.0), + REAL_CONST(121804.53579095862 / 8.0), + REAL_CONST(121829.44533069231 / 8.0), + REAL_CONST(121854.3561437571 / 8.0), + REAL_CONST(121879.26823002285 / 8.0), + REAL_CONST(121904.1815893594 / 8.0), + REAL_CONST(121929.09622163669 / 8.0), + REAL_CONST(121954.01212672464 / 8.0), + REAL_CONST(121978.92930449323 / 8.0), + REAL_CONST(122003.84775481246 / 8.0), + REAL_CONST(122028.76747755238 / 8.0), + REAL_CONST(122053.68847258303 / 8.0), + REAL_CONST(122078.61073977455 / 8.0), + REAL_CONST(122103.53427899707 / 8.0), + REAL_CONST(122128.45909012076 / 8.0), + REAL_CONST(122153.38517301581 / 8.0), + REAL_CONST(122178.31252755247 / 8.0), + REAL_CONST(122203.24115360099 / 8.0), + REAL_CONST(122228.17105103172 / 8.0), + REAL_CONST(122253.10221971494 / 8.0), + REAL_CONST(122278.03465952107 / 8.0), + REAL_CONST(122302.96837032049 / 8.0), + REAL_CONST(122327.90335198362 / 8.0), + REAL_CONST(122352.83960438096 / 8.0), + REAL_CONST(122377.777127383 / 8.0), + REAL_CONST(122402.71592086025 / 8.0), + REAL_CONST(122427.65598468333 / 8.0), + REAL_CONST(122452.59731872278 / 8.0), + REAL_CONST(122477.53992284928 / 8.0), + REAL_CONST(122502.48379693348 / 8.0), + REAL_CONST(122527.42894084606 / 8.0), + REAL_CONST(122552.37535445779 / 8.0), + REAL_CONST(122577.32303763942 / 8.0), + REAL_CONST(122602.27199026172 / 8.0), + REAL_CONST(122627.22221219557 / 8.0), + REAL_CONST(122652.17370331181 / 8.0), + REAL_CONST(122677.12646348133 / 8.0), + REAL_CONST(122702.08049257506 / 8.0), + REAL_CONST(122727.03579046397 / 8.0), + REAL_CONST(122751.99235701906 / 8.0), + REAL_CONST(122776.95019211136 / 8.0), + REAL_CONST(122801.9092956119 / 8.0), + REAL_CONST(122826.8696673918 / 8.0), + REAL_CONST(122851.83130732219 / 8.0), + REAL_CONST(122876.79421527422 / 8.0), + REAL_CONST(122901.75839111909 / 8.0), + REAL_CONST(122926.72383472799 / 8.0), + REAL_CONST(122951.69054597223 / 8.0), + REAL_CONST(122976.65852472307 / 8.0), + REAL_CONST(123001.62777085182 / 8.0), + REAL_CONST(123026.59828422987 / 8.0), + REAL_CONST(123051.57006472857 / 8.0), + REAL_CONST(123076.54311221937 / 8.0), + REAL_CONST(123101.5174265737 / 8.0), + REAL_CONST(123126.49300766307 / 8.0), + REAL_CONST(123151.46985535898 / 8.0), + REAL_CONST(123176.44796953299 / 8.0), + REAL_CONST(123201.42735005668 / 8.0), + REAL_CONST(123226.40799680166 / 8.0), + REAL_CONST(123251.38990963959 / 8.0), + REAL_CONST(123276.37308844214 / 8.0), + REAL_CONST(123301.35753308103 / 8.0), + REAL_CONST(123326.343243428 / 8.0), + REAL_CONST(123351.33021935483 / 8.0), + REAL_CONST(123376.31846073334 / 8.0), + REAL_CONST(123401.30796743535 / 8.0), + REAL_CONST(123426.29873933276 / 8.0), + REAL_CONST(123451.29077629748 / 8.0), + REAL_CONST(123476.28407820144 / 8.0), + REAL_CONST(123501.2786449166 / 8.0), + REAL_CONST(123526.27447631498 / 8.0), + REAL_CONST(123551.27157226863 / 8.0), + REAL_CONST(123576.26993264959 / 8.0), + REAL_CONST(123601.26955732999 / 8.0), + REAL_CONST(123626.27044618195 / 8.0), + REAL_CONST(123651.27259907764 / 8.0), + REAL_CONST(123676.27601588926 / 8.0), + REAL_CONST(123701.28069648903 / 8.0), + REAL_CONST(123726.28664074924 / 8.0), + REAL_CONST(123751.29384854218 / 8.0), + REAL_CONST(123776.30231974016 / 8.0), + REAL_CONST(123801.31205421555 / 8.0), + REAL_CONST(123826.32305184075 / 8.0), + REAL_CONST(123851.33531248817 / 8.0), + REAL_CONST(123876.34883603029 / 8.0), + REAL_CONST(123901.36362233957 / 8.0), + REAL_CONST(123926.37967128855 / 8.0), + REAL_CONST(123951.39698274979 / 8.0), + REAL_CONST(123976.41555659588 / 8.0), + REAL_CONST(124001.43539269941 / 8.0), + REAL_CONST(124026.45649093305 / 8.0), + REAL_CONST(124051.47885116948 / 8.0), + REAL_CONST(124076.50247328142 / 8.0), + REAL_CONST(124101.5273571416 / 8.0), + REAL_CONST(124126.55350262282 / 8.0), + REAL_CONST(124151.58090959788 / 8.0), + REAL_CONST(124176.60957793961 / 8.0), + REAL_CONST(124201.63950752091 / 8.0), + REAL_CONST(124226.67069821467 / 8.0), + REAL_CONST(124251.70314989384 / 8.0), + REAL_CONST(124276.73686243138 / 8.0), + REAL_CONST(124301.7718357003 / 8.0), + REAL_CONST(124326.80806957364 / 8.0), + REAL_CONST(124351.84556392446 / 8.0), + REAL_CONST(124376.88431862585 / 8.0), + REAL_CONST(124401.92433355095 / 8.0), + REAL_CONST(124426.96560857294 / 8.0), + REAL_CONST(124452.00814356498 / 8.0), + REAL_CONST(124477.05193840031 / 8.0), + REAL_CONST(124502.0969929522 / 8.0), + REAL_CONST(124527.14330709392 / 8.0), + REAL_CONST(124552.19088069882 / 8.0), + REAL_CONST(124577.23971364023 / 8.0), + REAL_CONST(124602.28980579154 / 8.0), + REAL_CONST(124627.34115702618 / 8.0), + REAL_CONST(124652.3937672176 / 8.0), + REAL_CONST(124677.44763623926 / 8.0), + REAL_CONST(124702.50276396469 / 8.0), + REAL_CONST(124727.55915026742 / 8.0), + REAL_CONST(124752.61679502104 / 8.0), + REAL_CONST(124777.67569809916 / 8.0), + REAL_CONST(124802.73585937542 / 8.0), + REAL_CONST(124827.79727872348 / 8.0), + REAL_CONST(124852.85995601704 / 8.0), + REAL_CONST(124877.92389112986 / 8.0), + REAL_CONST(124902.98908393568 / 8.0), + REAL_CONST(124928.05553430831 / 8.0), + REAL_CONST(124953.1232421216 / 8.0), + REAL_CONST(124978.19220724938 / 8.0), + REAL_CONST(125003.26242956554 / 8.0), + REAL_CONST(125028.33390894404 / 8.0), + REAL_CONST(125053.40664525882 / 8.0), + REAL_CONST(125078.48063838384 / 8.0), + REAL_CONST(125103.55588819318 / 8.0), + REAL_CONST(125128.63239456083 / 8.0), + REAL_CONST(125153.71015736091 / 8.0), + REAL_CONST(125178.78917646752 / 8.0), + REAL_CONST(125203.86945175481 / 8.0), + REAL_CONST(125228.95098309696 / 8.0), + REAL_CONST(125254.03377036817 / 8.0), + REAL_CONST(125279.1178134427 / 8.0), + REAL_CONST(125304.20311219479 / 8.0), + REAL_CONST(125329.28966649878 / 8.0), + REAL_CONST(125354.37747622898 / 8.0), + REAL_CONST(125379.46654125977 / 8.0), + REAL_CONST(125404.55686146552 / 8.0), + REAL_CONST(125429.6484367207 / 8.0), + REAL_CONST(125454.74126689974 / 8.0), + REAL_CONST(125479.83535187715 / 8.0), + REAL_CONST(125504.93069152744 / 8.0), + REAL_CONST(125530.02728572517 / 8.0), + REAL_CONST(125555.12513434493 / 8.0), + REAL_CONST(125580.22423726133 / 8.0), + REAL_CONST(125605.32459434902 / 8.0), + REAL_CONST(125630.4262054827 / 8.0), + REAL_CONST(125655.52907053704 / 8.0), + REAL_CONST(125680.63318938682 / 8.0), + REAL_CONST(125705.73856190679 / 8.0), + REAL_CONST(125730.84518797178 / 8.0), + REAL_CONST(125755.9530674566 / 8.0), + REAL_CONST(125781.06220023613 / 8.0), + REAL_CONST(125806.17258618528 / 8.0), + REAL_CONST(125831.28422517896 / 8.0), + REAL_CONST(125856.39711709213 / 8.0), + REAL_CONST(125881.51126179981 / 8.0), + REAL_CONST(125906.62665917698 / 8.0), + REAL_CONST(125931.74330909875 / 8.0), + REAL_CONST(125956.86121144016 / 8.0), + REAL_CONST(125981.98036607634 / 8.0), + REAL_CONST(126007.10077288245 / 8.0), + REAL_CONST(126032.22243173365 / 8.0), + REAL_CONST(126057.34534250517 / 8.0), + REAL_CONST(126082.46950507225 / 8.0), + REAL_CONST(126107.59491931014 / 8.0), + REAL_CONST(126132.72158509417 / 8.0), + REAL_CONST(126157.84950229966 / 8.0), + REAL_CONST(126182.97867080198 / 8.0), + REAL_CONST(126208.10909047653 / 8.0), + REAL_CONST(126233.24076119871 / 8.0), + REAL_CONST(126258.37368284403 / 8.0), + REAL_CONST(126283.50785528794 / 8.0), + REAL_CONST(126308.64327840599 / 8.0), + REAL_CONST(126333.77995207369 / 8.0), + REAL_CONST(126358.91787616667 / 8.0), + REAL_CONST(126384.0570505605 / 8.0), + REAL_CONST(126409.19747513086 / 8.0), + REAL_CONST(126434.3391497534 / 8.0), + REAL_CONST(126459.48207430386 / 8.0), + REAL_CONST(126484.62624865794 / 8.0), + REAL_CONST(126509.77167269142 / 8.0), + REAL_CONST(126534.9183462801 / 8.0), + REAL_CONST(126560.06626929982 / 8.0), + REAL_CONST(126585.21544162642 / 8.0), + REAL_CONST(126610.36586313581 / 8.0), + REAL_CONST(126635.51753370393 / 8.0), + REAL_CONST(126660.67045320668 / 8.0), + REAL_CONST(126685.82462152008 / 8.0), + REAL_CONST(126710.98003852014 / 8.0), + REAL_CONST(126736.13670408291 / 8.0), + REAL_CONST(126761.29461808444 / 8.0), + REAL_CONST(126786.45378040087 / 8.0), + REAL_CONST(126811.61419090834 / 8.0), + REAL_CONST(126836.77584948298 / 8.0), + REAL_CONST(126861.93875600102 / 8.0), + REAL_CONST(126887.10291033868 / 8.0), + REAL_CONST(126912.26831237224 / 8.0), + REAL_CONST(126937.43496197795 / 8.0), + REAL_CONST(126962.60285903217 / 8.0), + REAL_CONST(126987.77200341123 / 8.0), + REAL_CONST(127012.94239499152 / 8.0), + REAL_CONST(127038.11403364947 / 8.0), + REAL_CONST(127063.2869192615 / 8.0), + REAL_CONST(127088.46105170409 / 8.0), + REAL_CONST(127113.63643085376 / 8.0), + REAL_CONST(127138.81305658702 / 8.0), + REAL_CONST(127163.99092878048 / 8.0), + REAL_CONST(127189.17004731069 / 8.0), + REAL_CONST(127214.35041205429 / 8.0), + REAL_CONST(127239.53202288797 / 8.0), + REAL_CONST(127264.71487968838 / 8.0), + REAL_CONST(127289.89898233226 / 8.0), + REAL_CONST(127315.08433069635 / 8.0), + REAL_CONST(127340.27092465744 / 8.0), + REAL_CONST(127365.45876409234 / 8.0), + REAL_CONST(127390.64784887788 / 8.0), + REAL_CONST(127415.83817889093 / 8.0), + REAL_CONST(127441.02975400841 / 8.0), + REAL_CONST(127466.22257410725 / 8.0), + REAL_CONST(127491.41663906439 / 8.0), + REAL_CONST(127516.61194875685 / 8.0), + REAL_CONST(127541.80850306165 / 8.0), + REAL_CONST(127567.00630185583 / 8.0), + REAL_CONST(127592.20534501647 / 8.0), + REAL_CONST(127617.4056324207 / 8.0), + REAL_CONST(127642.60716394568 / 8.0), + REAL_CONST(127667.80993946856 / 8.0), + REAL_CONST(127693.01395886653 / 8.0), + REAL_CONST(127718.21922201688 / 8.0), + REAL_CONST(127743.42572879682 / 8.0), + REAL_CONST(127768.63347908368 / 8.0), + REAL_CONST(127793.84247275478 / 8.0), + REAL_CONST(127819.05270968749 / 8.0), + REAL_CONST(127844.26418975917 / 8.0), + REAL_CONST(127869.47691284724 / 8.0), + REAL_CONST(127894.69087882918 / 8.0), + REAL_CONST(127919.90608758242 / 8.0), + REAL_CONST(127945.12253898452 / 8.0), + REAL_CONST(127970.34023291297 / 8.0), + REAL_CONST(127995.55916924537 / 8.0), + REAL_CONST(128020.77934785932 / 8.0), + REAL_CONST(128046.00076863244 / 8.0), + REAL_CONST(128071.22343144237 / 8.0), + REAL_CONST(128096.44733616684 / 8.0), + REAL_CONST(128121.67248268353 / 8.0), + REAL_CONST(128146.89887087021 / 8.0), + REAL_CONST(128172.12650060465 / 8.0), + REAL_CONST(128197.35537176467 / 8.0), + REAL_CONST(128222.5854842281 / 8.0), + REAL_CONST(128247.81683787282 / 8.0), + REAL_CONST(128273.04943257671 / 8.0), + REAL_CONST(128298.28326821771 / 8.0), + REAL_CONST(128323.51834467379 / 8.0), + REAL_CONST(128348.75466182294 / 8.0), + REAL_CONST(128373.99221954317 / 8.0), + REAL_CONST(128399.23101771252 / 8.0), + REAL_CONST(128424.47105620909 / 8.0), + REAL_CONST(128449.71233491098 / 8.0), + REAL_CONST(128474.95485369631 / 8.0), + REAL_CONST(128500.19861244329 / 8.0), + REAL_CONST(128525.44361103009 / 8.0), + REAL_CONST(128550.68984933494 / 8.0), + REAL_CONST(128575.93732723613 / 8.0), + REAL_CONST(128601.18604461191 / 8.0), + REAL_CONST(128626.43600134061 / 8.0), + REAL_CONST(128651.68719730059 / 8.0), + REAL_CONST(128676.93963237021 / 8.0), + REAL_CONST(128702.1933064279 / 8.0), + REAL_CONST(128727.44821935208 / 8.0), + REAL_CONST(128752.70437102125 / 8.0), + REAL_CONST(128777.96176131385 / 8.0), + REAL_CONST(128803.22039010846 / 8.0), + REAL_CONST(128828.48025728362 / 8.0), + REAL_CONST(128853.74136271792 / 8.0), + REAL_CONST(128879.00370628996 / 8.0), + REAL_CONST(128904.26728787841 / 8.0), + REAL_CONST(128929.53210736193 / 8.0), + REAL_CONST(128954.79816461923 / 8.0), + REAL_CONST(128980.06545952905 / 8.0), + REAL_CONST(129005.33399197015 / 8.0), + REAL_CONST(129030.60376182134 / 8.0), + REAL_CONST(129055.87476896142 / 8.0), + REAL_CONST(129081.14701326926 / 8.0), + REAL_CONST(129106.42049462376 / 8.0), + REAL_CONST(129131.6952129038 / 8.0), + REAL_CONST(129156.97116798835 / 8.0), + REAL_CONST(129182.24835975636 / 8.0), + REAL_CONST(129207.52678808685 / 8.0), + REAL_CONST(129232.80645285884 / 8.0), + REAL_CONST(129258.08735395141 / 8.0), + REAL_CONST(129283.36949124365 / 8.0), + REAL_CONST(129308.65286461466 / 8.0), + REAL_CONST(129333.9374739436 / 8.0), + REAL_CONST(129359.22331910966 / 8.0), + REAL_CONST(129384.51039999202 / 8.0), + REAL_CONST(129409.79871646997 / 8.0), + REAL_CONST(129435.08826842274 / 8.0), + REAL_CONST(129460.37905572963 / 8.0), + REAL_CONST(129485.67107826998 / 8.0), + REAL_CONST(129510.96433592314 / 8.0), + REAL_CONST(129536.25882856851 / 8.0), + REAL_CONST(129561.55455608548 / 8.0), + REAL_CONST(129586.85151835352 / 8.0), + REAL_CONST(129612.14971525209 / 8.0), + REAL_CONST(129637.4491466607 / 8.0), + REAL_CONST(129662.74981245887 / 8.0), + REAL_CONST(129688.0517125262 / 8.0), + REAL_CONST(129713.35484674224 / 8.0), + REAL_CONST(129738.65921498663 / 8.0), + REAL_CONST(129763.96481713903 / 8.0), + REAL_CONST(129789.27165307909 / 8.0), + REAL_CONST(129814.57972268655 / 8.0), + REAL_CONST(129839.88902584116 / 8.0), + REAL_CONST(129865.19956242264 / 8.0), + REAL_CONST(129890.51133231082 / 8.0), + REAL_CONST(129915.82433538554 / 8.0), + REAL_CONST(129941.13857152662 / 8.0), + REAL_CONST(129966.45404061397 / 8.0), + REAL_CONST(129991.7707425275 / 8.0), + REAL_CONST(130017.08867714716 / 8.0), + REAL_CONST(130042.4078443529 / 8.0), + REAL_CONST(130067.72824402474 / 8.0), + REAL_CONST(130093.04987604271 / 8.0), + REAL_CONST(130118.37274028687 / 8.0), + REAL_CONST(130143.69683663732 / 8.0), + REAL_CONST(130169.02216497416 / 8.0), + REAL_CONST(130194.34872517755 / 8.0), + REAL_CONST(130219.67651712766 / 8.0), + REAL_CONST(130245.0055407047 / 8.0), + REAL_CONST(130270.33579578891 / 8.0), + REAL_CONST(130295.66728226055 / 8.0), + REAL_CONST(130320.99999999991 / 8.0), + REAL_CONST(130346.33394888733 / 8.0), + REAL_CONST(130371.66912880314 / 8.0), + REAL_CONST(130397.00553962773 / 8.0), + REAL_CONST(130422.34318124152 / 8.0), + REAL_CONST(130447.68205352494 / 8.0), + REAL_CONST(130473.02215635845 / 8.0), + REAL_CONST(130498.36348962256 / 8.0), + REAL_CONST(130523.70605319779 / 8.0), + REAL_CONST(130549.0498469647 / 8.0), + REAL_CONST(130574.39487080388 / 8.0), + REAL_CONST(130599.74112459592 / 8.0), + REAL_CONST(130625.08860822149 / 8.0), + REAL_CONST(130650.43732156123 / 8.0), + REAL_CONST(130675.78726449587 / 8.0), + REAL_CONST(130701.13843690613 / 8.0), + REAL_CONST(130726.49083867275 / 8.0), + REAL_CONST(130751.84446967654 / 8.0), + REAL_CONST(130777.19932979831 / 8.0), + REAL_CONST(130802.5554189189 / 8.0), + REAL_CONST(130827.91273691918 / 8.0), + REAL_CONST(130853.27128368006 / 8.0), + REAL_CONST(130878.63105908247 / 8.0), + REAL_CONST(130903.99206300738 / 8.0), + REAL_CONST(130929.35429533575 / 8.0), + REAL_CONST(130954.71775594862 / 8.0), + REAL_CONST(130980.08244472703 / 8.0), + REAL_CONST(131005.44836155206 / 8.0), + REAL_CONST(131030.81550630482 / 8.0), + REAL_CONST(131056.18387886642 / 8.0), + REAL_CONST(131081.55347911804 / 8.0), + REAL_CONST(131106.92430694087 / 8.0), + REAL_CONST(131132.29636221612 / 8.0), + REAL_CONST(131157.66964482504 / 8.0), + REAL_CONST(131183.0441546489 / 8.0), + REAL_CONST(131208.41989156904 / 8.0), + REAL_CONST(131233.79685546676 / 8.0), + REAL_CONST(131259.17504622342 / 8.0), + REAL_CONST(131284.55446372041 / 8.0), + REAL_CONST(131309.93510783918 / 8.0), + REAL_CONST(131335.31697846117 / 8.0), + REAL_CONST(131360.70007546784 / 8.0), + REAL_CONST(131386.0843987407 / 8.0), + REAL_CONST(131411.46994816128 / 8.0), + REAL_CONST(131436.85672361116 / 8.0), + REAL_CONST(131462.24472497194 / 8.0), + REAL_CONST(131487.63395212521 / 8.0), + REAL_CONST(131513.02440495262 / 8.0), + REAL_CONST(131538.41608333588 / 8.0), + REAL_CONST(131563.80898715663 / 8.0), + REAL_CONST(131589.2031162967 / 8.0), + REAL_CONST(131614.59847063778 / 8.0), + REAL_CONST(131639.9950500617 / 8.0), + REAL_CONST(131665.39285445024 / 8.0), + REAL_CONST(131690.79188368531 / 8.0), + REAL_CONST(131716.19213764873 / 8.0), + REAL_CONST(131741.59361622241 / 8.0), + REAL_CONST(131766.99631928833 / 8.0), + REAL_CONST(131792.40024672839 / 8.0), + REAL_CONST(131817.80539842462 / 8.0), + REAL_CONST(131843.21177425905 / 8.0), + REAL_CONST(131868.61937411371 / 8.0), + REAL_CONST(131894.02819787065 / 8.0), + REAL_CONST(131919.43824541202 / 8.0), + REAL_CONST(131944.84951661993 / 8.0), + REAL_CONST(131970.26201137656 / 8.0), + REAL_CONST(131995.67572956407 / 8.0), + REAL_CONST(132021.09067106468 / 8.0), + REAL_CONST(132046.50683576067 / 8.0), + REAL_CONST(132071.9242235343 / 8.0), + REAL_CONST(132097.34283426782 / 8.0), + REAL_CONST(132122.76266784366 / 8.0), + REAL_CONST(132148.1837241441 / 8.0), + REAL_CONST(132173.60600305157 / 8.0), + REAL_CONST(132199.02950444847 / 8.0), + REAL_CONST(132224.45422821722 / 8.0), + REAL_CONST(132249.88017424036 / 8.0), + REAL_CONST(132275.30734240031 / 8.0), + REAL_CONST(132300.73573257966 / 8.0), + REAL_CONST(132326.16534466096 / 8.0), + REAL_CONST(132351.59617852676 / 8.0), + REAL_CONST(132377.02823405969 / 8.0), + REAL_CONST(132402.46151114244 / 8.0), + REAL_CONST(132427.89600965759 / 8.0), + REAL_CONST(132453.33172948789 / 8.0), + REAL_CONST(132478.76867051609 / 8.0), + REAL_CONST(132504.20683262491 / 8.0), + REAL_CONST(132529.64621569714 / 8.0), + REAL_CONST(132555.08681961559 / 8.0), + REAL_CONST(132580.5286442631 / 8.0), + REAL_CONST(132605.97168952253 / 8.0), + REAL_CONST(132631.41595527678 / 8.0), + REAL_CONST(132656.86144140881 / 8.0), + REAL_CONST(132682.30814780149 / 8.0), + REAL_CONST(132707.75607433787 / 8.0), + REAL_CONST(132733.20522090094 / 8.0), + REAL_CONST(132758.65558737374 / 8.0), + REAL_CONST(132784.10717363929 / 8.0), + REAL_CONST(132809.55997958075 / 8.0), + REAL_CONST(132835.01400508118 / 8.0), + REAL_CONST(132860.46925002377 / 8.0), + REAL_CONST(132885.92571429166 / 8.0), + REAL_CONST(132911.38339776811 / 8.0), + REAL_CONST(132936.84230033628 / 8.0), + REAL_CONST(132962.30242187946 / 8.0), + REAL_CONST(132987.76376228096 / 8.0), + REAL_CONST(133013.22632142407 / 8.0), + REAL_CONST(133038.69009919214 / 8.0), + REAL_CONST(133064.15509546854 / 8.0), + REAL_CONST(133089.62131013666 / 8.0), + REAL_CONST(133115.08874307995 / 8.0), + REAL_CONST(133140.55739418184 / 8.0), + REAL_CONST(133166.02726332581 / 8.0), + REAL_CONST(133191.49835039541 / 8.0), + REAL_CONST(133216.97065527414 / 8.0), + REAL_CONST(133242.44417784561 / 8.0), + REAL_CONST(133267.91891799335 / 8.0), + REAL_CONST(133293.39487560102 / 8.0), + REAL_CONST(133318.87205055228 / 8.0), + REAL_CONST(133344.35044273079 / 8.0), + REAL_CONST(133369.83005202023 / 8.0), + REAL_CONST(133395.31087830439 / 8.0), + REAL_CONST(133420.79292146701 / 8.0), + REAL_CONST(133446.27618139185 / 8.0), + REAL_CONST(133471.76065796276 / 8.0), + REAL_CONST(133497.24635106357 / 8.0), + REAL_CONST(133522.73326057816 / 8.0), + REAL_CONST(133548.22138639039 / 8.0), + REAL_CONST(133573.71072838426 / 8.0), + REAL_CONST(133599.20128644365 / 8.0), + REAL_CONST(133624.69306045261 / 8.0), + REAL_CONST(133650.1860502951 / 8.0), + REAL_CONST(133675.68025585517 / 8.0), + REAL_CONST(133701.1756770169 / 8.0), + REAL_CONST(133726.67231366437 / 8.0), + REAL_CONST(133752.17016568172 / 8.0), + REAL_CONST(133777.66923295305 / 8.0), + REAL_CONST(133803.16951536259 / 8.0), + REAL_CONST(133828.67101279454 / 8.0), + REAL_CONST(133854.17372513309 / 8.0), + REAL_CONST(133879.67765226253 / 8.0), + REAL_CONST(133905.18279406714 / 8.0), + REAL_CONST(133930.68915043125 / 8.0), + REAL_CONST(133956.19672123916 / 8.0), + REAL_CONST(133981.70550637526 / 8.0), + REAL_CONST(134007.21550572399 / 8.0), + REAL_CONST(134032.7267191697 / 8.0), + REAL_CONST(134058.23914659687 / 8.0), + REAL_CONST(134083.75278789 / 8.0), + REAL_CONST(134109.26764293358 / 8.0), + REAL_CONST(134134.78371161217 / 8.0), + REAL_CONST(134160.30099381026 / 8.0), + REAL_CONST(134185.8194894125 / 8.0), + REAL_CONST(134211.33919830353 / 8.0), + REAL_CONST(134236.8601203679 / 8.0), + REAL_CONST(134262.38225549037 / 8.0), + REAL_CONST(134287.90560355558 / 8.0), + REAL_CONST(134313.43016444831 / 8.0), + REAL_CONST(134338.95593805326 / 8.0), + REAL_CONST(134364.48292425525 / 8.0), + REAL_CONST(134390.01112293909 / 8.0), + REAL_CONST(134415.54053398955 / 8.0), + REAL_CONST(134441.07115729159 / 8.0), + REAL_CONST(134466.60299273001 / 8.0), + REAL_CONST(134492.1360401898 / 8.0), + REAL_CONST(134517.67029955584 / 8.0), + REAL_CONST(134543.20577071316 / 8.0), + REAL_CONST(134568.74245354676 / 8.0), + REAL_CONST(134594.28034794159 / 8.0), + REAL_CONST(134619.81945378278 / 8.0), + REAL_CONST(134645.35977095537 / 8.0), + REAL_CONST(134670.90129934452 / 8.0), + REAL_CONST(134696.4440388353 / 8.0), + REAL_CONST(134721.98798931291 / 8.0), + REAL_CONST(134747.53315066252 / 8.0), + REAL_CONST(134773.07952276937 / 8.0), + REAL_CONST(134798.62710551871 / 8.0), + REAL_CONST(134824.17589879577 / 8.0), + REAL_CONST(134849.72590248589 / 8.0), + REAL_CONST(134875.27711647438 / 8.0), + REAL_CONST(134900.82954064661 / 8.0), + REAL_CONST(134926.38317488792 / 8.0), + REAL_CONST(134951.93801908373 / 8.0), + REAL_CONST(134977.49407311951 / 8.0), + REAL_CONST(135003.05133688069 / 8.0), + REAL_CONST(135028.60981025276 / 8.0), + REAL_CONST(135054.16949312127 / 8.0), + REAL_CONST(135079.73038537172 / 8.0), + REAL_CONST(135105.29248688967 / 8.0), + REAL_CONST(135130.85579756077 / 8.0), + REAL_CONST(135156.42031727062 / 8.0), + REAL_CONST(135181.98604590484 / 8.0), + REAL_CONST(135207.55298334916 / 8.0), + REAL_CONST(135233.12112948924 / 8.0), + REAL_CONST(135258.69048421088 / 8.0), + REAL_CONST(135284.26104739975 / 8.0), + REAL_CONST(135309.83281894168 / 8.0), + REAL_CONST(135335.4057987225 / 8.0), + REAL_CONST(135360.97998662802 / 8.0), + REAL_CONST(135386.55538254412 / 8.0), + REAL_CONST(135412.13198635669 / 8.0), + REAL_CONST(135437.70979795168 / 8.0), + REAL_CONST(135463.28881721498 / 8.0), + REAL_CONST(135488.86904403262 / 8.0), + REAL_CONST(135514.45047829056 / 8.0), + REAL_CONST(135540.03311987486 / 8.0), + REAL_CONST(135565.61696867159 / 8.0), + REAL_CONST(135591.20202456677 / 8.0), + REAL_CONST(135616.78828744654 / 8.0), + REAL_CONST(135642.37575719706 / 8.0), + REAL_CONST(135667.96443370447 / 8.0), + REAL_CONST(135693.55431685498 / 8.0), + REAL_CONST(135719.14540653475 / 8.0), + REAL_CONST(135744.73770263011 / 8.0), + REAL_CONST(135770.33120502727 / 8.0), + REAL_CONST(135795.92591361253 / 8.0), + REAL_CONST(135821.52182827223 / 8.0), + REAL_CONST(135847.11894889272 / 8.0), + REAL_CONST(135872.7172753604 / 8.0), + REAL_CONST(135898.31680756161 / 8.0), + REAL_CONST(135923.91754538284 / 8.0), + REAL_CONST(135949.51948871053 / 8.0), + REAL_CONST(135975.12263743114 / 8.0), + REAL_CONST(136000.72699143123 / 8.0), + REAL_CONST(136026.33255059729 / 8.0), + REAL_CONST(136051.93931481591 / 8.0), + REAL_CONST(136077.54728397369 / 8.0), + REAL_CONST(136103.15645795723 / 8.0), + REAL_CONST(136128.76683665317 / 8.0), + REAL_CONST(136154.37841994822 / 8.0), + REAL_CONST(136179.99120772901 / 8.0), + REAL_CONST(136205.60519988232 / 8.0), + REAL_CONST(136231.2203962949 / 8.0), + REAL_CONST(136256.83679685349 / 8.0), + REAL_CONST(136282.45440144493 / 8.0), + REAL_CONST(136308.07320995603 / 8.0), + REAL_CONST(136333.69322227367 / 8.0), + REAL_CONST(136359.31443828469 / 8.0), + REAL_CONST(136384.93685787608 / 8.0), + REAL_CONST(136410.56048093468 / 8.0), + REAL_CONST(136436.18530734754 / 8.0), + REAL_CONST(136461.81133700156 / 8.0), + REAL_CONST(136487.43856978384 / 8.0), + REAL_CONST(136513.06700558143 / 8.0), + REAL_CONST(136538.6966442813 / 8.0), + REAL_CONST(136564.32748577066 / 8.0), + REAL_CONST(136589.95952993655 / 8.0), + REAL_CONST(136615.59277666616 / 8.0), + REAL_CONST(136641.22722584667 / 8.0), + REAL_CONST(136666.86287736523 / 8.0), + REAL_CONST(136692.49973110916 / 8.0), + REAL_CONST(136718.13778696564 / 8.0), + REAL_CONST(136743.77704482197 / 8.0), + REAL_CONST(136769.41750456547 / 8.0), + REAL_CONST(136795.05916608346 / 8.0), + REAL_CONST(136820.70202926331 / 8.0), + REAL_CONST(136846.34609399244 / 8.0), + REAL_CONST(136871.99136015819 / 8.0), + REAL_CONST(136897.63782764805 / 8.0), + REAL_CONST(136923.28549634948 / 8.0), + REAL_CONST(136948.93436614997 / 8.0), + REAL_CONST(136974.58443693706 / 8.0), + REAL_CONST(137000.23570859825 / 8.0), + REAL_CONST(137025.88818102115 / 8.0), + REAL_CONST(137051.54185409332 / 8.0), + REAL_CONST(137077.19672770242 / 8.0), + REAL_CONST(137102.85280173609 / 8.0), + REAL_CONST(137128.51007608202 / 8.0), + REAL_CONST(137154.16855062786 / 8.0), + REAL_CONST(137179.82822526142 / 8.0), + REAL_CONST(137205.48909987041 / 8.0), + REAL_CONST(137231.15117434258 / 8.0), + REAL_CONST(137256.8144485658 / 8.0), + REAL_CONST(137282.47892242789 / 8.0), + REAL_CONST(137308.14459581667 / 8.0), + REAL_CONST(137333.81146862009 / 8.0), + REAL_CONST(137359.47954072602 / 8.0), + REAL_CONST(137385.14881202241 / 8.0), + REAL_CONST(137410.81928239719 / 8.0), + REAL_CONST(137436.49095173844 / 8.0), + REAL_CONST(137462.16381993407 / 8.0), + REAL_CONST(137487.83788687221 / 8.0), + REAL_CONST(137513.51315244089 / 8.0), + REAL_CONST(137539.18961652822 / 8.0), + REAL_CONST(137564.86727902229 / 8.0), + REAL_CONST(137590.54613981131 / 8.0), + REAL_CONST(137616.22619878338 / 8.0), + REAL_CONST(137641.90745582676 / 8.0), + REAL_CONST(137667.58991082967 / 8.0), + REAL_CONST(137693.27356368033 / 8.0), + REAL_CONST(137718.95841426702 / 8.0), + REAL_CONST(137744.64446247809 / 8.0), + REAL_CONST(137770.33170820182 / 8.0), + REAL_CONST(137796.02015132661 / 8.0), + REAL_CONST(137821.70979174081 / 8.0), + REAL_CONST(137847.40062933284 / 8.0), + REAL_CONST(137873.09266399115 / 8.0), + REAL_CONST(137898.78589560417 / 8.0), + REAL_CONST(137924.48032406042 / 8.0), + REAL_CONST(137950.17594924837 / 8.0), + REAL_CONST(137975.8727710566 / 8.0), + REAL_CONST(138001.57078937365 / 8.0), + REAL_CONST(138027.27000408815 / 8.0), + REAL_CONST(138052.97041508864 / 8.0), + REAL_CONST(138078.67202226384 / 8.0), + REAL_CONST(138104.3748255024 / 8.0), + REAL_CONST(138130.07882469296 / 8.0), + REAL_CONST(138155.78401972432 / 8.0), + REAL_CONST(138181.49041048516 / 8.0), + REAL_CONST(138207.1979968643 / 8.0), + REAL_CONST(138232.9067787505 / 8.0), + REAL_CONST(138258.61675603263 / 8.0), + REAL_CONST(138284.32792859949 / 8.0), + REAL_CONST(138310.04029633995 / 8.0), + REAL_CONST(138335.75385914298 / 8.0), + REAL_CONST(138361.46861689744 / 8.0), + REAL_CONST(138387.18456949232 / 8.0), + REAL_CONST(138412.90171681659 / 8.0), + REAL_CONST(138438.62005875923 / 8.0), + REAL_CONST(138464.33959520931 / 8.0), + REAL_CONST(138490.06032605586 / 8.0), + REAL_CONST(138515.78225118798 / 8.0), + REAL_CONST(138541.50537049473 / 8.0), + REAL_CONST(138567.2296838653 / 8.0), + REAL_CONST(138592.95519118884 / 8.0), + REAL_CONST(138618.68189235451 / 8.0), + REAL_CONST(138644.40978725153 / 8.0), + REAL_CONST(138670.13887576913 / 8.0), + REAL_CONST(138695.86915779658 / 8.0), + REAL_CONST(138721.60063322316 / 8.0), + REAL_CONST(138747.33330193823 / 8.0), + REAL_CONST(138773.06716383106 / 8.0), + REAL_CONST(138798.80221879104 / 8.0), + REAL_CONST(138824.53846670757 / 8.0), + REAL_CONST(138850.27590747006 / 8.0), + REAL_CONST(138876.01454096794 / 8.0), + REAL_CONST(138901.7543670907 / 8.0), + REAL_CONST(138927.49538572782 / 8.0), + REAL_CONST(138953.2375967688 / 8.0), + REAL_CONST(138978.9810001032 / 8.0), + REAL_CONST(139004.72559562061 / 8.0), + REAL_CONST(139030.47138321059 / 8.0), + REAL_CONST(139056.2183627628 / 8.0), + REAL_CONST(139081.96653416683 / 8.0), + REAL_CONST(139107.71589731239 / 8.0), + REAL_CONST(139133.46645208917 / 8.0), + REAL_CONST(139159.21819838689 / 8.0), + REAL_CONST(139184.97113609532 / 8.0), + REAL_CONST(139210.72526510421 / 8.0), + REAL_CONST(139236.48058530336 / 8.0), + REAL_CONST(139262.23709658257 / 8.0), + REAL_CONST(139287.99479883176 / 8.0), + REAL_CONST(139313.75369194071 / 8.0), + REAL_CONST(139339.51377579942 / 8.0), + REAL_CONST(139365.27505029776 / 8.0), + REAL_CONST(139391.03751532568 / 8.0), + REAL_CONST(139416.80117077316 / 8.0), + REAL_CONST(139442.56601653024 / 8.0), + REAL_CONST(139468.33205248689 / 8.0), + REAL_CONST(139494.09927853322 / 8.0), + REAL_CONST(139519.86769455927 / 8.0), + REAL_CONST(139545.63730045516 / 8.0), + REAL_CONST(139571.408096111 / 8.0), + REAL_CONST(139597.18008141697 / 8.0), + REAL_CONST(139622.95325626322 / 8.0), + REAL_CONST(139648.72762054001 / 8.0), + REAL_CONST(139674.5031741375 / 8.0), + REAL_CONST(139700.27991694602 / 8.0), + REAL_CONST(139726.05784885579 / 8.0), + REAL_CONST(139751.83696975713 / 8.0), + REAL_CONST(139777.61727954043 / 8.0), + REAL_CONST(139803.39877809596 / 8.0), + REAL_CONST(139829.18146531415 / 8.0), + REAL_CONST(139854.96534108539 / 8.0), + REAL_CONST(139880.75040530015 / 8.0), + REAL_CONST(139906.53665784886 / 8.0), + REAL_CONST(139932.32409862199 / 8.0), + REAL_CONST(139958.11272751007 / 8.0), + REAL_CONST(139983.90254440365 / 8.0), + REAL_CONST(140009.69354919327 / 8.0), + REAL_CONST(140035.48574176949 / 8.0), + REAL_CONST(140061.27912202294 / 8.0), + REAL_CONST(140087.07368984428 / 8.0), + REAL_CONST(140112.86944512415 / 8.0), + REAL_CONST(140138.66638775321 / 8.0), + REAL_CONST(140164.4645176222 / 8.0), + REAL_CONST(140190.26383462184 / 8.0), + REAL_CONST(140216.06433864293 / 8.0), + REAL_CONST(140241.86602957622 / 8.0), + REAL_CONST(140267.66890731253 / 8.0), + REAL_CONST(140293.47297174268 / 8.0), + REAL_CONST(140319.27822275754 / 8.0), + REAL_CONST(140345.08466024802 / 8.0), + REAL_CONST(140370.89228410498 / 8.0), + REAL_CONST(140396.70109421943 / 8.0), + REAL_CONST(140422.51109048226 / 8.0), + REAL_CONST(140448.32227278448 / 8.0), + REAL_CONST(140474.13464101712 / 8.0), + REAL_CONST(140499.94819507122 / 8.0), + REAL_CONST(140525.76293483781 / 8.0), + REAL_CONST(140551.57886020801 / 8.0), + REAL_CONST(140577.3959710729 / 8.0), + REAL_CONST(140603.21426732364 / 8.0), + REAL_CONST(140629.03374885136 / 8.0), + REAL_CONST(140654.85441554731 / 8.0), + REAL_CONST(140680.67626730262 / 8.0), + REAL_CONST(140706.49930400858 / 8.0), + REAL_CONST(140732.32352555645 / 8.0), + REAL_CONST(140758.1489318375 / 8.0), + REAL_CONST(140783.97552274304 / 8.0), + REAL_CONST(140809.80329816442 / 8.0), + REAL_CONST(140835.63225799298 / 8.0), + REAL_CONST(140861.46240212015 / 8.0), + REAL_CONST(140887.29373043729 / 8.0), + REAL_CONST(140913.12624283586 / 8.0), + REAL_CONST(140938.95993920733 / 8.0), + REAL_CONST(140964.79481944317 / 8.0), + REAL_CONST(140990.63088343487 / 8.0), + REAL_CONST(141016.46813107401 / 8.0), + REAL_CONST(141042.30656225214 / 8.0), + REAL_CONST(141068.14617686081 / 8.0), + REAL_CONST(141093.98697479168 / 8.0), + REAL_CONST(141119.82895593636 / 8.0), + REAL_CONST(141145.6721201865 / 8.0), + REAL_CONST(141171.51646743377 / 8.0), + REAL_CONST(141197.36199756994 / 8.0), + REAL_CONST(141223.20871048668 / 8.0), + REAL_CONST(141249.05660607578 / 8.0), + REAL_CONST(141274.90568422904 / 8.0), + REAL_CONST(141300.75594483822 / 8.0), + REAL_CONST(141326.6073877952 / 8.0), + REAL_CONST(141352.4600129918 / 8.0), + REAL_CONST(141378.31382031992 / 8.0), + REAL_CONST(141404.16880967148 / 8.0), + REAL_CONST(141430.02498093838 / 8.0), + REAL_CONST(141455.8823340126 / 8.0), + REAL_CONST(141481.74086878612 / 8.0), + REAL_CONST(141507.60058515094 / 8.0), + REAL_CONST(141533.46148299909 / 8.0), + REAL_CONST(141559.32356222265 / 8.0), + REAL_CONST(141585.18682271364 / 8.0), + REAL_CONST(141611.05126436421 / 8.0), + REAL_CONST(141636.9168870665 / 8.0), + REAL_CONST(141662.78369071262 / 8.0), + REAL_CONST(141688.65167519479 / 8.0), + REAL_CONST(141714.5208404052 / 8.0), + REAL_CONST(141740.39118623605 / 8.0), + REAL_CONST(141766.26271257963 / 8.0), + REAL_CONST(141792.1354193282 / 8.0), + REAL_CONST(141818.00930637406 / 8.0), + REAL_CONST(141843.88437360956 / 8.0), + REAL_CONST(141869.760620927 / 8.0), + REAL_CONST(141895.6380482188 / 8.0), + REAL_CONST(141921.51665537735 / 8.0), + REAL_CONST(141947.39644229505 / 8.0), + REAL_CONST(141973.27740886438 / 8.0), + REAL_CONST(141999.15955497778 / 8.0), + REAL_CONST(142025.04288052776 / 8.0), + REAL_CONST(142050.92738540689 / 8.0), + REAL_CONST(142076.81306950765 / 8.0), + REAL_CONST(142102.69993272264 / 8.0), + REAL_CONST(142128.58797494444 / 8.0), + REAL_CONST(142154.47719606571 / 8.0), + REAL_CONST(142180.36759597904 / 8.0), + REAL_CONST(142206.25917457714 / 8.0), + REAL_CONST(142232.15193175265 / 8.0), + REAL_CONST(142258.04586739838 / 8.0), + REAL_CONST(142283.94098140698 / 8.0), + REAL_CONST(142309.83727367126 / 8.0), + REAL_CONST(142335.73474408401 / 8.0), + REAL_CONST(142361.63339253806 / 8.0), + REAL_CONST(142387.5332189262 / 8.0), + REAL_CONST(142413.43422314132 / 8.0), + REAL_CONST(142439.33640507635 / 8.0), + REAL_CONST(142465.23976462413 / 8.0), + REAL_CONST(142491.14430167765 / 8.0), + REAL_CONST(142517.05001612983 / 8.0), + REAL_CONST(142542.95690787368 / 8.0), + REAL_CONST(142568.86497680223 / 8.0), + REAL_CONST(142594.77422280848 / 8.0), + REAL_CONST(142620.68464578551 / 8.0), + REAL_CONST(142646.5962456264 / 8.0), + REAL_CONST(142672.50902222423 / 8.0), + REAL_CONST(142698.42297547215 / 8.0), + REAL_CONST(142724.33810526333 / 8.0), + REAL_CONST(142750.25441149093 / 8.0), + REAL_CONST(142776.17189404817 / 8.0), + REAL_CONST(142802.09055282827 / 8.0), + REAL_CONST(142828.01038772447 / 8.0), + REAL_CONST(142853.93139863008 / 8.0), + REAL_CONST(142879.85358543837 / 8.0), + REAL_CONST(142905.77694804268 / 8.0), + REAL_CONST(142931.70148633636 / 8.0), + REAL_CONST(142957.62720021277 / 8.0), + REAL_CONST(142983.55408956532 / 8.0), + REAL_CONST(143009.48215428743 / 8.0), + REAL_CONST(143035.41139427255 / 8.0), + REAL_CONST(143061.34180941415 / 8.0), + REAL_CONST(143087.27339960571 / 8.0), + REAL_CONST(143113.20616474075 / 8.0), + REAL_CONST(143139.14010471283 / 8.0), + REAL_CONST(143165.07521941551 / 8.0), + REAL_CONST(143191.01150874238 / 8.0), + REAL_CONST(143216.94897258704 / 8.0), + REAL_CONST(143242.88761084314 / 8.0), + REAL_CONST(143268.82742340435 / 8.0), + REAL_CONST(143294.76841016437 / 8.0), + REAL_CONST(143320.71057101688 / 8.0), + REAL_CONST(143346.65390585564 / 8.0), + REAL_CONST(143372.59841457437 / 8.0), + REAL_CONST(143398.54409706692 / 8.0), + REAL_CONST(143424.49095322701 / 8.0), + REAL_CONST(143450.43898294857 / 8.0), + REAL_CONST(143476.38818612538 / 8.0), + REAL_CONST(143502.33856265133 / 8.0), + REAL_CONST(143528.29011242036 / 8.0), + REAL_CONST(143554.24283532638 / 8.0), + REAL_CONST(143580.19673126334 / 8.0), + REAL_CONST(143606.1518001252 / 8.0), + REAL_CONST(143632.10804180597 / 8.0), + REAL_CONST(143658.06545619969 / 8.0), + REAL_CONST(143684.02404320039 / 8.0), + REAL_CONST(143709.98380270213 / 8.0), + REAL_CONST(143735.944734599 / 8.0), + REAL_CONST(143761.90683878519 / 8.0), + REAL_CONST(143787.87011515474 / 8.0), + REAL_CONST(143813.83456360188 / 8.0), + REAL_CONST(143839.8001840208 / 8.0), + REAL_CONST(143865.76697630569 / 8.0), + REAL_CONST(143891.73494035081 / 8.0), + REAL_CONST(143917.7040760504 / 8.0), + REAL_CONST(143943.67438329876 / 8.0), + REAL_CONST(143969.6458619902 / 8.0), + REAL_CONST(143995.61851201905 / 8.0), + REAL_CONST(144021.59233327967 / 8.0), + REAL_CONST(144047.56732566646 / 8.0), + REAL_CONST(144073.54348907378 / 8.0), + REAL_CONST(144099.52082339607 / 8.0), + REAL_CONST(144125.49932852783 / 8.0), + REAL_CONST(144151.4790043635 / 8.0), + REAL_CONST(144177.45985079758 / 8.0), + REAL_CONST(144203.44186772458 / 8.0), + REAL_CONST(144229.42505503909 / 8.0), + REAL_CONST(144255.40941263564 / 8.0), + REAL_CONST(144281.39494040885 / 8.0), + REAL_CONST(144307.38163825331 / 8.0), + REAL_CONST(144333.36950606373 / 8.0), + REAL_CONST(144359.35854373468 / 8.0), + REAL_CONST(144385.34875116093 / 8.0), + REAL_CONST(144411.34012823718 / 8.0), + REAL_CONST(144437.33267485813 / 8.0), + REAL_CONST(144463.32639091855 / 8.0), + REAL_CONST(144489.32127631325 / 8.0), + REAL_CONST(144515.31733093705 / 8.0), + REAL_CONST(144541.31455468474 / 8.0), + REAL_CONST(144567.3129474512 / 8.0), + REAL_CONST(144593.3125091313 / 8.0), + REAL_CONST(144619.31323961995 / 8.0), + REAL_CONST(144645.31513881206 / 8.0), + REAL_CONST(144671.31820660262 / 8.0), + REAL_CONST(144697.32244288657 / 8.0), + REAL_CONST(144723.32784755889 / 8.0), + REAL_CONST(144749.33442051467 / 8.0), + REAL_CONST(144775.34216164888 / 8.0), + REAL_CONST(144801.35107085665 / 8.0), + REAL_CONST(144827.36114803303 / 8.0), + REAL_CONST(144853.37239307314 / 8.0), + REAL_CONST(144879.38480587213 / 8.0), + REAL_CONST(144905.39838632516 / 8.0), + REAL_CONST(144931.41313432742 / 8.0), + REAL_CONST(144957.4290497741 / 8.0), + REAL_CONST(144983.44613256046 / 8.0), + REAL_CONST(145009.46438258173 / 8.0), + REAL_CONST(145035.48379973322 / 8.0), + REAL_CONST(145061.50438391021 / 8.0), + REAL_CONST(145087.52613500805 / 8.0), + REAL_CONST(145113.54905292206 / 8.0), + REAL_CONST(145139.57313754765 / 8.0), + REAL_CONST(145165.59838878017 / 8.0), + REAL_CONST(145191.62480651509 / 8.0), + REAL_CONST(145217.65239064783 / 8.0), + REAL_CONST(145243.68114107384 / 8.0), + REAL_CONST(145269.71105768863 / 8.0), + REAL_CONST(145295.74214038774 / 8.0), + REAL_CONST(145321.77438906668 / 8.0), + REAL_CONST(145347.80780362099 / 8.0), + REAL_CONST(145373.84238394629 / 8.0), + REAL_CONST(145399.87812993818 / 8.0), + REAL_CONST(145425.91504149229 / 8.0), + REAL_CONST(145451.95311850426 / 8.0), + REAL_CONST(145477.9923608698 / 8.0), + REAL_CONST(145504.03276848458 / 8.0), + REAL_CONST(145530.07434124436 / 8.0), + REAL_CONST(145556.11707904484 / 8.0), + REAL_CONST(145582.16098178181 / 8.0), + REAL_CONST(145608.20604935108 / 8.0), + REAL_CONST(145634.25228164849 / 8.0), + REAL_CONST(145660.29967856981 / 8.0), + REAL_CONST(145686.34824001096 / 8.0), + REAL_CONST(145712.39796586783 / 8.0), + REAL_CONST(145738.4488560363 / 8.0), + REAL_CONST(145764.50091041232 / 8.0), + REAL_CONST(145790.55412889185 / 8.0), + REAL_CONST(145816.60851137087 / 8.0), + REAL_CONST(145842.66405774537 / 8.0), + REAL_CONST(145868.72076791141 / 8.0), + REAL_CONST(145894.77864176501 / 8.0), + REAL_CONST(145920.83767920226 / 8.0), + REAL_CONST(145946.89788011924 / 8.0), + REAL_CONST(145972.95924441208 / 8.0), + REAL_CONST(145999.02177197693 / 8.0), + REAL_CONST(146025.08546270995 / 8.0), + REAL_CONST(146051.15031650732 / 8.0), + REAL_CONST(146077.21633326527 / 8.0), + REAL_CONST(146103.28351288004 / 8.0), + REAL_CONST(146129.35185524789 / 8.0), + REAL_CONST(146155.42136026506 / 8.0), + REAL_CONST(146181.49202782792 / 8.0), + REAL_CONST(146207.56385783272 / 8.0), + REAL_CONST(146233.63685017588 / 8.0), + REAL_CONST(146259.71100475377 / 8.0), + REAL_CONST(146285.78632146274 / 8.0), + REAL_CONST(146311.86280019928 / 8.0), + REAL_CONST(146337.94044085976 / 8.0), + REAL_CONST(146364.01924334071 / 8.0), + REAL_CONST(146390.09920753856 / 8.0), + REAL_CONST(146416.18033334985 / 8.0), + REAL_CONST(146442.26262067116 / 8.0), + REAL_CONST(146468.34606939898 / 8.0), + REAL_CONST(146494.43067942993 / 8.0), + REAL_CONST(146520.51645066062 / 8.0), + REAL_CONST(146546.60338298764 / 8.0), + REAL_CONST(146572.69147630769 / 8.0), + REAL_CONST(146598.78073051744 / 8.0), + REAL_CONST(146624.87114551352 / 8.0), + REAL_CONST(146650.96272119274 / 8.0), + REAL_CONST(146677.05545745179 / 8.0), + REAL_CONST(146703.14935418745 / 8.0), + REAL_CONST(146729.2444112965 / 8.0), + REAL_CONST(146755.34062867577 / 8.0), + REAL_CONST(146781.43800622207 / 8.0), + REAL_CONST(146807.53654383228 / 8.0), + REAL_CONST(146833.63624140329 / 8.0), + REAL_CONST(146859.73709883197 / 8.0), + REAL_CONST(146885.83911601527 / 8.0), + REAL_CONST(146911.94229285014 / 8.0), + REAL_CONST(146938.04662923355 / 8.0), + REAL_CONST(146964.15212506248 / 8.0), + REAL_CONST(146990.25878023397 / 8.0), + REAL_CONST(147016.36659464505 / 8.0), + REAL_CONST(147042.47556819281 / 8.0), + REAL_CONST(147068.58570077427 / 8.0), + REAL_CONST(147094.6969922866 / 8.0), + REAL_CONST(147120.80944262692 / 8.0), + REAL_CONST(147146.92305169237 / 8.0), + REAL_CONST(147173.03781938017 / 8.0), + REAL_CONST(147199.15374558745 / 8.0), + REAL_CONST(147225.27083021149 / 8.0), + REAL_CONST(147251.38907314953 / 8.0), + REAL_CONST(147277.50847429881 / 8.0), + REAL_CONST(147303.62903355664 / 8.0), + REAL_CONST(147329.75075082036 / 8.0), + REAL_CONST(147355.87362598727 / 8.0), + REAL_CONST(147381.99765895473 / 8.0), + REAL_CONST(147408.12284962015 / 8.0), + REAL_CONST(147434.24919788091 / 8.0), + REAL_CONST(147460.37670363448 / 8.0), + REAL_CONST(147486.50536677826 / 8.0), + REAL_CONST(147512.63518720976 / 8.0), + REAL_CONST(147538.76616482646 / 8.0), + REAL_CONST(147564.89829952587 / 8.0), + REAL_CONST(147591.03159120557 / 8.0), + REAL_CONST(147617.16603976308 / 8.0), + REAL_CONST(147643.30164509601 / 8.0), + REAL_CONST(147669.43840710199 / 8.0), + REAL_CONST(147695.57632567859 / 8.0), + REAL_CONST(147721.71540072354 / 8.0), + REAL_CONST(147747.85563213445 / 8.0), + REAL_CONST(147773.99701980909 / 8.0), + REAL_CONST(147800.13956364512 / 8.0), + REAL_CONST(147826.28326354033 / 8.0), + REAL_CONST(147852.42811939248 / 8.0), + REAL_CONST(147878.57413109933 / 8.0), + REAL_CONST(147904.72129855872 / 8.0), + REAL_CONST(147930.86962166851 / 8.0), + REAL_CONST(147957.01910032652 / 8.0), + REAL_CONST(147983.16973443062 / 8.0), + REAL_CONST(148009.32152387875 / 8.0), + REAL_CONST(148035.47446856883 / 8.0), + REAL_CONST(148061.62856839882 / 8.0), + REAL_CONST(148087.78382326665 / 8.0), + REAL_CONST(148113.94023307035 / 8.0), + REAL_CONST(148140.09779770792 / 8.0), + REAL_CONST(148166.25651707739 / 8.0), + REAL_CONST(148192.41639107687 / 8.0), + REAL_CONST(148218.57741960438 / 8.0), + REAL_CONST(148244.73960255808 / 8.0), + REAL_CONST(148270.90293983606 / 8.0), + REAL_CONST(148297.0674313365 / 8.0), + REAL_CONST(148323.23307695755 / 8.0), + REAL_CONST(148349.39987659742 / 8.0), + REAL_CONST(148375.56783015432 / 8.0), + REAL_CONST(148401.73693752653 / 8.0), + REAL_CONST(148427.90719861226 / 8.0), + REAL_CONST(148454.07861330983 / 8.0), + REAL_CONST(148480.25118151752 / 8.0), + REAL_CONST(148506.42490313368 / 8.0), + REAL_CONST(148532.59977805667 / 8.0), + REAL_CONST(148558.77580618486 / 8.0), + REAL_CONST(148584.95298741665 / 8.0), + REAL_CONST(148611.13132165043 / 8.0), + REAL_CONST(148637.31080878471 / 8.0), + REAL_CONST(148663.49144871789 / 8.0), + REAL_CONST(148689.6732413485 / 8.0), + REAL_CONST(148715.85618657502 / 8.0), + REAL_CONST(148742.040284296 / 8.0), + REAL_CONST(148768.22553440998 / 8.0), + REAL_CONST(148794.41193681557 / 8.0), + REAL_CONST(148820.59949141133 / 8.0), + REAL_CONST(148846.78819809589 / 8.0), + REAL_CONST(148872.97805676793 / 8.0), + REAL_CONST(148899.16906732606 / 8.0), + REAL_CONST(148925.36122966901 / 8.0), + REAL_CONST(148951.55454369547 / 8.0), + REAL_CONST(148977.74900930419 / 8.0), + REAL_CONST(149003.9446263939 / 8.0), + REAL_CONST(149030.1413948634 / 8.0), + REAL_CONST(149056.33931461151 / 8.0), + REAL_CONST(149082.53838553699 / 8.0), + REAL_CONST(149108.73860753875 / 8.0), + REAL_CONST(149134.9399805156 / 8.0), + REAL_CONST(149161.14250436646 / 8.0), + REAL_CONST(149187.34617899026 / 8.0), + REAL_CONST(149213.5510042859 / 8.0), + REAL_CONST(149239.75698015234 / 8.0), + REAL_CONST(149265.96410648854 / 8.0), + REAL_CONST(149292.17238319354 / 8.0), + REAL_CONST(149318.38181016635 / 8.0), + REAL_CONST(149344.59238730598 / 8.0), + REAL_CONST(149370.80411451156 / 8.0), + REAL_CONST(149397.01699168212 / 8.0), + REAL_CONST(149423.23101871679 / 8.0), + REAL_CONST(149449.44619551473 / 8.0), + REAL_CONST(149475.66252197503 / 8.0), + REAL_CONST(149501.87999799693 / 8.0), + REAL_CONST(149528.0986234796 / 8.0), + REAL_CONST(149554.31839832227 / 8.0), + REAL_CONST(149580.53932242419 / 8.0), + REAL_CONST(149606.76139568459 / 8.0), + REAL_CONST(149632.98461800278 / 8.0), + REAL_CONST(149659.20898927809 / 8.0), + REAL_CONST(149685.43450940982 / 8.0), + REAL_CONST(149711.66117829733 / 8.0), + REAL_CONST(149737.88899584001 / 8.0), + REAL_CONST(149764.11796193724 / 8.0), + REAL_CONST(149790.34807648844 / 8.0), + REAL_CONST(149816.57933939309 / 8.0), + REAL_CONST(149842.81175055061 / 8.0), + REAL_CONST(149869.04530986046 / 8.0), + REAL_CONST(149895.28001722222 / 8.0), + REAL_CONST(149921.51587253538 / 8.0), + REAL_CONST(149947.75287569952 / 8.0), + REAL_CONST(149973.99102661415 / 8.0), + REAL_CONST(150000.23032517891 / 8.0), + REAL_CONST(150026.47077129342 / 8.0), + REAL_CONST(150052.71236485732 / 8.0), + REAL_CONST(150078.95510577026 / 8.0), + REAL_CONST(150105.1989939319 / 8.0), + REAL_CONST(150131.444029242 / 8.0), + REAL_CONST(150157.69021160025 / 8.0), + REAL_CONST(150183.93754090639 / 8.0), + REAL_CONST(150210.18601706024 / 8.0), + REAL_CONST(150236.43563996154 / 8.0), + REAL_CONST(150262.68640951012 / 8.0), + REAL_CONST(150288.93832560582 / 8.0), + REAL_CONST(150315.19138814852 / 8.0), + REAL_CONST(150341.44559703805 / 8.0), + REAL_CONST(150367.70095217437 / 8.0), + REAL_CONST(150393.95745345735 / 8.0), + REAL_CONST(150420.21510078697 / 8.0), + REAL_CONST(150446.47389406321 / 8.0), + REAL_CONST(150472.73383318601 / 8.0), + REAL_CONST(150498.99491805542 / 8.0), + REAL_CONST(150525.25714857146 / 8.0), + REAL_CONST(150551.52052463419 / 8.0), + REAL_CONST(150577.78504614369 / 8.0), + REAL_CONST(150604.05071300003 / 8.0), + REAL_CONST(150630.31752510337 / 8.0), + REAL_CONST(150656.58548235384 / 8.0), + REAL_CONST(150682.85458465159 / 8.0), + REAL_CONST(150709.1248318968 / 8.0), + REAL_CONST(150735.39622398972 / 8.0), + REAL_CONST(150761.66876083051 / 8.0), + REAL_CONST(150787.9424423195 / 8.0), + REAL_CONST(150814.21726835691 / 8.0), + REAL_CONST(150840.49323884305 / 8.0), + REAL_CONST(150866.77035367821 / 8.0), + REAL_CONST(150893.04861276277 / 8.0), + REAL_CONST(150919.32801599705 / 8.0), + REAL_CONST(150945.60856328148 / 8.0), + REAL_CONST(150971.89025451642 / 8.0), + REAL_CONST(150998.17308960229 / 8.0), + REAL_CONST(151024.45706843957 / 8.0), + REAL_CONST(151050.74219092872 / 8.0), + REAL_CONST(151077.02845697021 / 8.0), + REAL_CONST(151103.31586646455 / 8.0), + REAL_CONST(151129.60441931229 / 8.0), + REAL_CONST(151155.894115414 / 8.0), + REAL_CONST(151182.1849546702 / 8.0), + REAL_CONST(151208.47693698155 / 8.0), + REAL_CONST(151234.77006224863 / 8.0), + REAL_CONST(151261.06433037209 / 8.0), + REAL_CONST(151287.35974125259 / 8.0), + REAL_CONST(151313.65629479082 / 8.0), + REAL_CONST(151339.95399088747 / 8.0), + REAL_CONST(151366.25282944329 / 8.0), + REAL_CONST(151392.55281035902 / 8.0), + REAL_CONST(151418.85393353543 / 8.0), + REAL_CONST(151445.1561988733 / 8.0), + REAL_CONST(151471.45960627345 / 8.0), + REAL_CONST(151497.76415563675 / 8.0), + REAL_CONST(151524.06984686397 / 8.0), + REAL_CONST(151550.37667985607 / 8.0), + REAL_CONST(151576.68465451393 / 8.0), + REAL_CONST(151602.99377073845 / 8.0), + REAL_CONST(151629.30402843058 / 8.0), + REAL_CONST(151655.61542749128 / 8.0), + REAL_CONST(151681.92796782157 / 8.0), + REAL_CONST(151708.24164932242 / 8.0), + REAL_CONST(151734.55647189484 / 8.0), + REAL_CONST(151760.87243543993 / 8.0), + REAL_CONST(151787.18953985872 / 8.0), + REAL_CONST(151813.50778505235 / 8.0), + REAL_CONST(151839.82717092187 / 8.0), + REAL_CONST(151866.14769736846 / 8.0), + REAL_CONST(151892.46936429327 / 8.0), + REAL_CONST(151918.79217159748 / 8.0), + REAL_CONST(151945.11611918229 / 8.0), + REAL_CONST(151971.44120694889 / 8.0), + REAL_CONST(151997.76743479856 / 8.0), + REAL_CONST(152024.09480263255 / 8.0), + REAL_CONST(152050.42331035214 / 8.0), + REAL_CONST(152076.75295785864 / 8.0), + REAL_CONST(152103.08374505339 / 8.0), + REAL_CONST(152129.41567183775 / 8.0), + REAL_CONST(152155.74873811303 / 8.0), + REAL_CONST(152182.08294378067 / 8.0), + REAL_CONST(152208.41828874208 / 8.0), + REAL_CONST(152234.75477289871 / 8.0), + REAL_CONST(152261.09239615197 / 8.0), + REAL_CONST(152287.43115840337 / 8.0), + REAL_CONST(152313.77105955439 / 8.0), + REAL_CONST(152340.11209950657 / 8.0), + REAL_CONST(152366.45427816146 / 8.0), + REAL_CONST(152392.79759542056 / 8.0), + REAL_CONST(152419.14205118554 / 8.0), + REAL_CONST(152445.48764535793 / 8.0), + REAL_CONST(152471.8343778394 / 8.0), + REAL_CONST(152498.18224853161 / 8.0), + REAL_CONST(152524.53125733617 / 8.0), + REAL_CONST(152550.88140415482 / 8.0), + REAL_CONST(152577.23268888926 / 8.0), + REAL_CONST(152603.58511144121 / 8.0), + REAL_CONST(152629.93867171241 / 8.0), + REAL_CONST(152656.29336960468 / 8.0), + REAL_CONST(152682.64920501978 / 8.0), + REAL_CONST(152709.00617785956 / 8.0), + REAL_CONST(152735.36428802583 / 8.0), + REAL_CONST(152761.72353542043 / 8.0), + REAL_CONST(152788.08391994529 / 8.0), + REAL_CONST(152814.44544150229 / 8.0), + REAL_CONST(152840.80809999333 / 8.0), + REAL_CONST(152867.17189532038 / 8.0), + REAL_CONST(152893.53682738543 / 8.0), + REAL_CONST(152919.90289609041 / 8.0), + REAL_CONST(152946.27010133737 / 8.0), + REAL_CONST(152972.63844302832 / 8.0), + REAL_CONST(152999.00792106529 / 8.0), + REAL_CONST(153025.37853535041 / 8.0), + REAL_CONST(153051.7502857857 / 8.0), + REAL_CONST(153078.12317227334 / 8.0), + REAL_CONST(153104.4971947154 / 8.0), + REAL_CONST(153130.8723530141 / 8.0), + REAL_CONST(153157.24864707157 / 8.0), + REAL_CONST(153183.62607679001 / 8.0), + REAL_CONST(153210.00464207167 / 8.0), + REAL_CONST(153236.38434281875 / 8.0), + REAL_CONST(153262.76517893354 / 8.0), + REAL_CONST(153289.14715031831 / 8.0), + REAL_CONST(153315.53025687535 / 8.0), + REAL_CONST(153341.91449850702 / 8.0), + REAL_CONST(153368.2998751156 / 8.0), + REAL_CONST(153394.68638660354 / 8.0), + REAL_CONST(153421.07403287315 / 8.0), + REAL_CONST(153447.46281382689 / 8.0), + REAL_CONST(153473.85272936718 / 8.0), + REAL_CONST(153500.24377939643 / 8.0), + REAL_CONST(153526.63596381716 / 8.0), + REAL_CONST(153553.02928253182 / 8.0), + REAL_CONST(153579.42373544298 / 8.0), + REAL_CONST(153605.81932245308 / 8.0), + REAL_CONST(153632.21604346478 / 8.0), + REAL_CONST(153658.61389838057 / 8.0), + REAL_CONST(153685.0128871031 / 8.0), + REAL_CONST(153711.41300953497 / 8.0), + REAL_CONST(153737.81426557881 / 8.0), + REAL_CONST(153764.21665513728 / 8.0), + REAL_CONST(153790.62017811305 / 8.0), + REAL_CONST(153817.02483440886 / 8.0), + REAL_CONST(153843.43062392739 / 8.0), + REAL_CONST(153869.83754657139 / 8.0), + REAL_CONST(153896.24560224367 / 8.0), + REAL_CONST(153922.65479084692 / 8.0), + REAL_CONST(153949.06511228404 / 8.0), + REAL_CONST(153975.4765664578 / 8.0), + REAL_CONST(154001.88915327107 / 8.0), + REAL_CONST(154028.30287262669 / 8.0), + REAL_CONST(154054.71772442761 / 8.0), + REAL_CONST(154081.13370857667 / 8.0), + REAL_CONST(154107.55082497682 / 8.0), + REAL_CONST(154133.96907353101 / 8.0), + REAL_CONST(154160.38845414223 / 8.0), + REAL_CONST(154186.80896671346 / 8.0), + REAL_CONST(154213.23061114774 / 8.0), + REAL_CONST(154239.65338734805 / 8.0), + REAL_CONST(154266.07729521746 / 8.0), + REAL_CONST(154292.50233465908 / 8.0), + REAL_CONST(154318.92850557598 / 8.0), + REAL_CONST(154345.35580787127 / 8.0), + REAL_CONST(154371.7842414481 / 8.0), + REAL_CONST(154398.21380620965 / 8.0), + REAL_CONST(154424.64450205903 / 8.0), + REAL_CONST(154451.07632889951 / 8.0), + REAL_CONST(154477.50928663427 / 8.0), + REAL_CONST(154503.94337516659 / 8.0), + REAL_CONST(154530.37859439969 / 8.0), + REAL_CONST(154556.81494423689 / 8.0), + REAL_CONST(154583.25242458144 / 8.0), + REAL_CONST(154609.69103533673 / 8.0), + REAL_CONST(154636.13077640603 / 8.0), + REAL_CONST(154662.57164769279 / 8.0), + REAL_CONST(154689.01364910032 / 8.0), + REAL_CONST(154715.45678053208 / 8.0), + REAL_CONST(154741.90104189145 / 8.0), + REAL_CONST(154768.34643308193 / 8.0), + REAL_CONST(154794.79295400696 / 8.0), + REAL_CONST(154821.24060457002 / 8.0), + REAL_CONST(154847.68938467462 / 8.0), + REAL_CONST(154874.13929422433 / 8.0), + REAL_CONST(154900.59033312264 / 8.0), + REAL_CONST(154927.04250127316 / 8.0), + REAL_CONST(154953.49579857948 / 8.0), + REAL_CONST(154979.95022494521 / 8.0), + REAL_CONST(155006.40578027396 / 8.0), + REAL_CONST(155032.86246446942 / 8.0), + REAL_CONST(155059.32027743524 / 8.0), + REAL_CONST(155085.77921907514 / 8.0), + REAL_CONST(155112.2392892928 / 8.0), + REAL_CONST(155138.70048799197 / 8.0), + REAL_CONST(155165.16281507642 / 8.0), + REAL_CONST(155191.62627044989 / 8.0), + REAL_CONST(155218.09085401625 / 8.0), + REAL_CONST(155244.55656567923 / 8.0), + REAL_CONST(155271.02340534274 / 8.0), + REAL_CONST(155297.49137291059 / 8.0), + REAL_CONST(155323.96046828668 / 8.0), + REAL_CONST(155350.4306913749 / 8.0), + REAL_CONST(155376.90204207919 / 8.0), + REAL_CONST(155403.37452030348 / 8.0), + REAL_CONST(155429.84812595171 / 8.0), + REAL_CONST(155456.32285892789 / 8.0), + REAL_CONST(155482.79871913602 / 8.0), + REAL_CONST(155509.27570648011 / 8.0), + REAL_CONST(155535.75382086422 / 8.0), + REAL_CONST(155562.23306219239 / 8.0), + REAL_CONST(155588.71343036872 / 8.0), + REAL_CONST(155615.19492529731 / 8.0), + REAL_CONST(155641.67754688227 / 8.0), + REAL_CONST(155668.16129502779 / 8.0), + REAL_CONST(155694.64616963797 / 8.0), + REAL_CONST(155721.13217061706 / 8.0), + REAL_CONST(155747.61929786921 / 8.0), + REAL_CONST(155774.10755129869 / 8.0), + REAL_CONST(155800.59693080973 / 8.0), + REAL_CONST(155827.08743630661 / 8.0), + REAL_CONST(155853.57906769359 / 8.0), + REAL_CONST(155880.07182487496 / 8.0), + REAL_CONST(155906.56570775513 / 8.0), + REAL_CONST(155933.06071623837 / 8.0), + REAL_CONST(155959.55685022907 / 8.0), + REAL_CONST(155986.05410963166 / 8.0), + REAL_CONST(156012.5524943505 / 8.0), + REAL_CONST(156039.05200429002 / 8.0), + REAL_CONST(156065.55263935472 / 8.0), + REAL_CONST(156092.054399449 / 8.0), + REAL_CONST(156118.5572844774 / 8.0), + REAL_CONST(156145.06129434443 / 8.0), + REAL_CONST(156171.5664289546 / 8.0), + REAL_CONST(156198.07268821247 / 8.0), + REAL_CONST(156224.5800720226 / 8.0), + REAL_CONST(156251.08858028959 / 8.0), + REAL_CONST(156277.59821291809 / 8.0), + REAL_CONST(156304.10896981266 / 8.0), + REAL_CONST(156330.62085087801 / 8.0), + REAL_CONST(156357.1338560188 / 8.0), + REAL_CONST(156383.64798513969 / 8.0), + REAL_CONST(156410.16323814544 / 8.0), + REAL_CONST(156436.67961494075 / 8.0), + REAL_CONST(156463.1971154304 / 8.0), + REAL_CONST(156489.71573951913 / 8.0), + REAL_CONST(156516.23548711176 / 8.0), + REAL_CONST(156542.75635811311 / 8.0), + REAL_CONST(156569.27835242799 / 8.0), + REAL_CONST(156595.80146996127 / 8.0), + REAL_CONST(156622.32571061782 / 8.0), + REAL_CONST(156648.85107430254 / 8.0), + REAL_CONST(156675.37756092031 / 8.0), + REAL_CONST(156701.90517037612 / 8.0), + REAL_CONST(156728.43390257491 / 8.0), + REAL_CONST(156754.96375742162 / 8.0), + REAL_CONST(156781.49473482129 / 8.0), + REAL_CONST(156808.02683467892 / 8.0), + REAL_CONST(156834.5600568995 / 8.0), + REAL_CONST(156861.09440138817 / 8.0), + REAL_CONST(156887.62986804993 / 8.0), + REAL_CONST(156914.16645678994 / 8.0), + REAL_CONST(156940.70416751326 / 8.0), + REAL_CONST(156967.24300012505 / 8.0), + REAL_CONST(156993.78295453047 / 8.0), + REAL_CONST(157020.32403063469 / 8.0), + REAL_CONST(157046.8662283429 / 8.0), + REAL_CONST(157073.40954756032 / 8.0), + REAL_CONST(157099.9539881922 / 8.0), + REAL_CONST(157126.49955014378 / 8.0), + REAL_CONST(157153.04623332032 / 8.0), + REAL_CONST(157179.59403762716 / 8.0), + REAL_CONST(157206.14296296958 / 8.0), + REAL_CONST(157232.69300925292 / 8.0), + REAL_CONST(157259.24417638258 / 8.0), + REAL_CONST(157285.79646426387 / 8.0), + REAL_CONST(157312.34987280221 / 8.0), + REAL_CONST(157338.90440190304 / 8.0), + REAL_CONST(157365.46005147175 / 8.0), + REAL_CONST(157392.01682141385 / 8.0), + REAL_CONST(157418.57471163478 / 8.0), + REAL_CONST(157445.13372204005 / 8.0), + REAL_CONST(157471.69385253513 / 8.0), + REAL_CONST(157498.25510302564 / 8.0), + REAL_CONST(157524.81747341706 / 8.0), + REAL_CONST(157551.38096361503 / 8.0), + REAL_CONST(157577.9455735251 / 8.0), + REAL_CONST(157604.51130305286 / 8.0), + REAL_CONST(157631.07815210402 / 8.0), + REAL_CONST(157657.64612058419 / 8.0), + REAL_CONST(157684.21520839902 / 8.0), + REAL_CONST(157710.78541545427 / 8.0), + REAL_CONST(157737.35674165559 / 8.0), + REAL_CONST(157763.92918690876 / 8.0), + REAL_CONST(157790.50275111952 / 8.0), + REAL_CONST(157817.07743419363 / 8.0), + REAL_CONST(157843.65323603692 / 8.0), + REAL_CONST(157870.23015655516 / 8.0), + REAL_CONST(157896.80819565422 / 8.0), + REAL_CONST(157923.3873532399 / 8.0), + REAL_CONST(157949.96762921812 / 8.0), + REAL_CONST(157976.54902349479 / 8.0), + REAL_CONST(158003.13153597576 / 8.0), + REAL_CONST(158029.71516656701 / 8.0), + REAL_CONST(158056.29991517449 / 8.0), + REAL_CONST(158082.88578170416 / 8.0), + REAL_CONST(158109.47276606198 / 8.0), + REAL_CONST(158136.06086815402 / 8.0), + REAL_CONST(158162.65008788629 / 8.0), + REAL_CONST(158189.24042516484 / 8.0), + REAL_CONST(158215.83187989573 / 8.0), + REAL_CONST(158242.42445198505 / 8.0), + REAL_CONST(158269.01814133892 / 8.0), + REAL_CONST(158295.61294786347 / 8.0), + REAL_CONST(158322.20887146486 / 8.0), + REAL_CONST(158348.80591204923 / 8.0), + REAL_CONST(158375.4040695228 / 8.0), + REAL_CONST(158402.00334379176 / 8.0), + REAL_CONST(158428.60373476235 / 8.0), + REAL_CONST(158455.2052423408 / 8.0), + REAL_CONST(158481.80786643337 / 8.0), + REAL_CONST(158508.41160694641 / 8.0), + REAL_CONST(158535.01646378616 / 8.0), + REAL_CONST(158561.62243685898 / 8.0), + REAL_CONST(158588.2295260712 / 8.0), + REAL_CONST(158614.8377313292 / 8.0), + REAL_CONST(158641.44705253936 / 8.0), + REAL_CONST(158668.05748960807 / 8.0), + REAL_CONST(158694.66904244179 / 8.0), + REAL_CONST(158721.28171094693 / 8.0), + REAL_CONST(158747.89549502998 / 8.0), + REAL_CONST(158774.5103945974 / 8.0), + REAL_CONST(158801.12640955573 / 8.0), + REAL_CONST(158827.74353981143 / 8.0), + REAL_CONST(158854.36178527112 / 8.0), + REAL_CONST(158880.9811458413 / 8.0), + REAL_CONST(158907.60162142856 / 8.0), + REAL_CONST(158934.22321193956 / 8.0), + REAL_CONST(158960.84591728085 / 8.0), + REAL_CONST(158987.46973735912 / 8.0), + REAL_CONST(159014.09467208097 / 8.0), + REAL_CONST(159040.72072135314 / 8.0), + REAL_CONST(159067.3478850823 / 8.0), + REAL_CONST(159093.97616317519 / 8.0), + REAL_CONST(159120.60555553852 / 8.0), + REAL_CONST(159147.23606207906 / 8.0), + REAL_CONST(159173.8676827036 / 8.0), + REAL_CONST(159200.50041731889 / 8.0), + REAL_CONST(159227.13426583182 / 8.0), + REAL_CONST(159253.76922814918 / 8.0), + REAL_CONST(159280.40530417781 / 8.0), + REAL_CONST(159307.04249382461 / 8.0), + REAL_CONST(159333.68079699649 / 8.0), + REAL_CONST(159360.32021360032 / 8.0), + REAL_CONST(159386.96074354305 / 8.0), + REAL_CONST(159413.60238673165 / 8.0), + REAL_CONST(159440.24514307309 / 8.0), + REAL_CONST(159466.88901247433 / 8.0), + REAL_CONST(159493.53399484244 / 8.0), + REAL_CONST(159520.18009008438 / 8.0), + REAL_CONST(159546.82729810724 / 8.0), + REAL_CONST(159573.47561881805 / 8.0), + REAL_CONST(159600.12505212394 / 8.0), + REAL_CONST(159626.77559793202 / 8.0), + REAL_CONST(159653.42725614941 / 8.0), + REAL_CONST(159680.08002668325 / 8.0), + REAL_CONST(159706.73390944069 / 8.0), + REAL_CONST(159733.38890432892 / 8.0), + REAL_CONST(159760.04501125516 / 8.0), + REAL_CONST(159786.70223012666 / 8.0), + REAL_CONST(159813.36056085059 / 8.0), + REAL_CONST(159840.02000333427 / 8.0), + REAL_CONST(159866.68055748497 / 8.0), + REAL_CONST(159893.34222320997 / 8.0), + REAL_CONST(159920.00500041663 / 8.0), + REAL_CONST(159946.66888901225 / 8.0), + REAL_CONST(159973.33388890422 / 8.0), + REAL_CONST(159999.99999999988 / 8.0), + REAL_CONST(160026.66722220668 / 8.0), + REAL_CONST(160053.33555543202 / 8.0), + REAL_CONST(160080.0049995833 / 8.0), + REAL_CONST(160106.67555456801 / 8.0), + REAL_CONST(160133.3472202936 / 8.0), + REAL_CONST(160160.0199966676 / 8.0), + REAL_CONST(160186.6938835975 / 8.0), + REAL_CONST(160213.36888099083 / 8.0), + REAL_CONST(160240.04498875517 / 8.0), + REAL_CONST(160266.72220679806 / 8.0), + REAL_CONST(160293.40053502709 / 8.0), + REAL_CONST(160320.07997334987 / 8.0), + REAL_CONST(160346.76052167406 / 8.0), + REAL_CONST(160373.44217990729 / 8.0), + REAL_CONST(160400.1249479572 / 8.0), + REAL_CONST(160426.80882573154 / 8.0), + REAL_CONST(160453.49381313793 / 8.0), + REAL_CONST(160480.17991008417 / 8.0), + REAL_CONST(160506.86711647795 / 8.0), + REAL_CONST(160533.55543222709 / 8.0), + REAL_CONST(160560.24485723933 / 8.0), + REAL_CONST(160586.93539142248 / 8.0), + REAL_CONST(160613.62703468435 / 8.0), + REAL_CONST(160640.31978693281 / 8.0), + REAL_CONST(160667.01364807569 / 8.0), + REAL_CONST(160693.70861802087 / 8.0), + REAL_CONST(160720.40469667627 / 8.0), + REAL_CONST(160747.1018839498 / 8.0), + REAL_CONST(160773.80017974938 / 8.0), + REAL_CONST(160800.49958398298 / 8.0), + REAL_CONST(160827.20009655855 / 8.0), + REAL_CONST(160853.90171738411 / 8.0), + REAL_CONST(160880.60444636765 / 8.0), + REAL_CONST(160907.30828341722 / 8.0), + REAL_CONST(160934.01322844089 / 8.0), + REAL_CONST(160960.71928134665 / 8.0), + REAL_CONST(160987.42644204266 / 8.0), + REAL_CONST(161014.13471043704 / 8.0), + REAL_CONST(161040.84408643784 / 8.0), + REAL_CONST(161067.55456995327 / 8.0), + REAL_CONST(161094.26616089148 / 8.0), + REAL_CONST(161120.97885916062 / 8.0), + REAL_CONST(161147.69266466892 / 8.0), + REAL_CONST(161174.40757732463 / 8.0), + REAL_CONST(161201.12359703594 / 8.0), + REAL_CONST(161227.84072371112 / 8.0), + REAL_CONST(161254.55895725847 / 8.0), + REAL_CONST(161281.27829758628 / 8.0), + REAL_CONST(161307.99874460287 / 8.0), + REAL_CONST(161334.72029821656 / 8.0), + REAL_CONST(161361.44295833571 / 8.0), + REAL_CONST(161388.1667248687 / 8.0), + REAL_CONST(161414.89159772391 / 8.0), + REAL_CONST(161441.61757680977 / 8.0), + REAL_CONST(161468.34466203468 / 8.0), + REAL_CONST(161495.07285330712 / 8.0), + REAL_CONST(161521.80215053557 / 8.0), + REAL_CONST(161548.53255362847 / 8.0), + REAL_CONST(161575.26406249436 / 8.0), + REAL_CONST(161601.99667704175 / 8.0), + REAL_CONST(161628.7303971792 / 8.0), + REAL_CONST(161655.46522281526 / 8.0), + REAL_CONST(161682.20115385848 / 8.0), + REAL_CONST(161708.93819021754 / 8.0), + REAL_CONST(161735.67633180099 / 8.0), + REAL_CONST(161762.41557851751 / 8.0), + REAL_CONST(161789.15593027571 / 8.0), + REAL_CONST(161815.89738698432 / 8.0), + REAL_CONST(161842.63994855201 / 8.0), + REAL_CONST(161869.38361488748 / 8.0), + REAL_CONST(161896.1283858995 / 8.0), + REAL_CONST(161922.87426149679 / 8.0), + REAL_CONST(161949.62124158812 / 8.0), + REAL_CONST(161976.36932608229 / 8.0), + REAL_CONST(162003.1185148881 / 8.0), + REAL_CONST(162029.8688079144 / 8.0), + REAL_CONST(162056.62020507001 / 8.0), + REAL_CONST(162083.37270626382 / 8.0), + REAL_CONST(162110.12631140469 / 8.0), + REAL_CONST(162136.88102040152 / 8.0), + REAL_CONST(162163.63683316324 / 8.0), + REAL_CONST(162190.39374959879 / 8.0), + REAL_CONST(162217.15176961714 / 8.0), + REAL_CONST(162243.91089312723 / 8.0), + REAL_CONST(162270.67112003808 / 8.0), + REAL_CONST(162297.43245025873 / 8.0), + REAL_CONST(162324.19488369819 / 8.0), + REAL_CONST(162350.9584202655 / 8.0), + REAL_CONST(162377.72305986975 / 8.0), + REAL_CONST(162404.48880242003 / 8.0), + REAL_CONST(162431.25564782543 / 8.0), + REAL_CONST(162458.02359599507 / 8.0), + REAL_CONST(162484.79264683815 / 8.0), + REAL_CONST(162511.56280026378 / 8.0), + REAL_CONST(162538.33405618116 / 8.0), + REAL_CONST(162565.10641449949 / 8.0), + REAL_CONST(162591.87987512801 / 8.0), + REAL_CONST(162618.65443797593 / 8.0), + REAL_CONST(162645.43010295252 / 8.0), + REAL_CONST(162672.20686996708 / 8.0), + REAL_CONST(162698.98473892888 / 8.0), + REAL_CONST(162725.76370974723 / 8.0), + REAL_CONST(162752.54378233149 / 8.0), + REAL_CONST(162779.32495659095 / 8.0), + REAL_CONST(162806.10723243505 / 8.0), + REAL_CONST(162832.89060977317 / 8.0), + REAL_CONST(162859.67508851466 / 8.0), + REAL_CONST(162886.46066856899 / 8.0), + REAL_CONST(162913.24734984562 / 8.0), + REAL_CONST(162940.03513225398 / 8.0), + REAL_CONST(162966.82401570358 / 8.0), + REAL_CONST(162993.6140001039 / 8.0), + REAL_CONST(163020.40508536444 / 8.0), + REAL_CONST(163047.19727139481 / 8.0), + REAL_CONST(163073.99055810447 / 8.0), + REAL_CONST(163100.78494540305 / 8.0), + REAL_CONST(163127.58043320014 / 8.0), + REAL_CONST(163154.37702140535 / 8.0), + REAL_CONST(163181.17470992831 / 8.0), + REAL_CONST(163207.97349867865 / 8.0), + REAL_CONST(163234.77338756606 / 8.0), + REAL_CONST(163261.57437650024 / 8.0), + REAL_CONST(163288.37646539087 / 8.0), + REAL_CONST(163315.17965414765 / 8.0), + REAL_CONST(163341.98394268038 / 8.0), + REAL_CONST(163368.78933089875 / 8.0), + REAL_CONST(163395.59581871261 / 8.0), + REAL_CONST(163422.40340603172 / 8.0), + REAL_CONST(163449.2120927659 / 8.0), + REAL_CONST(163476.02187882498 / 8.0), + REAL_CONST(163502.83276411882 / 8.0), + REAL_CONST(163529.6447485573 / 8.0), + REAL_CONST(163556.45783205028 / 8.0), + REAL_CONST(163583.2720145077 / 8.0), + REAL_CONST(163610.08729583945 / 8.0), + REAL_CONST(163636.90367595552 / 8.0), + REAL_CONST(163663.72115476584 / 8.0), + REAL_CONST(163690.53973218042 / 8.0), + REAL_CONST(163717.35940810922 / 8.0), + REAL_CONST(163744.18018246227 / 8.0), + REAL_CONST(163771.00205514964 / 8.0), + REAL_CONST(163797.82502608138 / 8.0), + REAL_CONST(163824.64909516752 / 8.0), + REAL_CONST(163851.4742623182 / 8.0), + REAL_CONST(163878.3005274435 / 8.0), + REAL_CONST(163905.12789045356 / 8.0), + REAL_CONST(163931.95635125853 / 8.0), + REAL_CONST(163958.78590976857 / 8.0), + REAL_CONST(163985.61656589387 / 8.0), + REAL_CONST(164012.44831954464 / 8.0), + REAL_CONST(164039.28117063109 / 8.0), + REAL_CONST(164066.11511906344 / 8.0), + REAL_CONST(164092.95016475199 / 8.0), + REAL_CONST(164119.78630760699 / 8.0), + REAL_CONST(164146.62354753874 / 8.0), + REAL_CONST(164173.46188445756 / 8.0), + REAL_CONST(164200.30131827376 / 8.0), + REAL_CONST(164227.14184889771 / 8.0), + REAL_CONST(164253.98347623978 / 8.0), + REAL_CONST(164280.82620021031 / 8.0), + REAL_CONST(164307.67002071979 / 8.0), + REAL_CONST(164334.51493767856 / 8.0), + REAL_CONST(164361.3609509971 / 8.0), + REAL_CONST(164388.20806058586 / 8.0), + REAL_CONST(164415.05626635533 / 8.0), + REAL_CONST(164441.905568216 / 8.0), + REAL_CONST(164468.75596607837 / 8.0), + REAL_CONST(164495.607459853 / 8.0), + REAL_CONST(164522.4600494504 / 8.0), + REAL_CONST(164549.31373478117 / 8.0), + REAL_CONST(164576.16851575591 / 8.0), + REAL_CONST(164603.02439228518 / 8.0), + REAL_CONST(164629.88136427966 / 8.0), + REAL_CONST(164656.73943164994 / 8.0), + REAL_CONST(164683.59859430668 / 8.0), + REAL_CONST(164710.45885216061 / 8.0), + REAL_CONST(164737.32020512238 / 8.0), + REAL_CONST(164764.1826531027 / 8.0), + REAL_CONST(164791.04619601235 / 8.0), + REAL_CONST(164817.91083376206 / 8.0), + REAL_CONST(164844.77656626256 / 8.0), + REAL_CONST(164871.64339342469 / 8.0), + REAL_CONST(164898.51131515924 / 8.0), + REAL_CONST(164925.38033137703 / 8.0), + REAL_CONST(164952.25044198887 / 8.0), + REAL_CONST(164979.1216469057 / 8.0), + REAL_CONST(165005.9939460383 / 8.0), + REAL_CONST(165032.86733929763 / 8.0), + REAL_CONST(165059.7418265946 / 8.0), + REAL_CONST(165086.61740784015 / 8.0), + REAL_CONST(165113.4940829452 / 8.0) + #endif +}; +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static real_t tns_coef_0_3[] = {COEF_CONST(0.0), COEF_CONST(0.4338837391), COEF_CONST(0.7818314825), COEF_CONST(0.9749279122), COEF_CONST(-0.9848077530), COEF_CONST(-0.8660254038), + COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433), COEF_CONST(-0.4338837391), COEF_CONST(-0.7818314825), COEF_CONST(-0.9749279122), COEF_CONST(-0.9749279122), + COEF_CONST(-0.9848077530), COEF_CONST(-0.8660254038), COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433)}; +static real_t tns_coef_0_4[] = {COEF_CONST(0.0), COEF_CONST(0.2079116908), COEF_CONST(0.4067366431), COEF_CONST(0.5877852523), COEF_CONST(0.7431448255), COEF_CONST(0.8660254038), + COEF_CONST(0.9510565163), COEF_CONST(0.9945218954), COEF_CONST(-0.9957341763), COEF_CONST(-0.9618256432), COEF_CONST(-0.8951632914), COEF_CONST(-0.7980172273), + COEF_CONST(-0.6736956436), COEF_CONST(-0.5264321629), COEF_CONST(-0.3612416662), COEF_CONST(-0.1837495178)}; +static real_t tns_coef_1_3[] = {COEF_CONST(0.0), COEF_CONST(0.4338837391), COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433), COEF_CONST(0.9749279122), COEF_CONST(0.7818314825), + COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433), COEF_CONST(-0.4338837391), COEF_CONST(-0.7818314825), COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433), + COEF_CONST(-0.7818314825), COEF_CONST(-0.4338837391), COEF_CONST(-0.6427876097), COEF_CONST(-0.3420201433)}; +static real_t tns_coef_1_4[] = {COEF_CONST(0.0), COEF_CONST(0.2079116908), COEF_CONST(0.4067366431), COEF_CONST(0.5877852523), COEF_CONST(-0.6736956436), COEF_CONST(-0.5264321629), + COEF_CONST(-0.3612416662), COEF_CONST(-0.1837495178), COEF_CONST(0.9945218954), COEF_CONST(0.9510565163), COEF_CONST(0.8660254038), COEF_CONST(0.7431448255), + COEF_CONST(-0.6736956436), COEF_CONST(-0.5264321629), COEF_CONST(-0.3612416662), COEF_CONST(-0.1837495178)}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +static rvlc_huff_table book_escape[] = { + /*index length codeword */ + {1, 2, 0}, {0, 2, 2}, {3, 3, 2}, {2, 3, 6}, {4, 4, 14}, {7, 5, 13}, {6, 5, 15}, {5, 5, 31}, {11, 6, 24}, {10, 6, 25}, + {9, 6, 29}, {8, 6, 61}, {13, 7, 56}, {12, 7, 120}, {15, 8, 114}, {14, 8, 242}, {17, 9, 230}, {16, 9, 486}, {19, 10, 463}, {18, 10, 974}, + {22, 11, 925}, {20, 11, 1950}, {21, 11, 1951}, {23, 12, 1848}, {25, 13, 3698}, {24, 14, 7399}, {26, 15, 14797}, {49, 19, 236736}, {50, 19, 236737}, {51, 19, 236738}, + {52, 19, 236739}, {53, 19, 236740}, {27, 20, 473482}, {28, 20, 473483}, {29, 20, 473484}, {30, 20, 473485}, {31, 20, 473486}, {32, 20, 473487}, {33, 20, 473488}, {34, 20, 473489}, + {35, 20, 473490}, {36, 20, 473491}, {37, 20, 473492}, {38, 20, 473493}, {39, 20, 473494}, {40, 20, 473495}, {41, 20, 473496}, {42, 20, 473497}, {43, 20, 473498}, {44, 20, 473499}, + {45, 20, 473500}, {46, 20, 473501}, {47, 20, 473502}, {48, 20, 473503}, {99, 21, 0} /* Shouldn't come this far */ +}; +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +static const real_t dct4_64_tab[] = {COEF_CONST(0.999924719333649), COEF_CONST(0.998118102550507), COEF_CONST(0.993906974792480), COEF_CONST(0.987301409244537), COEF_CONST(0.978317379951477), + COEF_CONST(0.966976463794708), COEF_CONST(0.953306019306183), COEF_CONST(0.937339007854462), COEF_CONST(0.919113874435425), COEF_CONST(0.898674488067627), + COEF_CONST(0.876070082187653), COEF_CONST(0.851355195045471), COEF_CONST(0.824589252471924), COEF_CONST(0.795836925506592), COEF_CONST(0.765167236328125), + COEF_CONST(0.732654273509979), COEF_CONST(0.698376238346100), COEF_CONST(0.662415742874146), COEF_CONST(0.624859452247620), COEF_CONST(0.585797846317291), + COEF_CONST(0.545324981212616), COEF_CONST(0.503538429737091), COEF_CONST(0.460538715124130), COEF_CONST(0.416429549455643), COEF_CONST(0.371317148208618), + COEF_CONST(0.325310230255127), COEF_CONST(0.278519600629807), COEF_CONST(0.231058135628700), COEF_CONST(0.183039888739586), COEF_CONST(0.134580686688423), + COEF_CONST(0.085797272622585), COEF_CONST(0.036807164549828), COEF_CONST(-1.012196302413940), COEF_CONST(-1.059438824653626), COEF_CONST(-1.104129195213318), + COEF_CONST(-1.146159529685974), COEF_CONST(-1.185428738594055), COEF_CONST(-1.221842169761658), COEF_CONST(-1.255311965942383), COEF_CONST(-1.285757660865784), + COEF_CONST(-1.313105940818787), COEF_CONST(-1.337290763854981), COEF_CONST(-1.358253836631775), COEF_CONST(-1.375944852828980), COEF_CONST(-1.390321016311646), + COEF_CONST(-1.401347875595093), COEF_CONST(-1.408998727798462), COEF_CONST(-1.413255214691162), COEF_CONST(-1.414107084274292), COEF_CONST(-1.411552190780640), + COEF_CONST(-1.405596733093262), COEF_CONST(-1.396255016326904), COEF_CONST(-1.383549690246582), COEF_CONST(-1.367511272430420), COEF_CONST(-1.348178386688232), + COEF_CONST(-1.325597524642944), COEF_CONST(-1.299823284149170), COEF_CONST(-1.270917654037476), COEF_CONST(-1.238950133323669), COEF_CONST(-1.203998088836670), + COEF_CONST(-1.166145324707031), COEF_CONST(-1.125483393669128), COEF_CONST(-1.082109928131104), COEF_CONST(-1.036129593849182), COEF_CONST(-0.987653195858002), + COEF_CONST(-0.936797380447388), COEF_CONST(-0.883684754371643), COEF_CONST(-0.828443288803101), COEF_CONST(-0.771206021308899), COEF_CONST(-0.712110757827759), + COEF_CONST(-0.651300072669983), COEF_CONST(-0.588920354843140), COEF_CONST(-0.525121808052063), COEF_CONST(-0.460058242082596), COEF_CONST(-0.393886327743530), + COEF_CONST(-0.326765477657318), COEF_CONST(-0.258857429027557), COEF_CONST(-0.190325915813446), COEF_CONST(-0.121335685253143), COEF_CONST(-0.052053272724152), + COEF_CONST(0.017354607582092), COEF_CONST(0.086720645427704), COEF_CONST(0.155877828598022), COEF_CONST(0.224659323692322), COEF_CONST(0.292899727821350), + COEF_CONST(0.360434412956238), COEF_CONST(0.427100926637650), COEF_CONST(0.492738455533981), COEF_CONST(0.557188928127289), COEF_CONST(0.620297133922577), + COEF_CONST(0.681910991668701), COEF_CONST(0.741881847381592), COEF_CONST(0.800065577030182), COEF_CONST(0.856321990489960), COEF_CONST(0.910515367984772), + COEF_CONST(0.962515234947205), COEF_CONST(1.000000000000000), COEF_CONST(0.998795449733734), COEF_CONST(0.995184719562531), COEF_CONST(0.989176511764526), + COEF_CONST(0.980785250663757), COEF_CONST(0.970031261444092), COEF_CONST(0.956940352916718), COEF_CONST(0.941544055938721), COEF_CONST(0.923879504203796), + COEF_CONST(0.903989315032959), COEF_CONST(0.881921231746674), COEF_CONST(0.857728600502014), COEF_CONST(0.831469595432281), COEF_CONST(0.803207516670227), + COEF_CONST(0.773010432720184), COEF_CONST(0.740951120853424), COEF_CONST(0.707106769084930), COEF_CONST(0.671558916568756), COEF_CONST(0.634393274784088), + COEF_CONST(0.595699310302734), COEF_CONST(0.555570185184479), COEF_CONST(0.514102697372437), COEF_CONST(0.471396654844284), COEF_CONST(0.427555114030838), + COEF_CONST(0.382683426141739), COEF_CONST(0.336889833211899), COEF_CONST(0.290284633636475), COEF_CONST(0.242980122566223), COEF_CONST(0.195090234279633), + COEF_CONST(0.146730497479439), COEF_CONST(0.098017133772373), COEF_CONST(0.049067649990320), COEF_CONST(-1.000000000000000), COEF_CONST(-1.047863125801086), + COEF_CONST(-1.093201875686646), COEF_CONST(-1.135906934738159), COEF_CONST(-1.175875544548035), COEF_CONST(-1.213011503219605), COEF_CONST(-1.247225046157837), + COEF_CONST(-1.278433918952942), COEF_CONST(-1.306562900543213), COEF_CONST(-1.331544399261475), COEF_CONST(-1.353317975997925), COEF_CONST(-1.371831417083740), + COEF_CONST(-1.387039899826050), COEF_CONST(-1.398906826972961), COEF_CONST(-1.407403707504273), COEF_CONST(-1.412510156631470), COEF_CONST(0), + COEF_CONST(-1.412510156631470), COEF_CONST(-1.407403707504273), COEF_CONST(-1.398906826972961), COEF_CONST(-1.387039899826050), COEF_CONST(-1.371831417083740), + COEF_CONST(-1.353317975997925), COEF_CONST(-1.331544399261475), COEF_CONST(-1.306562900543213), COEF_CONST(-1.278433918952942), COEF_CONST(-1.247225046157837), + COEF_CONST(-1.213011384010315), COEF_CONST(-1.175875544548035), COEF_CONST(-1.135907053947449), COEF_CONST(-1.093201875686646), COEF_CONST(-1.047863125801086), + COEF_CONST(-1.000000000000000), COEF_CONST(-0.949727773666382), COEF_CONST(-0.897167563438416), COEF_CONST(-0.842446029186249), COEF_CONST(-0.785694956779480), + COEF_CONST(-0.727051079273224), COEF_CONST(-0.666655659675598), COEF_CONST(-0.604654192924500), COEF_CONST(-0.541196048259735), COEF_CONST(-0.476434230804443), + COEF_CONST(-0.410524487495422), COEF_CONST(-0.343625843524933), COEF_CONST(-0.275899350643158), COEF_CONST(-0.207508206367493), COEF_CONST(-0.138617098331451), + COEF_CONST(-0.069392144680023), COEF_CONST(0.00000000000000), COEF_CONST(0.069392263889313), COEF_CONST(0.138617157936096), COEF_CONST(0.207508206367493), + COEF_CONST(0.275899469852448), COEF_CONST(0.343625962734222), COEF_CONST(0.410524636507034), COEF_CONST(0.476434201002121), COEF_CONST(0.541196107864380), + COEF_CONST(0.604654192924500), COEF_CONST(0.666655719280243), COEF_CONST(0.727051138877869), COEF_CONST(0.785695075988770), COEF_CONST(0.842446029186249), + COEF_CONST(0.897167563438416), COEF_CONST(0.949727773666382)}; + #endif // SBR_LOW_POWER +#endif // SBR_DEC +#ifdef SSR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sine_short_32[] = {0.0245412290, 0.0735645667, 0.1224106774, 0.1709618866, 0.2191012502, 0.2667127550, 0.3136817515, 0.3598950505, 0.4052413106, 0.4496113360, 0.4928981960, + 0.5349976420, 0.5758082271, 0.6152316332, 0.6531728506, 0.6895405650, 0.7242470980, 0.7572088838, 0.7883464694, 0.8175848126, 0.8448535800, 0.8700870275, + 0.8932242990, 0.9142097831, 0.9329928160, 0.9495282173, 0.9637760520, 0.9757021666, 0.9852776527, 0.9924795628, 0.9972904325, 0.9996988177}; + #ifdef SSR_DEC + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + #endif /*SSR_DEC*/ +static real_t sine_long_256[] = { + 0.0030679568, 0.0092037553, 0.0153392069, 0.0214740802, 0.0276081469, 0.0337411724, 0.0398729295, 0.0460031852, 0.0521317050, 0.0582582653, 0.0643826351, 0.0705045760, 0.0766238645, 0.0827402696, + 0.0888535529, 0.0949634984, 0.1010698676, 0.1071724296, 0.1132709533, 0.1193652153, 0.1254549921, 0.1315400302, 0.1376201212, 0.1436950415, 0.1497645378, 0.1558284014, 0.1618863940, 0.1679383069, + 0.1739838719, 0.1800229102, 0.1860551536, 0.1920804083, 0.1980984211, 0.2041089684, 0.2101118416, 0.2161068022, 0.2220936269, 0.2280720919, 0.2340419590, 0.2400030345, 0.2459550500, 0.2518978119, + 0.2578310966, 0.2637546957, 0.2696683407, 0.2755718231, 0.2814649343, 0.2873474658, 0.2932191789, 0.2990798354, 0.3049292266, 0.3107671738, 0.3165933788, 0.3224076927, 0.3282098472, 0.3339996636, + 0.3397769034, 0.3455413282, 0.3512927592, 0.3570309579, 0.3627557456, 0.3684668541, 0.3741640747, 0.3798472285, 0.3855160773, 0.3911703825, 0.3968099952, 0.4024346471, 0.4080441594, 0.4136383235, + 0.4192169011, 0.4247796834, 0.4303264916, 0.4358570874, 0.4413712919, 0.4468688369, 0.4523496032, 0.4578133225, 0.4632597864, 0.4686888456, 0.4741002321, 0.4794937670, 0.4848692715, 0.4902265072, + 0.4955652654, 0.5008853674, 0.5061866641, 0.5114688873, 0.5167317986, 0.5219752789, 0.5271991491, 0.5324031115, 0.5375871062, 0.5427507758, 0.5478940606, 0.5530167222, 0.5581185222, 0.5631993413, + 0.5682589412, 0.5732972026, 0.5783138275, 0.5833086967, 0.5882815719, 0.5932323337, 0.5981607437, 0.6030666232, 0.6079497933, 0.6128100753, 0.6176473498, 0.6224613190, 0.6272518039, 0.6320187449, + 0.6367619038, 0.6414810419, 0.6461760402, 0.6508467197, 0.6554928422, 0.6601143479, 0.6647109985, 0.6692826152, 0.6738290191, 0.6783500314, 0.6828455329, 0.6873153448, 0.6917592883, 0.6961771250, + 0.7005687952, 0.7049341202, 0.7092728615, 0.7135848999, 0.7178700566, 0.7221282125, 0.7263591886, 0.7305628061, 0.7347388864, 0.7388873696, 0.7430079579, 0.7471006513, 0.7511651516, 0.7552013993, + 0.7592092156, 0.7631884217, 0.7671388984, 0.7710605264, 0.7749531269, 0.7788165212, 0.7826505899, 0.7864552140, 0.7902302146, 0.7939754725, 0.7976908684, 0.8013761640, 0.8050313592, 0.8086562157, + 0.8122506142, 0.8158144355, 0.8193475604, 0.8228498101, 0.8263210654, 0.8297612667, 0.8331701756, 0.8365477324, 0.8398938179, 0.8432082534, 0.8464909792, 0.8497417569, 0.8529606462, 0.8561473489, + 0.8593018055, 0.8624239564, 0.8655136228, 0.8685707450, 0.8715950847, 0.8745866418, 0.8775452971, 0.8804709315, 0.8833633661, 0.8862225413, 0.8890483975, 0.8918406963, 0.8945994973, 0.8973246217, + 0.9000158906, 0.9026733041, 0.9052967429, 0.9078861475, 0.9104412794, 0.9129621983, 0.9154487252, 0.9179008007, 0.9203183055, 0.9227011204, 0.9250492454, 0.9273625612, 0.9296408892, 0.9318842888, + 0.9340925813, 0.9362657070, 0.9384035468, 0.9405061007, 0.9425731897, 0.9446048737, 0.9466009140, 0.9485613704, 0.9504860640, 0.9523749948, 0.9542281032, 0.9560452700, 0.9578264356, 0.9595715404, + 0.9612805247, 0.9629532695, 0.9645897746, 0.9661900401, 0.9677538276, 0.9692812562, 0.9707721472, 0.9722265005, 0.9736442566, 0.9750253558, 0.9763697386, 0.9776773453, 0.9789481759, 0.9801821709, + 0.9813792109, 0.9825392962, 0.9836624265, 0.9847484827, 0.9857975245, 0.9868094325, 0.9877841473, 0.9887216687, 0.9896219969, 0.9904850721, 0.9913108945, 0.9920993447, 0.9928504229, 0.9935641289, + 0.9942404628, 0.9948793054, 0.9954807758, 0.9960446954, 0.9965711236, 0.9970600605, 0.9975114465, 0.9979252815, 0.9983015656, 0.9986402392, 0.9989413023, 0.9992047548, 0.9994305968, 0.9996188283, + 0.9997693896, 0.9998823404, 0.9999576211, 0.9999952912}; + #ifdef SSR_DEC + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + #endif /*SSR_DEC*/ +static const real_t kbd_short_32[] = {0.0000875914060105, 0.0009321760265333, 0.0032114611466596, 0.0081009893216786, 0.0171240286619181, 0.0320720743527833, 0.0548307856028528, 0.0871361822564870, + 0.1302923415174603, 0.1848955425508276, 0.2506163195331889, 0.3260874142923209, 0.4089316830907141, 0.4959414909423747, 0.5833939894958904, 0.6674601983218376, + 0.7446454751465113, 0.8121892962974020, 0.8683559394406505, 0.9125649996381605, 0.9453396205809574, 0.9680864942677585, 0.9827581789763112, 0.9914756203467121, + 0.9961964092194694, 0.9984956609571091, 0.9994855586984285, 0.9998533730714648, 0.9999671864476404, 0.9999948432453556, 0.9999995655238333, 0.9999999961638728}; + + #ifdef SSR_DEC + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + #endif /*SSR_DEC*/ +static const real_t kbd_long_256[] = { + 0.0005851230124487, 0.0009642149851497, 0.0013558207534965, 0.0017771849644394, 0.0022352533849672, 0.0027342299070304, 0.0032773001022195, 0.0038671998069216, 0.0045064443384152, + 0.0051974336885144, 0.0059425050016407, 0.0067439602523141, 0.0076040812644888, 0.0085251378135895, 0.0095093917383048, 0.0105590986429280, 0.0116765080854300, 0.0128638627792770, + 0.0141233971318631, 0.0154573353235409, 0.0168678890600951, 0.0183572550877256, 0.0199276125319803, 0.0215811201042484, 0.0233199132076965, 0.0251461009666641, 0.0270617631981826, + 0.0290689473405856, 0.0311696653515848, 0.0333658905863535, 0.0356595546648444, 0.0380525443366107, 0.0405466983507029, 0.0431438043376910, 0.0458455957104702, 0.0486537485902075, + 0.0515698787635492, 0.0545955386770205, 0.0577322144743916, 0.0609813230826460, 0.0643442093520723, 0.0678221432558827, 0.0714163171546603, 0.0751278431308314, 0.0789577503982528, + 0.0829069827918993, 0.0869763963425241, 0.0911667569410503, 0.0954787380973307, 0.0999129187977865, 0.1044697814663005, 0.1091497100326053, 0.1139529881122542, 0.1188797973021148, + 0.1239302155951605, 0.1291042159181728, 0.1344016647957880, 0.1398223211441467, 0.1453658351972151, 0.1510317475686540, 0.1568194884519144, 0.1627283769610327, 0.1687576206143887, + 0.1749063149634756, 0.1811734433685097, 0.1875578769224857, 0.1940583745250518, 0.2006735831073503, 0.2074020380087318, 0.2142421635060113, 0.2211922734956977, 0.2282505723293797, + 0.2354151558022098, 0.2426840122941792, 0.2500550240636293, 0.2575259686921987, 0.2650945206801527, 0.2727582531907993, 0.2805146399424422, 0.2883610572460804, 0.2962947861868143, + 0.3043130149466800, 0.3124128412663888, 0.3205912750432127, 0.3288452410620226, 0.3371715818562547, 0.3455670606953511, 0.3540283646950029, 0.3625521080463003, 0.3711348353596863, + 0.3797730251194006, 0.3884630932439016, 0.3972013967475546, 0.4059842374986933, 0.4148078660689724, 0.4236684856687616, 0.4325622561631607, 0.4414852981630577, 0.4504336971855032, + 0.4594035078775303, 0.4683907582974173, 0.4773914542472655, 0.4864015836506502, 0.4954171209689973, 0.5044340316502417, 0.5134482766032377, 0.5224558166913167, 0.5314526172383208, + 0.5404346525403849, 0.5493979103766972, 0.5583383965124314, 0.5672521391870222, 0.5761351935809411, 0.5849836462541291, 0.5937936195492526, 0.6025612759529649, 0.6112828224083939, + 0.6199545145721097, 0.6285726610088878, 0.6371336273176413, 0.6456338401819751, 0.6540697913388968, 0.6624380414593221, 0.6707352239341151, 0.6789580485595255, 0.6871033051160131, + 0.6951678668345944, 0.7031486937449871, 0.7110428359000029, 0.7188474364707993, 0.7265597347077880, 0.7341770687621900, 0.7416968783634273, 0.7491167073477523, 0.7564342060337386, + 0.7636471334404891, 0.7707533593446514, 0.7777508661725849, 0.7846377507242818, 0.7914122257259034, 0.7980726212080798, 0.8046173857073919, 0.8110450872887550, 0.8173544143867162, + 0.8235441764639875, 0.8296133044858474, 0.8355608512093652, 0.8413859912867303, 0.8470880211822968, 0.8526663589032990, 0.8581205435445334, 0.8634502346476508, 0.8686552113760616, + 0.8737353715068081, 0.8786907302411250, 0.8835214188357692, 0.8882276830575707, 0.8928098814640207, 0.8972684835130879, 0.9016040675058185, 0.9058173183656508, 0.9099090252587376, + 0.9138800790599416, 0.9177314696695282, 0.9214642831859411, 0.9250796989403991, 0.9285789863994010, 0.9319635019415643, 0.9352346855155568, 0.9383940571861993, 0.9414432135761304, + 0.9443838242107182, 0.9472176277741918, 0.9499464282852282, 0.9525720912004834, 0.9550965394547873, 0.9575217494469370, 0.9598497469802043, 0.9620826031668507, 0.9642224303060783, + 0.9662713777449607, 0.9682316277319895, 0.9701053912729269, 0.9718949039986892, 0.9736024220549734, 0.9752302180233160, 0.9767805768831932, 0.9782557920246753, 0.9796581613210076, + 0.9809899832703159, 0.9822535532154261, 0.9834511596505429, 0.9845850806232530, 0.9856575802399989, 0.9866709052828243, 0.9876272819448033, 0.9885289126911557, 0.9893779732525968, + 0.9901766097569984, 0.9909269360049311, 0.9916310308941294, 0.9922909359973702, 0.9929086532976777, 0.9934861430841844, 0.9940253220113651, 0.9945280613237534, 0.9949961852476154, + 0.9954314695504363, 0.9958356402684387, 0.9962103726017252, 0.9965572899760172, 0.9968779632693499, 0.9971739102014799, 0.9974465948831872, 0.9976974275220812, 0.9979277642809907, + 0.9981389072844972, 0.9983321047686901, 0.9985085513687731, 0.9986693885387259, 0.9988157050968516, 0.9989485378906924, 0.9990688725744943, 0.9991776444921379, 0.9992757396582338, + 0.9993639958299003, 0.9994432036616085, 0.9995141079353859, 0.9995774088586188, 0.9996337634216871, 0.9996837868076957, 0.9997280538466377, 0.9997671005064359, 0.9998014254134544, + 0.9998314913952471, 0.9998577270385304, 0.9998805282555989, 0.9999002598526793, 0.9999172570940037, 0.9999318272557038, 0.9999442511639580, 0.9999547847121726, 0.9999636603523446, + 0.9999710885561258, 0.9999772592414866, 0.9999823431612708, 0.9999864932503106, 0.9999898459281599, 0.9999925223548691, 0.9999946296375997, 0.9999962619864214, 0.9999975018180320, + 0.9999984208055542, 0.9999990808746198, 0.9999995351446231, 0.9999998288155155}; +#endif /*SSR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* filters are mirrored in coef 6, second half left out */ +static const real_t p8_13_20[7] = {FRAC_CONST(0.00746082949812), + FRAC_CONST(0.02270420949825), + FRAC_CONST(0.04546865930473), + FRAC_CONST(0.07266113929591), + FRAC_CONST(0.09885108575264), + FRAC_CONST(0.11793710567217), + FRAC_CONST(0.125)}; +static const real_t p2_13_20[7] = {FRAC_CONST(0.0), FRAC_CONST(0.01899487526049), FRAC_CONST(0.0), FRAC_CONST(-0.07293139167538), FRAC_CONST(0.0), FRAC_CONST(0.30596630545168), FRAC_CONST(0.5)}; +static const real_t p12_13_34[7] = {FRAC_CONST(0.04081179924692), FRAC_CONST(0.03812810994926), FRAC_CONST(0.05144908135699), FRAC_CONST(0.06399831151592), + FRAC_CONST(0.07428313801106), FRAC_CONST(0.08100347892914), FRAC_CONST(0.08333333333333)}; +static const real_t p8_13_34[7] = {FRAC_CONST(0.01565675600122), + FRAC_CONST(0.03752716391991), + FRAC_CONST(0.05417891378782), + FRAC_CONST(0.08417044116767), + FRAC_CONST(0.10307344158036), + FRAC_CONST(0.12222452249753), + FRAC_CONST(0.125)}; +static const real_t p4_13_34[7] = {FRAC_CONST(-0.05908211155639), FRAC_CONST(-0.04871498374946), FRAC_CONST(0.0), FRAC_CONST(0.07778723915851), + FRAC_CONST(0.16486303567403), FRAC_CONST(0.23279856662996), FRAC_CONST(0.25)}; + #ifdef PARAM_32KHZ +static const uint8_t delay_length_d[2][NO_ALLPASS_LINKS] = { + {1, 2, 3} /* d_24kHz */, + {3, 4, 5} /* d_48kHz */ +}; + #else // PARAM_32KHZ +static const uint8_t delay_length_d[NO_ALLPASS_LINKS] = { + 3, 4, 5 /* d_48kHz */ +}; + #endif // PARAM_32KHZ +static const real_t filter_a[NO_ALLPASS_LINKS] = {/* a(m) = exp(-d_48kHz(m)/7) */ + FRAC_CONST(0.65143905753106), FRAC_CONST(0.56471812200776), FRAC_CONST(0.48954165955695)}; +static const uint8_t group_border20[10 + 12 + 1] = {6, 7, 0, 1, 2, 3, /* 6 subqmf subbands */ + 9, 8, /* 2 subqmf subbands */ + 10, 11, /* 2 subqmf subbands */ + 3, 4, 5, 6, 7, 8, 9, 11, 14, 18, 23, 35, 64}; +static const uint8_t group_border34[32 + 18 + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* 12 subqmf subbands */ + 12, 13, 14, 15, 16, 17, 18, 19, /* 8 subqmf subbands */ + 20, 21, 22, 23, /* 4 subqmf subbands */ + 24, 25, 26, 27, /* 4 subqmf subbands */ + 28, 29, 30, 31, /* 4 subqmf subbands */ + 32 - 27, 33 - 27, 34 - 27, 35 - 27, 36 - 27, 37 - 27, 38 - 27, 40 - 27, 42 - 27, 44 - 27, 46 - 27, 48 - 27, + 51 - 27, 54 - 27, 57 - 27, 60 - 27, 64 - 27, 68 - 27, 91 - 27}; +static const uint16_t map_group2bk20[10 + 12] = {(NEGATE_IPD_MASK | 1), (NEGATE_IPD_MASK | 0), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; +static const uint16_t map_group2bk34[32 + 18] = {0, + 1, + 2, + 3, + 4, + 5, + 6, + 6, + 7, + (NEGATE_IPD_MASK | 2), + (NEGATE_IPD_MASK | 1), + (NEGATE_IPD_MASK | 0), + 10, + 10, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 9, + 14, + 11, + 12, + 13, + 14, + 15, + 16, + 13, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* binary lookup huffman tables */ +static const int8_t f_huff_iid_def[][2] = { + {/*0*/ -31, 1}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 1x */ + {/*1*/ -30, /*-1*/ -32}, /* index 2: 3 bits: 10x */ + {4, 5}, /* index 3: 3 bits: 11x */ + {/*2*/ -29, /*-2*/ -33}, /* index 4: 4 bits: 110x */ + {6, 7}, /* index 5: 4 bits: 111x */ + {/*3*/ -28, /*-3*/ -34}, /* index 6: 5 bits: 1110x */ + {8, 9}, /* index 7: 5 bits: 1111x */ + {/*-4*/ -35, /*4*/ -27}, /* index 8: 6 bits: 11110x */ + {/*5*/ -26, 10}, /* index 9: 6 bits: 11111x */ + {/*-5*/ -36, 11}, /* index 10: 7 bits: 111111x */ + {/*6*/ -25, 12}, /* index 11: 8 bits: 1111111x */ + {/*-6*/ -37, 13}, /* index 12: 9 bits: 11111111x */ + {/*-7*/ -38, 14}, /* index 13: 10 bits: 111111111x */ + {/*7*/ -24, 15}, /* index 14: 11 bits: 1111111111x */ + {16, 17}, /* index 15: 12 bits: 11111111111x */ + {/*8*/ -23, /*-8*/ -39}, /* index 16: 13 bits: 111111111110x */ + {18, 19}, /* index 17: 13 bits: 111111111111x */ + {/*9*/ -22, /*10*/ -21}, /* index 18: 14 bits: 1111111111110x */ + {20, 21}, /* index 19: 14 bits: 1111111111111x */ + {/*-9*/ -40, /*11*/ -20}, /* index 20: 15 bits: 11111111111110x */ + {22, 23}, /* index 21: 15 bits: 11111111111111x */ + {/*-10*/ -41, 24}, /* index 22: 16 bits: 111111111111110x */ + {25, 26}, /* index 23: 16 bits: 111111111111111x */ + {/*-11*/ -42, /*-14*/ -45}, /* index 24: 17 bits: 1111111111111101x */ + {/*-13*/ -44, /*-12*/ -43}, /* index 25: 17 bits: 1111111111111110x */ + {/*12*/ -19, 27}, /* index 26: 17 bits: 1111111111111111x */ + {/*13*/ -18, /*14*/ -17} /* index 27: 18 bits: 11111111111111111x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t t_huff_iid_def[][2] = { + {/*0*/ -31, 1}, /* index 0: 1 bits: x */ + {/*-1*/ -32, 2}, /* index 1: 2 bits: 1x */ + {/*1*/ -30, 3}, /* index 2: 3 bits: 11x */ + {/*-2*/ -33, 4}, /* index 3: 4 bits: 111x */ + {/*2*/ -29, 5}, /* index 4: 5 bits: 1111x */ + {/*-3*/ -34, 6}, /* index 5: 6 bits: 11111x */ + {/*3*/ -28, 7}, /* index 6: 7 bits: 111111x */ + {/*-4*/ -35, 8}, /* index 7: 8 bits: 1111111x */ + {/*4*/ -27, 9}, /* index 8: 9 bits: 11111111x */ + {/*-5*/ -36, 10}, /* index 9: 10 bits: 111111111x */ + {/*5*/ -26, 11}, /* index 10: 11 bits: 1111111111x */ + {/*-6*/ -37, 12}, /* index 11: 12 bits: 11111111111x */ + {/*6*/ -25, 13}, /* index 12: 13 bits: 111111111111x */ + {/*7*/ -24, 14}, /* index 13: 14 bits: 1111111111111x */ + {/*-7*/ -38, 15}, /* index 14: 15 bits: 11111111111111x */ + {16, 17}, /* index 15: 16 bits: 111111111111111x */ + {/*8*/ -23, /*-8*/ -39}, /* index 16: 17 bits: 1111111111111110x */ + {18, 19}, /* index 17: 17 bits: 1111111111111111x */ + {20, 21}, /* index 18: 18 bits: 11111111111111110x */ + {22, 23}, /* index 19: 18 bits: 11111111111111111x */ + {/*9*/ -22, /*-14*/ -45}, /* index 20: 19 bits: 111111111111111100x */ + {/*-13*/ -44, /*-12*/ -43}, /* index 21: 19 bits: 111111111111111101x */ + {24, 25}, /* index 22: 19 bits: 111111111111111110x */ + {26, 27}, /* index 23: 19 bits: 111111111111111111x */ + {/*-11*/ -42, /*-10*/ -41}, /* index 24: 20 bits: 1111111111111111100x */ + {/*-9*/ -40, /*10*/ -21}, /* index 25: 20 bits: 1111111111111111101x */ + {/*11*/ -20, /*12*/ -19}, /* index 26: 20 bits: 1111111111111111110x */ + {/*13*/ -18, /*14*/ -17} /* index 27: 20 bits: 1111111111111111111x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t f_huff_iid_fine[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 0x */ + {4, /*-1*/ -32}, /* index 2: 3 bits: 00x */ + {/*1*/ -30, 5}, /* index 3: 3 bits: 01x */ + {/*-2*/ -33, /*2*/ -29}, /* index 4: 4 bits: 000x */ + {6, 7}, /* index 5: 4 bits: 011x */ + {/*-3*/ -34, /*3*/ -28}, /* index 6: 5 bits: 0110x */ + {8, 9}, /* index 7: 5 bits: 0111x */ + {/*-4*/ -35, /*4*/ -27}, /* index 8: 6 bits: 01110x */ + {10, 11}, /* index 9: 6 bits: 01111x */ + {/*-5*/ -36, /*5*/ -26}, /* index 10: 7 bits: 011110x */ + {12, 13}, /* index 11: 7 bits: 011111x */ + {/*-6*/ -37, /*6*/ -25}, /* index 12: 8 bits: 0111110x */ + {14, 15}, /* index 13: 8 bits: 0111111x */ + {/*7*/ -24, 16}, /* index 14: 9 bits: 01111110x */ + {17, 18}, /* index 15: 9 bits: 01111111x */ + {19, /*-8*/ -39}, /* index 16: 10 bits: 011111101x */ + {/*8*/ -23, 20}, /* index 17: 10 bits: 011111110x */ + {21, /*-7*/ -38}, /* index 18: 10 bits: 011111111x */ + {/*10*/ -21, 22}, /* index 19: 11 bits: 0111111010x */ + {23, /*-9*/ -40}, /* index 20: 11 bits: 0111111101x */ + {/*9*/ -22, 24}, /* index 21: 11 bits: 0111111110x */ + {/*-11*/ -42, /*11*/ -20}, /* index 22: 12 bits: 01111110101x */ + {25, 26}, /* index 23: 12 bits: 01111111010x */ + {27, /*-10*/ -41}, /* index 24: 12 bits: 01111111101x */ + {28, /*-12*/ -43}, /* index 25: 13 bits: 011111110100x */ + {/*12*/ -19, 29}, /* index 26: 13 bits: 011111110101x */ + {30, 31}, /* index 27: 13 bits: 011111111010x */ + {32, /*-14*/ -45}, /* index 28: 14 bits: 0111111101000x */ + {/*14*/ -17, 33}, /* index 29: 14 bits: 0111111101011x */ + {34, /*-13*/ -44}, /* index 30: 14 bits: 0111111110100x */ + {/*13*/ -18, 35}, /* index 31: 14 bits: 0111111110101x */ + {36, 37}, /* index 32: 15 bits: 01111111010000x */ + {38, /*-15*/ -46}, /* index 33: 15 bits: 01111111010111x */ + {/*15*/ -16, 39}, /* index 34: 15 bits: 01111111101000x */ + {40, 41}, /* index 35: 15 bits: 01111111101011x */ + {42, 43}, /* index 36: 16 bits: 011111110100000x */ + {/*-17*/ -48, /*17*/ -14}, /* index 37: 16 bits: 011111110100001x */ + {44, 45}, /* index 38: 16 bits: 011111110101110x */ + {46, 47}, /* index 39: 16 bits: 011111111010001x */ + {48, 49}, /* index 40: 16 bits: 011111111010110x */ + {/*-16*/ -47, /*16*/ -15}, /* index 41: 16 bits: 011111111010111x */ + {/*-21*/ -52, /*21*/ -10}, /* index 42: 17 bits: 0111111101000000x */ + {/*-19*/ -50, /*19*/ -12}, /* index 43: 17 bits: 0111111101000001x */ + {/*-18*/ -49, /*18*/ -13}, /* index 44: 17 bits: 0111111101011100x */ + {50, 51}, /* index 45: 17 bits: 0111111101011101x */ + {52, 53}, /* index 46: 17 bits: 0111111110100010x */ + {54, 55}, /* index 47: 17 bits: 0111111110100011x */ + {56, 57}, /* index 48: 17 bits: 0111111110101100x */ + {58, 59}, /* index 49: 17 bits: 0111111110101101x */ + {/*-26*/ -57, /*-25*/ -56}, /* index 50: 18 bits: 01111111010111010x */ + {/*-28*/ -59, /*-27*/ -58}, /* index 51: 18 bits: 01111111010111011x */ + {/*-22*/ -53, /*22*/ -9}, /* index 52: 18 bits: 01111111101000100x */ + {/*-24*/ -55, /*-23*/ -54}, /* index 53: 18 bits: 01111111101000101x */ + {/*25*/ -6, /*26*/ -5}, /* index 54: 18 bits: 01111111101000110x */ + {/*23*/ -8, /*24*/ -7}, /* index 55: 18 bits: 01111111101000111x */ + {/*29*/ -2, /*30*/ -1}, /* index 56: 18 bits: 01111111101011000x */ + {/*27*/ -4, /*28*/ -3}, /* index 57: 18 bits: 01111111101011001x */ + {/*-30*/ -61, /*-29*/ -60}, /* index 58: 18 bits: 01111111101011010x */ + {/*-20*/ -51, /*20*/ -11} /* index 59: 18 bits: 01111111101011011x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t t_huff_iid_fine[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {/*1*/ -30, 2}, /* index 1: 2 bits: 0x */ + {3, /*-1*/ -32}, /* index 2: 3 bits: 01x */ + {4, 5}, /* index 3: 4 bits: 010x */ + {6, 7}, /* index 4: 5 bits: 0100x */ + {/*-2*/ -33, /*2*/ -29}, /* index 5: 5 bits: 0101x */ + {8, /*-3*/ -34}, /* index 6: 6 bits: 01000x */ + {/*3*/ -28, 9}, /* index 7: 6 bits: 01001x */ + {/*-4*/ -35, /*4*/ -27}, /* index 8: 7 bits: 010000x */ + {10, 11}, /* index 9: 7 bits: 010011x */ + {/*5*/ -26, 12}, /* index 10: 8 bits: 0100110x */ + {13, 14}, /* index 11: 8 bits: 0100111x */ + {/*-6*/ -37, /*6*/ -25}, /* index 12: 9 bits: 01001101x */ + {15, 16}, /* index 13: 9 bits: 01001110x */ + {17, /*-5*/ -36}, /* index 14: 9 bits: 01001111x */ + {18, /*-7*/ -38}, /* index 15: 10 bits: 010011100x */ + {/*7*/ -24, 19}, /* index 16: 10 bits: 010011101x */ + {20, 21}, /* index 17: 10 bits: 010011110x */ + {/*9*/ -22, 22}, /* index 18: 11 bits: 0100111000x */ + {23, 24}, /* index 19: 11 bits: 0100111011x */ + {/*-8*/ -39, /*8*/ -23}, /* index 20: 11 bits: 0100111100x */ + {25, 26}, /* index 21: 11 bits: 0100111101x */ + {/*11*/ -20, 27}, /* index 22: 12 bits: 01001110001x */ + {28, 29}, /* index 23: 12 bits: 01001110110x */ + {/*-10*/ -41, /*10*/ -21}, /* index 24: 12 bits: 01001110111x */ + {30, 31}, /* index 25: 12 bits: 01001111010x */ + {32, /*-9*/ -40}, /* index 26: 12 bits: 01001111011x */ + {33, /*-13*/ -44}, /* index 27: 13 bits: 010011100011x */ + {/*13*/ -18, 34}, /* index 28: 13 bits: 010011101100x */ + {35, 36}, /* index 29: 13 bits: 010011101101x */ + {37, /*-12*/ -43}, /* index 30: 13 bits: 010011110100x */ + {/*12*/ -19, 38}, /* index 31: 13 bits: 010011110101x */ + {39, /*-11*/ -42}, /* index 32: 13 bits: 010011110110x */ + {40, 41}, /* index 33: 14 bits: 0100111000110x */ + {42, 43}, /* index 34: 14 bits: 0100111011001x */ + {44, 45}, /* index 35: 14 bits: 0100111011010x */ + {46, /*-15*/ -46}, /* index 36: 14 bits: 0100111011011x */ + {/*15*/ -16, 47}, /* index 37: 14 bits: 0100111101000x */ + {/*-14*/ -45, /*14*/ -17}, /* index 38: 14 bits: 0100111101011x */ + {48, 49}, /* index 39: 14 bits: 0100111101100x */ + {/*-21*/ -52, /*-20*/ -51}, /* index 40: 15 bits: 01001110001100x */ + {/*18*/ -13, /*19*/ -12}, /* index 41: 15 bits: 01001110001101x */ + {/*-19*/ -50, /*-18*/ -49}, /* index 42: 15 bits: 01001110110010x */ + {50, 51}, /* index 43: 15 bits: 01001110110011x */ + {52, 53}, /* index 44: 15 bits: 01001110110100x */ + {54, 55}, /* index 45: 15 bits: 01001110110101x */ + {56, /*-17*/ -48}, /* index 46: 15 bits: 01001110110110x */ + {/*17*/ -14, 57}, /* index 47: 15 bits: 01001111010001x */ + {58, /*-16*/ -47}, /* index 48: 15 bits: 01001111011000x */ + {/*16*/ -15, 59}, /* index 49: 15 bits: 01001111011001x */ + {/*-26*/ -57, /*26*/ -5}, /* index 50: 16 bits: 010011101100110x */ + {/*-28*/ -59, /*-27*/ -58}, /* index 51: 16 bits: 010011101100111x */ + {/*29*/ -2, /*30*/ -1}, /* index 52: 16 bits: 010011101101000x */ + {/*27*/ -4, /*28*/ -3}, /* index 53: 16 bits: 010011101101001x */ + {/*-30*/ -61, /*-29*/ -60}, /* index 54: 16 bits: 010011101101010x */ + {/*-25*/ -56, /*25*/ -6}, /* index 55: 16 bits: 010011101101011x */ + {/*-24*/ -55, /*24*/ -7}, /* index 56: 16 bits: 010011101101100x */ + {/*-23*/ -54, /*23*/ -8}, /* index 57: 16 bits: 010011110100011x */ + {/*-22*/ -53, /*22*/ -9}, /* index 58: 16 bits: 010011110110000x */ + {/*20*/ -11, /*21*/ -10} /* index 59: 16 bits: 010011110110011x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t f_huff_icc[][2] = { + {/*0*/ -31, 1}, /* index 0: 1 bits: x */ + {/*1*/ -30, 2}, /* index 1: 2 bits: 1x */ + {/*-1*/ -32, 3}, /* index 2: 3 bits: 11x */ + {/*2*/ -29, 4}, /* index 3: 4 bits: 111x */ + {/*-2*/ -33, 5}, /* index 4: 5 bits: 1111x */ + {/*3*/ -28, 6}, /* index 5: 6 bits: 11111x */ + {/*-3*/ -34, 7}, /* index 6: 7 bits: 111111x */ + {/*4*/ -27, 8}, /* index 7: 8 bits: 1111111x */ + {/*5*/ -26, 9}, /* index 8: 9 bits: 11111111x */ + {/*-4*/ -35, 10}, /* index 9: 10 bits: 111111111x */ + {/*6*/ -25, 11}, /* index 10: 11 bits: 1111111111x */ + {/*-5*/ -36, 12}, /* index 11: 12 bits: 11111111111x */ + {/*7*/ -24, 13}, /* index 12: 13 bits: 111111111111x */ + {/*-6*/ -37, /*-7*/ -38} /* index 13: 14 bits: 1111111111111x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t t_huff_icc[][2] = { + {/*0*/ -31, 1}, /* index 0: 1 bits: x */ + {/*1*/ -30, 2}, /* index 1: 2 bits: 1x */ + {/*-1*/ -32, 3}, /* index 2: 3 bits: 11x */ + {/*2*/ -29, 4}, /* index 3: 4 bits: 111x */ + {/*-2*/ -33, 5}, /* index 4: 5 bits: 1111x */ + {/*3*/ -28, 6}, /* index 5: 6 bits: 11111x */ + {/*-3*/ -34, 7}, /* index 6: 7 bits: 111111x */ + {/*4*/ -27, 8}, /* index 7: 8 bits: 1111111x */ + {/*-4*/ -35, 9}, /* index 8: 9 bits: 11111111x */ + {/*5*/ -26, 10}, /* index 9: 10 bits: 111111111x */ + {/*-5*/ -36, 11}, /* index 10: 11 bits: 1111111111x */ + {/*6*/ -25, 12}, /* index 11: 12 bits: 11111111111x */ + {/*-6*/ -37, 13}, /* index 12: 13 bits: 111111111111x */ + {/*-7*/ -38, /*7*/ -24} /* index 13: 14 bits: 1111111111111x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t f_huff_ipd[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 0x */ + {/*1*/ -30, 4}, /* index 2: 3 bits: 00x */ + {5, 6}, /* index 3: 3 bits: 01x */ + {/*4*/ -27, /*5*/ -26}, /* index 4: 4 bits: 001x */ + {/*3*/ -28, /*6*/ -25}, /* index 5: 4 bits: 010x */ + {/*2*/ -29, /*7*/ -24} /* index 6: 4 bits: 011x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t t_huff_ipd[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 0x */ + {4, 5}, /* index 2: 3 bits: 00x */ + {/*1*/ -30, /*7*/ -24}, /* index 3: 3 bits: 01x */ + {/*5*/ -26, 6}, /* index 4: 4 bits: 000x */ + {/*2*/ -29, /*6*/ -25}, /* index 5: 4 bits: 001x */ + {/*4*/ -27, /*3*/ -28} /* index 6: 5 bits: 0001x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t f_huff_opd[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 0x */ + {/*7*/ -24, /*1*/ -30}, /* index 2: 3 bits: 00x */ + {4, 5}, /* index 3: 3 bits: 01x */ + {/*3*/ -28, /*6*/ -25}, /* index 4: 4 bits: 010x */ + {/*2*/ -29, 6}, /* index 5: 4 bits: 011x */ + {/*5*/ -26, /*4*/ -27} /* index 6: 5 bits: 0111x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const int8_t t_huff_opd[][2] = { + {1, /*0*/ -31}, /* index 0: 1 bits: x */ + {2, 3}, /* index 1: 2 bits: 0x */ + {4, 5}, /* index 2: 3 bits: 00x */ + {/*1*/ -30, /*7*/ -24}, /* index 3: 3 bits: 01x */ + {/*5*/ -26, /*2*/ -29}, /* index 4: 4 bits: 000x */ + {/*6*/ -25, 6}, /* index 5: 4 bits: 001x */ + {/*4*/ -27, /*3*/ -28} /* index 6: 5 bits: 0011x */ +}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const complex_t Phi_Fract_SubQmf20[] = { + {FRAC_CONST(0.9882950187), FRAC_CONST(0.1525546312)}, {FRAC_CONST(0.8962930441), FRAC_CONST(0.4434623122)}, {FRAC_CONST(0.7208535671), FRAC_CONST(0.6930873394)}, + {FRAC_CONST(0.4783087075), FRAC_CONST(0.8781917691)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, + {FRAC_CONST(0.8962930441), FRAC_CONST(-0.4434623122)}, {FRAC_CONST(0.9882950187), FRAC_CONST(-0.1525546312)}, {FRAC_CONST(-0.5424415469), FRAC_CONST(0.8400935531)}, + {FRAC_CONST(0.0392598175), FRAC_CONST(0.9992290139)}, {FRAC_CONST(-0.9268565774), FRAC_CONST(0.3754155636)}, {FRAC_CONST(-0.9741733670), FRAC_CONST(-0.2258012742)}}; +/* RE(Phi_Fract_SubQmf34[j]) = (float)cos(M_PI*f_center_34[j]*0.39); */ +/* IM(Phi_Fract_SubQmf34[j]) = (float)sin(M_PI*f_center_34[j]*0.39); */ +static const complex_t Phi_Fract_SubQmf34[] = { + {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, + {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, + {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, + {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, + {FRAC_CONST(-0.7705132365), FRAC_CONST(0.6374239922)}, {FRAC_CONST(-0.7705132365), FRAC_CONST(0.6374239922)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, + {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, + {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, {FRAC_CONST(-0.7705132365), FRAC_CONST(0.6374239922)}, + {FRAC_CONST(-0.7705132365), FRAC_CONST(0.6374239922)}, {FRAC_CONST(-0.8607420325), FRAC_CONST(-0.5090414286)}, {FRAC_CONST(0.3387379348), FRAC_CONST(0.9408807755)}, + {FRAC_CONST(0.1873813123), FRAC_CONST(-0.9822872281)}, {FRAC_CONST(-0.7705132365), FRAC_CONST(0.6374239922)}, {FRAC_CONST(-0.8607420325), FRAC_CONST(-0.5090414286)}, + {FRAC_CONST(-0.8607420325), FRAC_CONST(-0.5090414286)}, {FRAC_CONST(0.1873813123), FRAC_CONST(-0.9822872281)}, {FRAC_CONST(0.1873813123), FRAC_CONST(-0.9822872281)}, + {FRAC_CONST(0.9876883626), FRAC_CONST(-0.1564344615)}, {FRAC_CONST(-0.8607420325), FRAC_CONST(-0.5090414286)}}; +/* RE(Q_Fract_allpass_SubQmf20[j][i]) = (float)cos(M_PI*f_center_20[j]*frac_delay_q[i]); */ +/* IM(Q_Fract_allpass_SubQmf20[j][i]) = (float)sin(M_PI*f_center_20[j]*frac_delay_q[i]); */ +static const complex_t Q_Fract_allpass_SubQmf20[][3] = { + {{FRAC_CONST(0.9857769012), FRAC_CONST(0.1680592746)}, {FRAC_CONST(0.9569403529), FRAC_CONST(0.2902846634)}, {FRAC_CONST(0.9907300472), FRAC_CONST(0.1358452588)}}, + {{FRAC_CONST(0.8744080663), FRAC_CONST(0.4851911962)}, {FRAC_CONST(0.6343932748), FRAC_CONST(0.7730104327)}, {FRAC_CONST(0.9175986052), FRAC_CONST(0.3975082636)}}, + {{FRAC_CONST(0.6642524004), FRAC_CONST(0.7475083470)}, {FRAC_CONST(0.0980171412), FRAC_CONST(0.9951847196)}, {FRAC_CONST(0.7767338753), FRAC_CONST(0.6298289299)}}, + {{FRAC_CONST(0.3790524006), FRAC_CONST(0.9253752232)}, {FRAC_CONST(-0.4713967443), FRAC_CONST(0.8819212914)}, {FRAC_CONST(0.5785340071), FRAC_CONST(0.8156582713)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(0.8744080663), FRAC_CONST(-0.4851911962)}, {FRAC_CONST(0.6343932748), FRAC_CONST(-0.7730104327)}, {FRAC_CONST(0.9175986052), FRAC_CONST(-0.3975082636)}}, + {{FRAC_CONST(0.9857769012), FRAC_CONST(-0.1680592746)}, {FRAC_CONST(0.9569403529), FRAC_CONST(-0.2902846634)}, {FRAC_CONST(0.9907300472), FRAC_CONST(-0.1358452588)}}, + {{FRAC_CONST(-0.7126385570), FRAC_CONST(0.7015314102)}, {FRAC_CONST(-0.5555702448), FRAC_CONST(-0.8314695954)}, {FRAC_CONST(-0.3305967748), FRAC_CONST(0.9437720776)}}, + {{FRAC_CONST(-0.1175374240), FRAC_CONST(0.9930684566)}, {FRAC_CONST(-0.9807852507), FRAC_CONST(0.1950903237)}, {FRAC_CONST(0.2066311091), FRAC_CONST(0.9784189463)}}, + {{FRAC_CONST(-0.9947921634), FRAC_CONST(0.1019244045)}, {FRAC_CONST(0.5555702448), FRAC_CONST(-0.8314695954)}, {FRAC_CONST(-0.7720130086), FRAC_CONST(0.6356067061)}}, + {{FRAC_CONST(-0.8400934935), FRAC_CONST(-0.5424416065)}, {FRAC_CONST(0.9807852507), FRAC_CONST(0.1950903237)}, {FRAC_CONST(-0.9896889329), FRAC_CONST(0.1432335079)}}}; +/* RE(Q_Fract_allpass_SubQmf34[j][i]) = (float)cos(M_PI*f_center_34[j]*frac_delay_q[i]); */ +/* IM(Q_Fract_allpass_SubQmf34[j][i]) = (float)sin(M_PI*f_center_34[j]*frac_delay_q[i]); */ +static const complex_t Q_Fract_allpass_SubQmf34[][3] = { + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(-0.9048270583), FRAC_CONST(0.4257792532)}, {FRAC_CONST(-0.0000000000), FRAC_CONST(-1.0000000000)}, {FRAC_CONST(-0.5724321604), FRAC_CONST(0.8199520707)}}, + {{FRAC_CONST(-0.9048270583), FRAC_CONST(0.4257792532)}, {FRAC_CONST(-0.0000000000), FRAC_CONST(-1.0000000000)}, {FRAC_CONST(-0.5724321604), FRAC_CONST(0.8199520707)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(1.0000000000), FRAC_CONST(0.0000000000)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(-0.9048270583), FRAC_CONST(0.4257792532)}, {FRAC_CONST(-0.0000000000), FRAC_CONST(-1.0000000000)}, {FRAC_CONST(-0.5724321604), FRAC_CONST(0.8199520707)}}, + {{FRAC_CONST(-0.9048270583), FRAC_CONST(0.4257792532)}, {FRAC_CONST(-0.0000000000), FRAC_CONST(-1.0000000000)}, {FRAC_CONST(-0.5724321604), FRAC_CONST(0.8199520707)}}, + {{FRAC_CONST(-0.6129069924), FRAC_CONST(-0.7901550531)}, {FRAC_CONST(0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(-0.9917160273), FRAC_CONST(-0.1284494549)}}, + {{FRAC_CONST(0.2181432247), FRAC_CONST(0.9759167433)}, {FRAC_CONST(-0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(0.4623677433), FRAC_CONST(0.8866882324)}}, + {{FRAC_CONST(0.6374240518), FRAC_CONST(-0.7705131769)}, {FRAC_CONST(-1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(-0.3446428776), FRAC_CONST(-0.9387338758)}}, + {{FRAC_CONST(-0.9048270583), FRAC_CONST(0.4257792532)}, {FRAC_CONST(-0.0000000000), FRAC_CONST(-1.0000000000)}, {FRAC_CONST(-0.5724321604), FRAC_CONST(0.8199520707)}}, + {{FRAC_CONST(-0.6129069924), FRAC_CONST(-0.7901550531)}, {FRAC_CONST(0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(-0.9917160273), FRAC_CONST(-0.1284494549)}}, + {{FRAC_CONST(-0.6129069924), FRAC_CONST(-0.7901550531)}, {FRAC_CONST(0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(-0.9917160273), FRAC_CONST(-0.1284494549)}}, + {{FRAC_CONST(0.6374240518), FRAC_CONST(-0.7705131769)}, {FRAC_CONST(-1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(-0.3446428776), FRAC_CONST(-0.9387338758)}}, + {{FRAC_CONST(0.6374240518), FRAC_CONST(-0.7705131769)}, {FRAC_CONST(-1.0000000000), FRAC_CONST(0.0000000000)}, {FRAC_CONST(-0.3446428776), FRAC_CONST(-0.9387338758)}}, + {{FRAC_CONST(0.8910064697), FRAC_CONST(0.4539906085)}, {FRAC_CONST(0.7071067691), FRAC_CONST(-0.7071067691)}, {FRAC_CONST(0.6730125546), FRAC_CONST(-0.7396310568)}}, + {{FRAC_CONST(-0.6129069924), FRAC_CONST(-0.7901550531)}, {FRAC_CONST(0.7071067691), FRAC_CONST(0.7071067691)}, {FRAC_CONST(-0.9917160273), FRAC_CONST(-0.1284494549)}}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t cos_alphas[] = {COEF_CONST(1.0000000000), COEF_CONST(0.9841239700), COEF_CONST(0.9594738210), COEF_CONST(0.8946843079), + COEF_CONST(0.8269340931), COEF_CONST(0.7071067812), COEF_CONST(0.4533210856), COEF_CONST(0.0000000000)}; +static const real_t sin_alphas[] = {COEF_CONST(0.0000000000), COEF_CONST(0.1774824264), COEF_CONST(0.2817977763), COEF_CONST(0.4466989918), + COEF_CONST(0.5622988580), COEF_CONST(0.7071067812), COEF_CONST(0.8913472911), COEF_CONST(1.0000000000)}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t cos_betas_normal[][8] = {{COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), + COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9995871699), COEF_CONST(0.9989419133), COEF_CONST(0.9972204583), COEF_CONST(0.9953790839), + COEF_CONST(0.9920112747), COEF_CONST(0.9843408180), COEF_CONST(0.9681727381)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9984497744), COEF_CONST(0.9960279377), COEF_CONST(0.9895738413), COEF_CONST(0.9826814632), + COEF_CONST(0.9701058164), COEF_CONST(0.9416098832), COEF_CONST(0.8822105900)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9959398908), COEF_CONST(0.9896038018), COEF_CONST(0.9727589768), COEF_CONST(0.9548355329), + COEF_CONST(0.9223070404), COEF_CONST(0.8494349490), COEF_CONST(0.7013005535)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9932417400), COEF_CONST(0.9827071856), COEF_CONST(0.9547730996), COEF_CONST(0.9251668930), + COEF_CONST(0.8717461589), COEF_CONST(0.7535520592), COEF_CONST(0.5198827312)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9902068095), COEF_CONST(0.9749613872), COEF_CONST(0.9346538534), COEF_CONST(0.8921231300), + COEF_CONST(0.8158851259), COEF_CONST(0.6495964302), COEF_CONST(0.3313370772)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9880510933), COEF_CONST(0.9694670261), COEF_CONST(0.9204347876), COEF_CONST(0.8688622825), + COEF_CONST(0.7768516704), COEF_CONST(0.5782161800), COEF_CONST(0.2069970356)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9858996945), COEF_CONST(0.9639898866), COEF_CONST(0.9063034786), COEF_CONST(0.8458214608), + COEF_CONST(0.7384262300), COEF_CONST(0.5089811277), COEF_CONST(0.0905465944)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sin_betas_normal[][8] = {{COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), + COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0287313368), COEF_CONST(-0.0459897147), COEF_CONST(-0.0745074328), COEF_CONST(-0.0960233266), + COEF_CONST(-0.1261492408), COEF_CONST(-0.1762757894), COEF_CONST(-0.2502829383)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0556601118), COEF_CONST(-0.0890412670), COEF_CONST(-0.1440264301), COEF_CONST(-0.1853028382), + COEF_CONST(-0.2426823129), COEF_CONST(-0.3367058477), COEF_CONST(-0.4708550466)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0900207420), COEF_CONST(-0.1438204281), COEF_CONST(-0.2318188366), COEF_CONST(-0.2971348264), + COEF_CONST(-0.3864579191), COEF_CONST(-0.5276933461), COEF_CONST(-0.7128657193)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1160639735), COEF_CONST(-0.1851663774), COEF_CONST(-0.2973353800), COEF_CONST(-0.3795605619), + COEF_CONST(-0.4899577884), COEF_CONST(-0.6573882369), COEF_CONST(-0.8542376401)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1396082894), COEF_CONST(-0.2223742196), COEF_CONST(-0.3555589603), COEF_CONST(-0.4517923427), + COEF_CONST(-0.5782140273), COEF_CONST(-0.7602792104), COEF_CONST(-0.9435124489)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1541266914), COEF_CONST(-0.2452217065), COEF_CONST(-0.3908961522), COEF_CONST(-0.4950538699), + COEF_CONST(-0.6296836366), COEF_CONST(-0.8158836002), COEF_CONST(-0.9783415698)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1673373610), COEF_CONST(-0.2659389001), COEF_CONST(-0.4226275012), COEF_CONST(-0.5334660781), + COEF_CONST(-0.6743342664), COEF_CONST(-0.8607776784), COEF_CONST(-0.9958922202)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t cos_betas_fine[][8] = {{COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), COEF_CONST(1.0000000000), + COEF_CONST(1.0000000000), COEF_CONST(1.0000000000)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9995871699), COEF_CONST(0.9989419133), COEF_CONST(0.9972204583), COEF_CONST(0.9953790839), COEF_CONST(0.9920112747), + COEF_CONST(0.9843408180), COEF_CONST(0.9681727381)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9984497744), COEF_CONST(0.9960279377), COEF_CONST(0.9895738413), COEF_CONST(0.9826814632), COEF_CONST(0.9701058164), + COEF_CONST(0.9416098832), COEF_CONST(0.8822105900)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9968361371), COEF_CONST(0.9918968104), COEF_CONST(0.9787540479), COEF_CONST(0.9647515190), COEF_CONST(0.9392903010), + COEF_CONST(0.8820167114), COEF_CONST(0.7645325390)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9950262915), COEF_CONST(0.9872675041), COEF_CONST(0.9666584578), COEF_CONST(0.9447588606), COEF_CONST(0.9050918405), + COEF_CONST(0.8165997379), COEF_CONST(0.6383824796)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9932417400), COEF_CONST(0.9827071856), COEF_CONST(0.9547730996), COEF_CONST(0.9251668930), COEF_CONST(0.8717461589), + COEF_CONST(0.7535520592), COEF_CONST(0.5198827312)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9908827998), COEF_CONST(0.9766855904), COEF_CONST(0.9391249214), COEF_CONST(0.8994531782), COEF_CONST(0.8282352693), + COEF_CONST(0.6723983174), COEF_CONST(0.3719473225)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9890240165), COEF_CONST(0.9719459866), COEF_CONST(0.9268448110), COEF_CONST(0.8793388536), COEF_CONST(0.7944023271), + COEF_CONST(0.6101812098), COEF_CONST(0.2621501145)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9876350461), COEF_CONST(0.9684073447), COEF_CONST(0.9176973944), COEF_CONST(0.8643930070), COEF_CONST(0.7693796058), + COEF_CONST(0.5646720713), COEF_CONST(0.1838899556)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9866247085), COEF_CONST(0.9658349704), COEF_CONST(0.9110590761), COEF_CONST(0.8535668048), COEF_CONST(0.7513165426), + COEF_CONST(0.5320914819), COEF_CONST(0.1289530943)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9858996945), COEF_CONST(0.9639898866), COEF_CONST(0.9063034786), COEF_CONST(0.8458214608), COEF_CONST(0.7384262300), + COEF_CONST(0.5089811277), COEF_CONST(0.0905465944)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9851245614), COEF_CONST(0.9620180268), COEF_CONST(0.9012265590), COEF_CONST(0.8375623272), COEF_CONST(0.7247108045), + COEF_CONST(0.4845204297), COEF_CONST(0.0504115003)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9846869856), COEF_CONST(0.9609052357), COEF_CONST(0.8983639533), COEF_CONST(0.8329098386), COEF_CONST(0.7169983441), + COEF_CONST(0.4708245354), COEF_CONST(0.0281732509)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9844406325), COEF_CONST(0.9602788522), COEF_CONST(0.8967533934), COEF_CONST(0.8302936455), COEF_CONST(0.7126658102), + COEF_CONST(0.4631492839), COEF_CONST(0.0157851140)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9843020502), COEF_CONST(0.9599265269), COEF_CONST(0.8958477331), COEF_CONST(0.8288229094), COEF_CONST(0.7102315840), + COEF_CONST(0.4588429315), COEF_CONST(0.0088578059)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9842241136), COEF_CONST(0.9597283916), COEF_CONST(0.8953385094), COEF_CONST(0.8279961409), COEF_CONST(0.7088635748), + COEF_CONST(0.4564246834), COEF_CONST(0.0049751355)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sin_betas_fine[][8] = {{COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), COEF_CONST(0.0000000000), + COEF_CONST(0.0000000000), COEF_CONST(0.0000000000)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0287313368), COEF_CONST(-0.0459897147), COEF_CONST(-0.0745074328), COEF_CONST(-0.0960233266), + COEF_CONST(-0.1261492408), COEF_CONST(-0.1762757894), COEF_CONST(-0.2502829383)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0556601118), COEF_CONST(-0.0890412670), COEF_CONST(-0.1440264301), COEF_CONST(-0.1853028382), + COEF_CONST(-0.2426823129), COEF_CONST(-0.3367058477), COEF_CONST(-0.4708550466)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0794840594), COEF_CONST(-0.1270461238), COEF_CONST(-0.2050378347), COEF_CONST(-0.2631625097), + COEF_CONST(-0.3431234916), COEF_CONST(-0.4712181245), COEF_CONST(-0.6445851354)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.0996126459), COEF_CONST(-0.1590687758), COEF_CONST(-0.2560691819), COEF_CONST(-0.3277662204), + COEF_CONST(-0.4252161335), COEF_CONST(-0.5772043556), COEF_CONST(-0.7697193058)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1160639735), COEF_CONST(-0.1851663774), COEF_CONST(-0.2973353800), COEF_CONST(-0.3795605619), + COEF_CONST(-0.4899577884), COEF_CONST(-0.6573882369), COEF_CONST(-0.8542376401)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1347266752), COEF_CONST(-0.2146747714), COEF_CONST(-0.3435758752), COEF_CONST(-0.4370171396), + COEF_CONST(-0.5603805303), COEF_CONST(-0.7401895046), COEF_CONST(-0.9282538388)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1477548470), COEF_CONST(-0.2352041647), COEF_CONST(-0.3754446647), COEF_CONST(-0.4761965776), + COEF_CONST(-0.6073919186), COEF_CONST(-0.7922618830), COEF_CONST(-0.9650271071)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1567705832), COEF_CONST(-0.2493736450), COEF_CONST(-0.3972801182), COEF_CONST(-0.5028167951), + COEF_CONST(-0.6387918458), COEF_CONST(-0.8253153651), COEF_CONST(-0.9829468369)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1630082348), COEF_CONST(-0.2591578860), COEF_CONST(-0.4122758299), COEF_CONST(-0.5209834064), + COEF_CONST(-0.6599420072), COEF_CONST(-0.8466868694), COEF_CONST(-0.9916506943)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1673373610), COEF_CONST(-0.2659389001), COEF_CONST(-0.4226275012), COEF_CONST(-0.5334660781), + COEF_CONST(-0.6743342664), COEF_CONST(-0.8607776784), COEF_CONST(-0.9958922202)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1718417832), COEF_CONST(-0.2729859267), COEF_CONST(-0.4333482310), COEF_CONST(-0.5463417868), + COEF_CONST(-0.6890531546), COEF_CONST(-0.8747799456), COEF_CONST(-0.9987285320)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1743316967), COEF_CONST(-0.2768774604), COEF_CONST(-0.4392518725), COEF_CONST(-0.5534087104), + COEF_CONST(-0.6970748701), COEF_CONST(-0.8822268738), COEF_CONST(-0.9996030552)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1757175038), COEF_CONST(-0.2790421580), COEF_CONST(-0.4425306221), COEF_CONST(-0.5573261722), + COEF_CONST(-0.7015037013), COEF_CONST(-0.8862802834), COEF_CONST(-0.9998754073)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1764921355), COEF_CONST(-0.2802517850), COEF_CONST(-0.4443611583), COEF_CONST(-0.5595110229), + COEF_CONST(-0.7039681080), COEF_CONST(-0.8885173967), COEF_CONST(-0.9999607689)}, + {COEF_CONST(0.0000000000), COEF_CONST(-0.1769262394), COEF_CONST(-0.2809295540), COEF_CONST(-0.4453862969), COEF_CONST(-0.5607337966), + COEF_CONST(-0.7053456119), COEF_CONST(-0.8897620516), COEF_CONST(-0.9999876239)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sincos_alphas_B_normal[][8] = {{COEF_CONST(0.0561454100), COEF_CONST(0.0526385859), COEF_CONST(0.0472937334), COEF_CONST(0.0338410641), COEF_CONST(0.0207261065), + COEF_CONST(0.0028205635), COEF_CONST(0.0028205635), COEF_CONST(0.0028205635)}, + {COEF_CONST(0.1249065138), COEF_CONST(0.1173697697), COEF_CONST(0.1057888284), COEF_CONST(0.0761985131), COEF_CONST(0.0468732723), + COEF_CONST(0.0063956103), COEF_CONST(0.0063956103), COEF_CONST(0.0063956103)}, + {COEF_CONST(0.1956693050), COEF_CONST(0.1846090179), COEF_CONST(0.1673645109), COEF_CONST(0.1220621836), COEF_CONST(0.0757362479), + COEF_CONST(0.0103882630), COEF_CONST(0.0103882630), COEF_CONST(0.0103882630)}, + {COEF_CONST(0.3015113269), COEF_CONST(0.2870525790), COEF_CONST(0.2637738799), COEF_CONST(0.1984573949), COEF_CONST(0.1260749909), + COEF_CONST(0.0175600126), COEF_CONST(0.0175600126), COEF_CONST(0.0175600126)}, + {COEF_CONST(0.4078449476), COEF_CONST(0.3929852420), COEF_CONST(0.3680589270), COEF_CONST(0.2911029124), COEF_CONST(0.1934512363), + COEF_CONST(0.0278686716), COEF_CONST(0.0278686716), COEF_CONST(0.0278686716)}, + {COEF_CONST(0.5336171261), COEF_CONST(0.5226637762), COEF_CONST(0.5033652606), COEF_CONST(0.4349162672), COEF_CONST(0.3224682122), + COEF_CONST(0.0521999036), COEF_CONST(0.0521999036), COEF_CONST(0.0521999036)}, + {COEF_CONST(0.6219832023), COEF_CONST(0.6161847276), COEF_CONST(0.6057251063), COEF_CONST(0.5654342668), COEF_CONST(0.4826149915), + COEF_CONST(0.1058044758), COEF_CONST(0.1058044758), COEF_CONST(0.1058044758)}, + {COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), + COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657)}, + {COEF_CONST(0.7830305572), COEF_CONST(0.7876016373), COEF_CONST(0.7956739618), COEF_CONST(0.8247933372), COEF_CONST(0.8758325942), + COEF_CONST(0.9943869542), COEF_CONST(0.9943869542), COEF_CONST(0.9943869542)}, + {COEF_CONST(0.8457261833), COEF_CONST(0.8525388778), COEF_CONST(0.8640737401), COEF_CONST(0.9004708933), COEF_CONST(0.9465802987), + COEF_CONST(0.9986366532), COEF_CONST(0.9986366532), COEF_CONST(0.9986366532)}, + {COEF_CONST(0.9130511848), COEF_CONST(0.9195447612), COEF_CONST(0.9298024282), COEF_CONST(0.9566917233), COEF_CONST(0.9811098801), + COEF_CONST(0.9996115928), COEF_CONST(0.9996115928), COEF_CONST(0.9996115928)}, + {COEF_CONST(0.9534625907), COEF_CONST(0.9579148236), COEF_CONST(0.9645845234), COEF_CONST(0.9801095128), COEF_CONST(0.9920207064), + COEF_CONST(0.9998458099), COEF_CONST(0.9998458099), COEF_CONST(0.9998458099)}, + {COEF_CONST(0.9806699215), COEF_CONST(0.9828120260), COEF_CONST(0.9858950861), COEF_CONST(0.9925224431), COEF_CONST(0.9971278825), + COEF_CONST(0.9999460406), COEF_CONST(0.9999460406), COEF_CONST(0.9999460406)}, + {COEF_CONST(0.9921685024), COEF_CONST(0.9930882705), COEF_CONST(0.9943886135), COEF_CONST(0.9970926648), COEF_CONST(0.9989008403), + COEF_CONST(0.9999795479), COEF_CONST(0.9999795479), COEF_CONST(0.9999795479)}, + {COEF_CONST(0.9984226014), COEF_CONST(0.9986136287), COEF_CONST(0.9988810254), COEF_CONST(0.9994272242), COEF_CONST(0.9997851906), + COEF_CONST(0.9999960221), COEF_CONST(0.9999960221), COEF_CONST(0.9999960221)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sincos_alphas_B_fine[][8] = {{COEF_CONST(0.0031622158), COEF_CONST(0.0029630181), COEF_CONST(0.0026599892), COEF_CONST(0.0019002704), COEF_CONST(0.0011626042), + COEF_CONST(0.0001580278), COEF_CONST(0.0001580278), COEF_CONST(0.0001580278)}, + {COEF_CONST(0.0056232673), COEF_CONST(0.0052689825), COEF_CONST(0.0047302825), COEF_CONST(0.0033791756), COEF_CONST(0.0020674015), + COEF_CONST(0.0002811710), COEF_CONST(0.0002811710), COEF_CONST(0.0002811710)}, + {COEF_CONST(0.0099994225), COEF_CONST(0.0093696693), COEF_CONST(0.0084117414), COEF_CONST(0.0060093796), COEF_CONST(0.0036766009), + COEF_CONST(0.0005000392), COEF_CONST(0.0005000392), COEF_CONST(0.0005000392)}, + {COEF_CONST(0.0177799194), COEF_CONST(0.0166607102), COEF_CONST(0.0149581377), COEF_CONST(0.0106875809), COEF_CONST(0.0065392545), + COEF_CONST(0.0008893767), COEF_CONST(0.0008893767), COEF_CONST(0.0008893767)}, + {COEF_CONST(0.0316069684), COEF_CONST(0.0296211579), COEF_CONST(0.0265987295), COEF_CONST(0.0190113813), COEF_CONST(0.0116349973), + COEF_CONST(0.0015826974), COEF_CONST(0.0015826974), COEF_CONST(0.0015826974)}, + {COEF_CONST(0.0561454100), COEF_CONST(0.0526385859), COEF_CONST(0.0472937334), COEF_CONST(0.0338410641), COEF_CONST(0.0207261065), + COEF_CONST(0.0028205635), COEF_CONST(0.0028205635), COEF_CONST(0.0028205635)}, + {COEF_CONST(0.0791834041), COEF_CONST(0.0742798103), COEF_CONST(0.0667907269), COEF_CONST(0.0478705292), COEF_CONST(0.0293500747), + COEF_CONST(0.0039966755), COEF_CONST(0.0039966755), COEF_CONST(0.0039966755)}, + {COEF_CONST(0.1115021177), COEF_CONST(0.1047141985), COEF_CONST(0.0943053154), COEF_CONST(0.0678120561), COEF_CONST(0.0416669150), + COEF_CONST(0.0056813213), COEF_CONST(0.0056813213), COEF_CONST(0.0056813213)}, + {COEF_CONST(0.1565355066), COEF_CONST(0.1473258371), COEF_CONST(0.1330924027), COEF_CONST(0.0963282233), COEF_CONST(0.0594509113), + COEF_CONST(0.0081277946), COEF_CONST(0.0081277946), COEF_CONST(0.0081277946)}, + {COEF_CONST(0.2184643682), COEF_CONST(0.2064579524), COEF_CONST(0.1876265439), COEF_CONST(0.1375744167), COEF_CONST(0.0856896681), + COEF_CONST(0.0117817338), COEF_CONST(0.0117817338), COEF_CONST(0.0117817338)}, + {COEF_CONST(0.3015113269), COEF_CONST(0.2870525790), COEF_CONST(0.2637738799), COEF_CONST(0.1984573949), COEF_CONST(0.1260749909), + COEF_CONST(0.0175600126), COEF_CONST(0.0175600126), COEF_CONST(0.0175600126)}, + {COEF_CONST(0.3698741335), COEF_CONST(0.3547727297), COEF_CONST(0.3298252076), COEF_CONST(0.2556265829), COEF_CONST(0.1665990017), + COEF_CONST(0.0236344541), COEF_CONST(0.0236344541), COEF_CONST(0.0236344541)}, + {COEF_CONST(0.4480623975), COEF_CONST(0.4339410024), COEF_CONST(0.4098613774), COEF_CONST(0.3322709108), COEF_CONST(0.2266784729), + COEF_CONST(0.0334094131), COEF_CONST(0.0334094131), COEF_CONST(0.0334094131)}, + {COEF_CONST(0.5336171261), COEF_CONST(0.5226637762), COEF_CONST(0.5033652606), COEF_CONST(0.4349162672), COEF_CONST(0.3224682122), + COEF_CONST(0.0521999036), COEF_CONST(0.0521999036), COEF_CONST(0.0521999036)}, + {COEF_CONST(0.6219832023), COEF_CONST(0.6161847276), COEF_CONST(0.6057251063), COEF_CONST(0.5654342668), COEF_CONST(0.4826149915), + COEF_CONST(0.1058044758), COEF_CONST(0.1058044758), COEF_CONST(0.1058044758)}, + {COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), + COEF_CONST(0.7071067657), COEF_CONST(0.7071067657), COEF_CONST(0.7071067657)}, + {COEF_CONST(0.7830305572), COEF_CONST(0.7876016373), COEF_CONST(0.7956739618), COEF_CONST(0.8247933372), COEF_CONST(0.8758325942), + COEF_CONST(0.9943869542), COEF_CONST(0.9943869542), COEF_CONST(0.9943869542)}, + {COEF_CONST(0.8457261833), COEF_CONST(0.8525388778), COEF_CONST(0.8640737401), COEF_CONST(0.9004708933), COEF_CONST(0.9465802987), + COEF_CONST(0.9986366532), COEF_CONST(0.9986366532), COEF_CONST(0.9986366532)}, + {COEF_CONST(0.8940022267), COEF_CONST(0.9009412572), COEF_CONST(0.9121477564), COEF_CONST(0.9431839770), COEF_CONST(0.9739696219), + COEF_CONST(0.9994417480), COEF_CONST(0.9994417480), COEF_CONST(0.9994417480)}, + {COEF_CONST(0.9290818561), COEF_CONST(0.9349525662), COEF_CONST(0.9440420138), COEF_CONST(0.9667755833), COEF_CONST(0.9860247275), + COEF_CONST(0.9997206664), COEF_CONST(0.9997206664), COEF_CONST(0.9997206664)}, + {COEF_CONST(0.9534625907), COEF_CONST(0.9579148236), COEF_CONST(0.9645845234), COEF_CONST(0.9801095128), COEF_CONST(0.9920207064), + COEF_CONST(0.9998458099), COEF_CONST(0.9998458099), COEF_CONST(0.9998458099)}, + {COEF_CONST(0.9758449068), COEF_CONST(0.9784554646), COEF_CONST(0.9822404252), COEF_CONST(0.9904914275), COEF_CONST(0.9963218730), + COEF_CONST(0.9999305926), COEF_CONST(0.9999305926), COEF_CONST(0.9999305926)}, + {COEF_CONST(0.9876723320), COEF_CONST(0.9890880155), COEF_CONST(0.9911036356), COEF_CONST(0.9953496173), COEF_CONST(0.9982312259), + COEF_CONST(0.9999669685), COEF_CONST(0.9999669685), COEF_CONST(0.9999669685)}, + {COEF_CONST(0.9937641889), COEF_CONST(0.9945023501), COEF_CONST(0.9955433130), COEF_CONST(0.9976981117), COEF_CONST(0.9991315558), + COEF_CONST(0.9999838610), COEF_CONST(0.9999838610), COEF_CONST(0.9999838610)}, + {COEF_CONST(0.9968600642), COEF_CONST(0.9972374385), COEF_CONST(0.9977670024), COEF_CONST(0.9988535464), COEF_CONST(0.9995691924), + COEF_CONST(0.9999920129), COEF_CONST(0.9999920129), COEF_CONST(0.9999920129)}, + {COEF_CONST(0.9984226014), COEF_CONST(0.9986136287), COEF_CONST(0.9988810254), COEF_CONST(0.9994272242), COEF_CONST(0.9997851906), + COEF_CONST(0.9999960221), COEF_CONST(0.9999960221), COEF_CONST(0.9999960221)}, + {COEF_CONST(0.9995003746), COEF_CONST(0.9995611974), COEF_CONST(0.9996461891), COEF_CONST(0.9998192657), COEF_CONST(0.9999323103), + COEF_CONST(0.9999987475), COEF_CONST(0.9999987475), COEF_CONST(0.9999987475)}, + {COEF_CONST(0.9998419236), COEF_CONST(0.9998611991), COEF_CONST(0.9998881193), COEF_CONST(0.9999428861), COEF_CONST(0.9999786185), + COEF_CONST(0.9999996045), COEF_CONST(0.9999996045), COEF_CONST(0.9999996045)}, + {COEF_CONST(0.9999500038), COEF_CONST(0.9999561034), COEF_CONST(0.9999646206), COEF_CONST(0.9999819429), COEF_CONST(0.9999932409), + COEF_CONST(0.9999998750), COEF_CONST(0.9999998750), COEF_CONST(0.9999998750)}, + {COEF_CONST(0.9999841890), COEF_CONST(0.9999861183), COEF_CONST(0.9999888121), COEF_CONST(0.9999942902), COEF_CONST(0.9999978628), + COEF_CONST(0.9999999605), COEF_CONST(0.9999999605), COEF_CONST(0.9999999605)}, + {COEF_CONST(0.9999950000), COEF_CONST(0.9999956102), COEF_CONST(0.9999964621), COEF_CONST(0.9999981945), COEF_CONST(0.9999993242), + COEF_CONST(0.9999999875), COEF_CONST(0.9999999875), COEF_CONST(0.9999999875)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t cos_gammas_normal[][8] = {{COEF_CONST(1.0000000000), COEF_CONST(0.9841239707), COEF_CONST(0.9594738226), COEF_CONST(0.8946843024), COEF_CONST(0.8269341029), + COEF_CONST(0.7245688486), COEF_CONST(0.7245688486), COEF_CONST(0.7245688486)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9849690570), COEF_CONST(0.9617776789), COEF_CONST(0.9020941550), COEF_CONST(0.8436830391), + COEF_CONST(0.7846832804), COEF_CONST(0.7846832804), COEF_CONST(0.7846832804)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9871656089), COEF_CONST(0.9676774734), COEF_CONST(0.9199102884), COEF_CONST(0.8785067015), + COEF_CONST(0.8464232214), COEF_CONST(0.8464232214), COEF_CONST(0.8464232214)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9913533967), COEF_CONST(0.9786000177), COEF_CONST(0.9496063381), COEF_CONST(0.9277157252), + COEF_CONST(0.9133354077), COEF_CONST(0.9133354077), COEF_CONST(0.9133354077)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9948924435), COEF_CONST(0.9875319180), COEF_CONST(0.9716329849), COEF_CONST(0.9604805241), + COEF_CONST(0.9535949574), COEF_CONST(0.9535949574), COEF_CONST(0.9535949574)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9977406278), COEF_CONST(0.9945423840), COEF_CONST(0.9878736667), COEF_CONST(0.9833980494), + COEF_CONST(0.9807207440), COEF_CONST(0.9807207440), COEF_CONST(0.9807207440)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9990607067), COEF_CONST(0.9977417734), COEF_CONST(0.9950323970), COEF_CONST(0.9932453273), + COEF_CONST(0.9921884740), COEF_CONST(0.9921884740), COEF_CONST(0.9921884740)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9998081748), COEF_CONST(0.9995400312), COEF_CONST(0.9989936459), COEF_CONST(0.9986365356), + COEF_CONST(0.9984265591), COEF_CONST(0.9984265591), COEF_CONST(0.9984265591)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t cos_gammas_fine[][8] = {{COEF_CONST(1.0000000000), COEF_CONST(0.9841239707), COEF_CONST(0.9594738226), COEF_CONST(0.8946843024), COEF_CONST(0.8269341029), COEF_CONST(0.7245688486), + COEF_CONST(0.7245688486), COEF_CONST(0.7245688486)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9849690570), COEF_CONST(0.9617776789), COEF_CONST(0.9020941550), COEF_CONST(0.8436830391), COEF_CONST(0.7846832804), + COEF_CONST(0.7846832804), COEF_CONST(0.7846832804)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9871656089), COEF_CONST(0.9676774734), COEF_CONST(0.9199102884), COEF_CONST(0.8785067015), COEF_CONST(0.8464232214), + COEF_CONST(0.8464232214), COEF_CONST(0.8464232214)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9899597309), COEF_CONST(0.9750098690), COEF_CONST(0.9402333855), COEF_CONST(0.9129698759), COEF_CONST(0.8943765944), + COEF_CONST(0.8943765944), COEF_CONST(0.8943765944)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9926607607), COEF_CONST(0.9819295710), COEF_CONST(0.9580160104), COEF_CONST(0.9404993670), COEF_CONST(0.9293004472), + COEF_CONST(0.9293004472), COEF_CONST(0.9293004472)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9948924435), COEF_CONST(0.9875319180), COEF_CONST(0.9716329849), COEF_CONST(0.9604805241), COEF_CONST(0.9535949574), + COEF_CONST(0.9535949574), COEF_CONST(0.9535949574)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9972074644), COEF_CONST(0.9932414270), COEF_CONST(0.9849197629), COEF_CONST(0.9792926592), COEF_CONST(0.9759092525), + COEF_CONST(0.9759092525), COEF_CONST(0.9759092525)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9985361982), COEF_CONST(0.9964742028), COEF_CONST(0.9922136306), COEF_CONST(0.9893845420), COEF_CONST(0.9877041371), + COEF_CONST(0.9877041371), COEF_CONST(0.9877041371)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9992494366), COEF_CONST(0.9981967170), COEF_CONST(0.9960386625), COEF_CONST(0.9946185834), COEF_CONST(0.9937800239), + COEF_CONST(0.9937800239), COEF_CONST(0.9937800239)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9996194722), COEF_CONST(0.9990869422), COEF_CONST(0.9979996269), COEF_CONST(0.9972873651), COEF_CONST(0.9968679747), + COEF_CONST(0.9968679747), COEF_CONST(0.9968679747)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9998081748), COEF_CONST(0.9995400312), COEF_CONST(0.9989936459), COEF_CONST(0.9986365356), COEF_CONST(0.9984265591), + COEF_CONST(0.9984265591), COEF_CONST(0.9984265591)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9999390971), COEF_CONST(0.9998540271), COEF_CONST(0.9996809352), COEF_CONST(0.9995679735), COEF_CONST(0.9995016284), + COEF_CONST(0.9995016284), COEF_CONST(0.9995016284)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9999807170), COEF_CONST(0.9999537862), COEF_CONST(0.9998990191), COEF_CONST(0.9998632947), COEF_CONST(0.9998423208), + COEF_CONST(0.9998423208), COEF_CONST(0.9998423208)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9999938979), COEF_CONST(0.9999853814), COEF_CONST(0.9999680568), COEF_CONST(0.9999567596), COEF_CONST(0.9999501270), + COEF_CONST(0.9999501270), COEF_CONST(0.9999501270)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9999980703), COEF_CONST(0.9999953731), COEF_CONST(0.9999898968), COEF_CONST(0.9999863277), COEF_CONST(0.9999842265), + COEF_CONST(0.9999842265), COEF_CONST(0.9999842265)}, + {COEF_CONST(1.0000000000), COEF_CONST(0.9999993891), COEF_CONST(0.9999985397), COEF_CONST(0.9999968037), COEF_CONST(0.9999956786), COEF_CONST(0.9999950155), + COEF_CONST(0.9999950155), COEF_CONST(0.9999950155)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sin_gammas_normal[][8] = {{COEF_CONST(0.0000000000), COEF_CONST(0.1774824223), COEF_CONST(0.2817977711), COEF_CONST(0.4466990028), COEF_CONST(0.5622988435), + COEF_CONST(0.6892024258), COEF_CONST(0.6892024258), COEF_CONST(0.6892024258)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1727308798), COEF_CONST(0.2738315110), COEF_CONST(0.4315392630), COEF_CONST(0.5368416242), + COEF_CONST(0.6198968861), COEF_CONST(0.6198968861), COEF_CONST(0.6198968861)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1596999079), COEF_CONST(0.2521910140), COEF_CONST(0.3921288836), COEF_CONST(0.4777300236), + COEF_CONST(0.5325107795), COEF_CONST(0.5325107795), COEF_CONST(0.5325107795)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1312190642), COEF_CONST(0.2057717310), COEF_CONST(0.3134450552), COEF_CONST(0.3732874674), + COEF_CONST(0.4072080955), COEF_CONST(0.4072080955), COEF_CONST(0.4072080955)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1009407043), COEF_CONST(0.1574189028), COEF_CONST(0.2364938532), COEF_CONST(0.2783471983), + COEF_CONST(0.3010924396), COEF_CONST(0.3010924396), COEF_CONST(0.3010924396)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0671836269), COEF_CONST(0.1043333428), COEF_CONST(0.1552598422), COEF_CONST(0.1814615013), + COEF_CONST(0.1954144885), COEF_CONST(0.1954144885), COEF_CONST(0.1954144885)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0433324862), COEF_CONST(0.0671666110), COEF_CONST(0.0995516398), COEF_CONST(0.1160332699), + COEF_CONST(0.1247478739), COEF_CONST(0.1247478739), COEF_CONST(0.1247478739)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0195860576), COEF_CONST(0.0303269852), COEF_CONST(0.0448519274), COEF_CONST(0.0522022017), + COEF_CONST(0.0560750040), COEF_CONST(0.0560750040), COEF_CONST(0.0560750040)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sin_gammas_fine[][8] = {{COEF_CONST(0.0000000000), COEF_CONST(0.1774824223), COEF_CONST(0.2817977711), COEF_CONST(0.4466990028), COEF_CONST(0.5622988435), COEF_CONST(0.6892024258), + COEF_CONST(0.6892024258), COEF_CONST(0.6892024258)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1727308798), COEF_CONST(0.2738315110), COEF_CONST(0.4315392630), COEF_CONST(0.5368416242), COEF_CONST(0.6198968861), + COEF_CONST(0.6198968861), COEF_CONST(0.6198968861)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1596999079), COEF_CONST(0.2521910140), COEF_CONST(0.3921288836), COEF_CONST(0.4777300236), COEF_CONST(0.5325107795), + COEF_CONST(0.5325107795), COEF_CONST(0.5325107795)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1413496768), COEF_CONST(0.2221615526), COEF_CONST(0.3405307340), COEF_CONST(0.4080269669), COEF_CONST(0.4473147744), + COEF_CONST(0.4473147744), COEF_CONST(0.4473147744)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1209322714), COEF_CONST(0.1892467110), COEF_CONST(0.2867147079), COEF_CONST(0.3397954394), COEF_CONST(0.3693246252), + COEF_CONST(0.3693246252), COEF_CONST(0.3693246252)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.1009407043), COEF_CONST(0.1574189028), COEF_CONST(0.2364938532), COEF_CONST(0.2783471983), COEF_CONST(0.3010924396), + COEF_CONST(0.3010924396), COEF_CONST(0.3010924396)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0746811420), COEF_CONST(0.1160666523), COEF_CONST(0.1730117353), COEF_CONST(0.2024497161), COEF_CONST(0.2181768341), + COEF_CONST(0.2181768341), COEF_CONST(0.2181768341)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0540875291), COEF_CONST(0.0838997203), COEF_CONST(0.1245476266), COEF_CONST(0.1453211203), COEF_CONST(0.1563346972), + COEF_CONST(0.1563346972), COEF_CONST(0.1563346972)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0387371058), COEF_CONST(0.0600276114), COEF_CONST(0.0889212171), COEF_CONST(0.1036044086), COEF_CONST(0.1113609634), + COEF_CONST(0.1113609634), COEF_CONST(0.1113609634)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0275846110), COEF_CONST(0.0427233177), COEF_CONST(0.0632198125), COEF_CONST(0.0736064637), COEF_CONST(0.0790837596), + COEF_CONST(0.0790837596), COEF_CONST(0.0790837596)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0195860576), COEF_CONST(0.0303269852), COEF_CONST(0.0448519274), COEF_CONST(0.0522022017), COEF_CONST(0.0560750040), + COEF_CONST(0.0560750040), COEF_CONST(0.0560750040)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0110363955), COEF_CONST(0.0170857974), COEF_CONST(0.0252592108), COEF_CONST(0.0293916021), COEF_CONST(0.0315673054), + COEF_CONST(0.0315673054), COEF_CONST(0.0315673054)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0062101284), COEF_CONST(0.0096138203), COEF_CONST(0.0142109649), COEF_CONST(0.0165345659), COEF_CONST(0.0177576316), + COEF_CONST(0.0177576316), COEF_CONST(0.0177576316)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0034934509), COEF_CONST(0.0054071189), COEF_CONST(0.0079928316), COEF_CONST(0.0092994041), COEF_CONST(0.0099871631), + COEF_CONST(0.0099871631), COEF_CONST(0.0099871631)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0019645397), COEF_CONST(0.0030419905), COEF_CONST(0.0044951511), COEF_CONST(0.0052291853), COEF_CONST(0.0056166498), + COEF_CONST(0.0056166498), COEF_CONST(0.0056166498)}, + {COEF_CONST(0.0000000000), COEF_CONST(0.0011053943), COEF_CONST(0.0017089869), COEF_CONST(0.0025283670), COEF_CONST(0.0029398552), COEF_CONST(0.0031573685), + COEF_CONST(0.0031573685), COEF_CONST(0.0031573685)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sf_iid_normal[] = {COEF_CONST(1.4119827747), COEF_CONST(1.4031381607), COEF_CONST(1.3868767023), COEF_CONST(1.3483997583), COEF_CONST(1.2912493944), + COEF_CONST(1.1960374117), COEF_CONST(1.1073724031), COEF_CONST(1.0000000000), COEF_CONST(0.8796171546), COEF_CONST(0.7546485662), + COEF_CONST(0.5767799020), COEF_CONST(0.4264014363), COEF_CONST(0.2767182887), COEF_CONST(0.1766446233), COEF_CONST(0.0794016272)}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t sf_iid_fine[] = {COEF_CONST(1.4142065048), COEF_CONST(1.4141912460), COEF_CONST(1.4141428471), COEF_CONST(1.4139900208), COEF_CONST(1.4135069847), COEF_CONST(1.4119827747), + COEF_CONST(1.4097729921), COEF_CONST(1.4053947926), COEF_CONST(1.3967796564), COEF_CONST(1.3800530434), COEF_CONST(1.3483997583), COEF_CONST(1.3139201403), + COEF_CONST(1.2643101215), COEF_CONST(1.1960374117), COEF_CONST(1.1073724031), COEF_CONST(1.0000000000), COEF_CONST(0.8796171546), COEF_CONST(0.7546485662), + COEF_CONST(0.6336560845), COEF_CONST(0.5230810642), COEF_CONST(0.4264014363), COEF_CONST(0.3089554012), COEF_CONST(0.2213746458), COEF_CONST(0.1576878875), + COEF_CONST(0.1119822487), COEF_CONST(0.0794016272), COEF_CONST(0.0446990170), COEF_CONST(0.0251446925), COEF_CONST(0.0141414283), COEF_CONST(0.0079525812), + COEF_CONST(0.0044721137)}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t E_pan_tab[25] = {FRAC_CONST(0.000244081), FRAC_CONST(0.000488043), FRAC_CONST(0.00097561), FRAC_CONST(0.00194932), FRAC_CONST(0.00389105), + FRAC_CONST(0.00775194), FRAC_CONST(0.0153846), FRAC_CONST(0.030303), FRAC_CONST(0.0588235), FRAC_CONST(0.111111), + FRAC_CONST(0.2), FRAC_CONST(0.333333), FRAC_CONST(0.5), FRAC_CONST(0.666667), FRAC_CONST(0.8), + FRAC_CONST(0.888889), FRAC_CONST(0.941176), FRAC_CONST(0.969697), FRAC_CONST(0.984615), FRAC_CONST(0.992248), + FRAC_CONST(0.996109), FRAC_CONST(0.998051), FRAC_CONST(0.999024), FRAC_CONST(0.999512), FRAC_CONST(0.999756)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t E_deq_tab[64] = { + 64.0f, 128.0f, 256.0f, 512.0f, 1024.0f, 2048.0f, 4096.0f, 8192.0f, 16384.0f, 32768.0f, 65536.0f, 131072.0f, 262144.0f, + 524288.0f, 1.04858E+006f, 2.09715E+006f, 4.1943E+006f, 8.38861E+006f, 1.67772E+007f, 3.35544E+007f, 6.71089E+007f, 1.34218E+008f, 2.68435E+008f, 5.36871E+008f, 1.07374E+009f, 2.14748E+009f, + 4.29497E+009f, 8.58993E+009f, 1.71799E+010f, 3.43597E+010f, 6.87195E+010f, 1.37439E+011f, 2.74878E+011f, 5.49756E+011f, 1.09951E+012f, 2.19902E+012f, 4.39805E+012f, 8.79609E+012f, 1.75922E+013f, + 3.51844E+013f, 7.03687E+013f, 1.40737E+014f, 2.81475E+014f, 5.6295E+014f, 1.1259E+015f, 2.2518E+015f, 4.5036E+015f, 9.0072E+015f, 1.80144E+016f, 3.60288E+016f, 7.20576E+016f, 1.44115E+017f, + 2.8823E+017f, 5.76461E+017f, 1.15292E+018f, 2.30584E+018f, 4.61169E+018f, 9.22337E+018f, 1.84467E+019f, 3.68935E+019f, 7.3787E+019f, 1.47574E+020f, 2.95148E+020f, 5.90296E+020f}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +/* table for Q_div2 values when no coupling */ +static const real_t Q_div2_tab[31] = {FRAC_CONST(0.984615), FRAC_CONST(0.969697), FRAC_CONST(0.941176), FRAC_CONST(0.888889), FRAC_CONST(0.8), FRAC_CONST(0.666667), + FRAC_CONST(0.5), FRAC_CONST(0.333333), FRAC_CONST(0.2), FRAC_CONST(0.111111), FRAC_CONST(0.0588235), FRAC_CONST(0.030303), + FRAC_CONST(0.0153846), FRAC_CONST(0.00775194), FRAC_CONST(0.00389105), FRAC_CONST(0.00194932), FRAC_CONST(0.00097561), FRAC_CONST(0.000488043), + FRAC_CONST(0.000244081), FRAC_CONST(0.000122055), FRAC_CONST(6.10314E-005), FRAC_CONST(3.05166E-005), FRAC_CONST(1.52586E-005), FRAC_CONST(7.62934E-006), + FRAC_CONST(3.81468E-006), FRAC_CONST(1.90734E-006), FRAC_CONST(9.53673E-007), FRAC_CONST(4.76837E-007), FRAC_CONST(2.38419E-007), FRAC_CONST(1.19209E-007), + FRAC_CONST(5.96046E-008)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t Q_div2_tab_left[31][13] = { + {FRAC_CONST(0.0302959), FRAC_CONST(0.111015), FRAC_CONST(0.332468), FRAC_CONST(0.663212), FRAC_CONST(0.882759), FRAC_CONST(0.962406), FRAC_CONST(0.984615), FRAC_CONST(0.990329), + FRAC_CONST(0.991768), FRAC_CONST(0.992128), FRAC_CONST(0.992218), FRAC_CONST(0.992241), FRAC_CONST(0.992246)}, + {FRAC_CONST(0.0153809), FRAC_CONST(0.0587695), FRAC_CONST(0.199377), FRAC_CONST(0.496124), FRAC_CONST(0.790123), FRAC_CONST(0.927536), FRAC_CONST(0.969697), FRAC_CONST(0.980843), + FRAC_CONST(0.98367), FRAC_CONST(0.984379), FRAC_CONST(0.984556), FRAC_CONST(0.984601), FRAC_CONST(0.984612)}, + {FRAC_CONST(0.00775006), FRAC_CONST(0.0302744), FRAC_CONST(0.110727), FRAC_CONST(0.329897), FRAC_CONST(0.653061), FRAC_CONST(0.864865), FRAC_CONST(0.941176), FRAC_CONST(0.962406), + FRAC_CONST(0.967864), FRAC_CONST(0.969238), FRAC_CONST(0.969582), FRAC_CONST(0.969668), FRAC_CONST(0.96969)}, + {FRAC_CONST(0.0038901), FRAC_CONST(0.0153698), FRAC_CONST(0.0586081), FRAC_CONST(0.197531), FRAC_CONST(0.484848), FRAC_CONST(0.761905), FRAC_CONST(0.888889), FRAC_CONST(0.927536), + FRAC_CONST(0.937729), FRAC_CONST(0.940312), FRAC_CONST(0.94096), FRAC_CONST(0.941122), FRAC_CONST(0.941163)}, + {FRAC_CONST(0.00194884), FRAC_CONST(0.00774443), FRAC_CONST(0.0301887), FRAC_CONST(0.109589), FRAC_CONST(0.32), FRAC_CONST(0.615385), FRAC_CONST(0.8), FRAC_CONST(0.864865), FRAC_CONST(0.882759), + FRAC_CONST(0.887348), FRAC_CONST(0.888503), FRAC_CONST(0.888792), FRAC_CONST(0.888865)}, + {FRAC_CONST(0.000975372), FRAC_CONST(0.00388727), FRAC_CONST(0.0153257), FRAC_CONST(0.057971), FRAC_CONST(0.190476), FRAC_CONST(0.444444), FRAC_CONST(0.666667), FRAC_CONST(0.761905), + FRAC_CONST(0.790123), FRAC_CONST(0.797508), FRAC_CONST(0.799375), FRAC_CONST(0.799844), FRAC_CONST(0.799961)}, + {FRAC_CONST(0.000487924), FRAC_CONST(0.00194742), FRAC_CONST(0.00772201), FRAC_CONST(0.0298507), FRAC_CONST(0.105263), FRAC_CONST(0.285714), FRAC_CONST(0.5), FRAC_CONST(0.615385), + FRAC_CONST(0.653061), FRAC_CONST(0.663212), FRAC_CONST(0.6658), FRAC_CONST(0.66645), FRAC_CONST(0.666612)}, + {FRAC_CONST(0.000244021), FRAC_CONST(0.000974659), FRAC_CONST(0.00387597), FRAC_CONST(0.0151515), FRAC_CONST(0.0555556), FRAC_CONST(0.166667), FRAC_CONST(0.333333), FRAC_CONST(0.444444), + FRAC_CONST(0.484848), FRAC_CONST(0.496124), FRAC_CONST(0.499025), FRAC_CONST(0.499756), FRAC_CONST(0.499939)}, + {FRAC_CONST(0.000122026), FRAC_CONST(0.000487567), FRAC_CONST(0.00194175), FRAC_CONST(0.00763359), FRAC_CONST(0.0285714), FRAC_CONST(0.0909091), FRAC_CONST(0.2), FRAC_CONST(0.285714), + FRAC_CONST(0.32), FRAC_CONST(0.329897), FRAC_CONST(0.332468), FRAC_CONST(0.333116), FRAC_CONST(0.333279)}, + {FRAC_CONST(6.10165E-005), FRAC_CONST(0.000243843), FRAC_CONST(0.000971817), FRAC_CONST(0.00383142), FRAC_CONST(0.0144928), FRAC_CONST(0.047619), FRAC_CONST(0.111111), FRAC_CONST(0.166667), + FRAC_CONST(0.190476), FRAC_CONST(0.197531), FRAC_CONST(0.199377), FRAC_CONST(0.199844), FRAC_CONST(0.199961)}, + {FRAC_CONST(3.05092E-005), FRAC_CONST(0.000121936), FRAC_CONST(0.000486145), FRAC_CONST(0.00191939), FRAC_CONST(0.00729927), FRAC_CONST(0.0243902), FRAC_CONST(0.0588235), FRAC_CONST(0.0909091), + FRAC_CONST(0.105263), FRAC_CONST(0.109589), FRAC_CONST(0.110727), FRAC_CONST(0.111015), FRAC_CONST(0.111087)}, + {FRAC_CONST(1.52548E-005), FRAC_CONST(6.09719E-005), FRAC_CONST(0.000243132), FRAC_CONST(0.000960615), FRAC_CONST(0.003663), FRAC_CONST(0.0123457), FRAC_CONST(0.030303), FRAC_CONST(0.047619), + FRAC_CONST(0.0555556), FRAC_CONST(0.057971), FRAC_CONST(0.0586081), FRAC_CONST(0.0587695), FRAC_CONST(0.05881)}, + {FRAC_CONST(7.62747E-006), FRAC_CONST(3.04869E-005), FRAC_CONST(0.000121581), FRAC_CONST(0.000480538), FRAC_CONST(0.00183486), FRAC_CONST(0.00621118), FRAC_CONST(0.0153846), FRAC_CONST(0.0243902), + FRAC_CONST(0.0285714), FRAC_CONST(0.0298507), FRAC_CONST(0.0301887), FRAC_CONST(0.0302744), FRAC_CONST(0.0302959)}, + {FRAC_CONST(3.81375E-006), FRAC_CONST(1.52437E-005), FRAC_CONST(6.0794E-005), FRAC_CONST(0.000240327), FRAC_CONST(0.000918274), FRAC_CONST(0.00311526), FRAC_CONST(0.00775194), + FRAC_CONST(0.0123457), FRAC_CONST(0.0144928), FRAC_CONST(0.0151515), FRAC_CONST(0.0153257), FRAC_CONST(0.0153698), FRAC_CONST(0.0153809)}, + {FRAC_CONST(1.90688E-006), FRAC_CONST(7.62189E-006), FRAC_CONST(3.03979E-005), FRAC_CONST(0.000120178), FRAC_CONST(0.000459348), FRAC_CONST(0.00156006), FRAC_CONST(0.00389105), + FRAC_CONST(0.00621118), FRAC_CONST(0.00729927), FRAC_CONST(0.00763359), FRAC_CONST(0.00772201), FRAC_CONST(0.00774443), FRAC_CONST(0.00775006)}, + {FRAC_CONST(9.53441E-007), FRAC_CONST(3.81096E-006), FRAC_CONST(1.51992E-005), FRAC_CONST(6.00925E-005), FRAC_CONST(0.000229727), FRAC_CONST(0.00078064), FRAC_CONST(0.00194932), + FRAC_CONST(0.00311526), FRAC_CONST(0.003663), FRAC_CONST(0.00383142), FRAC_CONST(0.00387597), FRAC_CONST(0.00388727), FRAC_CONST(0.0038901)}, + {FRAC_CONST(4.76721E-007), FRAC_CONST(1.90548E-006), FRAC_CONST(7.59965E-006), FRAC_CONST(3.00472E-005), FRAC_CONST(0.000114877), FRAC_CONST(0.000390472), FRAC_CONST(0.00097561), + FRAC_CONST(0.00156006), FRAC_CONST(0.00183486), FRAC_CONST(0.00191939), FRAC_CONST(0.00194175), FRAC_CONST(0.00194742), FRAC_CONST(0.00194884)}, + {FRAC_CONST(2.3836E-007), FRAC_CONST(9.52743E-007), FRAC_CONST(3.79984E-006), FRAC_CONST(1.50238E-005), FRAC_CONST(5.74416E-005), FRAC_CONST(0.000195274), FRAC_CONST(0.000488043), + FRAC_CONST(0.00078064), FRAC_CONST(0.000918274), FRAC_CONST(0.000960615), FRAC_CONST(0.000971817), FRAC_CONST(0.000974659), FRAC_CONST(0.000975372)}, + {FRAC_CONST(1.1918E-007), FRAC_CONST(4.76372E-007), FRAC_CONST(1.89992E-006), FRAC_CONST(7.51196E-006), FRAC_CONST(2.87216E-005), FRAC_CONST(9.76467E-005), FRAC_CONST(0.000244081), + FRAC_CONST(0.000390472), FRAC_CONST(0.000459348), FRAC_CONST(0.000480538), FRAC_CONST(0.000486145), FRAC_CONST(0.000487567), FRAC_CONST(0.000487924)}, + {FRAC_CONST(5.95901E-008), FRAC_CONST(2.38186E-007), FRAC_CONST(9.49963E-007), FRAC_CONST(3.756E-006), FRAC_CONST(1.4361E-005), FRAC_CONST(4.88257E-005), FRAC_CONST(0.000122055), + FRAC_CONST(0.000195274), FRAC_CONST(0.000229727), FRAC_CONST(0.000240327), FRAC_CONST(0.000243132), FRAC_CONST(0.000243843), FRAC_CONST(0.000244021)}, + {FRAC_CONST(2.9795E-008), FRAC_CONST(1.19093E-007), FRAC_CONST(4.74982E-007), FRAC_CONST(1.878E-006), FRAC_CONST(7.18056E-006), FRAC_CONST(2.44135E-005), FRAC_CONST(6.10314E-005), + FRAC_CONST(9.76467E-005), FRAC_CONST(0.000114877), FRAC_CONST(0.000120178), FRAC_CONST(0.000121581), FRAC_CONST(0.000121936), FRAC_CONST(0.000122026)}, + {FRAC_CONST(1.48975E-008), FRAC_CONST(5.95465E-008), FRAC_CONST(2.37491E-007), FRAC_CONST(9.39002E-007), FRAC_CONST(3.59029E-006), FRAC_CONST(1.22069E-005), FRAC_CONST(3.05166E-005), + FRAC_CONST(4.88257E-005), FRAC_CONST(5.74416E-005), FRAC_CONST(6.00925E-005), FRAC_CONST(6.0794E-005), FRAC_CONST(6.09719E-005), FRAC_CONST(6.10165E-005)}, + {FRAC_CONST(7.44876E-009), FRAC_CONST(2.97732E-008), FRAC_CONST(1.18745E-007), FRAC_CONST(4.69501E-007), FRAC_CONST(1.79515E-006), FRAC_CONST(6.10348E-006), FRAC_CONST(1.52586E-005), + FRAC_CONST(2.44135E-005), FRAC_CONST(2.87216E-005), FRAC_CONST(3.00472E-005), FRAC_CONST(3.03979E-005), FRAC_CONST(3.04869E-005), FRAC_CONST(3.05092E-005)}, + {FRAC_CONST(3.72438E-009), FRAC_CONST(1.48866E-008), FRAC_CONST(5.93727E-008), FRAC_CONST(2.34751E-007), FRAC_CONST(8.97575E-007), FRAC_CONST(3.05175E-006), FRAC_CONST(7.62934E-006), + FRAC_CONST(1.22069E-005), FRAC_CONST(1.4361E-005), FRAC_CONST(1.50238E-005), FRAC_CONST(1.51992E-005), FRAC_CONST(1.52437E-005), FRAC_CONST(1.52548E-005)}, + {FRAC_CONST(1.86219E-009), FRAC_CONST(7.44331E-009), FRAC_CONST(2.96864E-008), FRAC_CONST(1.17375E-007), FRAC_CONST(4.48788E-007), FRAC_CONST(1.52588E-006), FRAC_CONST(3.81468E-006), + FRAC_CONST(6.10348E-006), FRAC_CONST(7.18056E-006), FRAC_CONST(7.51196E-006), FRAC_CONST(7.59965E-006), FRAC_CONST(7.62189E-006), FRAC_CONST(7.62747E-006)}, + {FRAC_CONST(9.31095E-010), FRAC_CONST(3.72166E-009), FRAC_CONST(1.48432E-008), FRAC_CONST(5.86876E-008), FRAC_CONST(2.24394E-007), FRAC_CONST(7.62939E-007), FRAC_CONST(1.90734E-006), + FRAC_CONST(3.05175E-006), FRAC_CONST(3.59029E-006), FRAC_CONST(3.756E-006), FRAC_CONST(3.79984E-006), FRAC_CONST(3.81096E-006), FRAC_CONST(3.81375E-006)}, + {FRAC_CONST(4.65548E-010), FRAC_CONST(1.86083E-009), FRAC_CONST(7.42159E-009), FRAC_CONST(2.93438E-008), FRAC_CONST(1.12197E-007), FRAC_CONST(3.8147E-007), FRAC_CONST(9.53673E-007), + FRAC_CONST(1.52588E-006), FRAC_CONST(1.79515E-006), FRAC_CONST(1.878E-006), FRAC_CONST(1.89992E-006), FRAC_CONST(1.90548E-006), FRAC_CONST(1.90688E-006)}, + {FRAC_CONST(2.32774E-010), FRAC_CONST(9.30414E-010), FRAC_CONST(3.71079E-009), FRAC_CONST(1.46719E-008), FRAC_CONST(5.60985E-008), FRAC_CONST(1.90735E-007), FRAC_CONST(4.76837E-007), + FRAC_CONST(7.62939E-007), FRAC_CONST(8.97575E-007), FRAC_CONST(9.39002E-007), FRAC_CONST(9.49963E-007), FRAC_CONST(9.52743E-007), FRAC_CONST(9.53441E-007)}, + {FRAC_CONST(1.16387E-010), FRAC_CONST(4.65207E-010), FRAC_CONST(1.8554E-009), FRAC_CONST(7.33596E-009), FRAC_CONST(2.80492E-008), FRAC_CONST(9.53674E-008), FRAC_CONST(2.38419E-007), + FRAC_CONST(3.8147E-007), FRAC_CONST(4.48788E-007), FRAC_CONST(4.69501E-007), FRAC_CONST(4.74982E-007), FRAC_CONST(4.76372E-007), FRAC_CONST(4.76721E-007)}, + {FRAC_CONST(5.81935E-011), FRAC_CONST(2.32603E-010), FRAC_CONST(9.27699E-010), FRAC_CONST(3.66798E-009), FRAC_CONST(1.40246E-008), FRAC_CONST(4.76837E-008), FRAC_CONST(1.19209E-007), + FRAC_CONST(1.90735E-007), FRAC_CONST(2.24394E-007), FRAC_CONST(2.34751E-007), FRAC_CONST(2.37491E-007), FRAC_CONST(2.38186E-007), FRAC_CONST(2.3836E-007)}, + {FRAC_CONST(2.90967E-011), FRAC_CONST(1.16302E-010), FRAC_CONST(4.63849E-010), FRAC_CONST(1.83399E-009), FRAC_CONST(7.01231E-009), FRAC_CONST(2.38419E-008), FRAC_CONST(5.96046E-008), + FRAC_CONST(9.53674E-008), FRAC_CONST(1.12197E-007), FRAC_CONST(1.17375E-007), FRAC_CONST(1.18745E-007), FRAC_CONST(1.19093E-007), FRAC_CONST(1.1918E-007)}}; + #endif // FIXED_POINT +#endif // SBR_DEC +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t Q_div2_tab_right[31][13] = { + {FRAC_CONST(0.992246), FRAC_CONST(0.992241), FRAC_CONST(0.992218), FRAC_CONST(0.992128), FRAC_CONST(0.991768), FRAC_CONST(0.990329), FRAC_CONST(0.984615), FRAC_CONST(0.962406), + FRAC_CONST(0.882759), FRAC_CONST(0.663212), FRAC_CONST(0.332468), FRAC_CONST(0.111015), FRAC_CONST(0.0302959)}, + {FRAC_CONST(0.984612), FRAC_CONST(0.984601), FRAC_CONST(0.984556), FRAC_CONST(0.984379), FRAC_CONST(0.98367), FRAC_CONST(0.980843), FRAC_CONST(0.969697), FRAC_CONST(0.927536), + FRAC_CONST(0.790123), FRAC_CONST(0.496124), FRAC_CONST(0.199377), FRAC_CONST(0.0587695), FRAC_CONST(0.0153809)}, + {FRAC_CONST(0.96969), FRAC_CONST(0.969668), FRAC_CONST(0.969582), FRAC_CONST(0.969238), FRAC_CONST(0.967864), FRAC_CONST(0.962406), FRAC_CONST(0.941176), FRAC_CONST(0.864865), + FRAC_CONST(0.653061), FRAC_CONST(0.329897), FRAC_CONST(0.110727), FRAC_CONST(0.0302744), FRAC_CONST(0.00775006)}, + {FRAC_CONST(0.941163), FRAC_CONST(0.941122), FRAC_CONST(0.94096), FRAC_CONST(0.940312), FRAC_CONST(0.937729), FRAC_CONST(0.927536), FRAC_CONST(0.888889), FRAC_CONST(0.761905), + FRAC_CONST(0.484848), FRAC_CONST(0.197531), FRAC_CONST(0.0586081), FRAC_CONST(0.0153698), FRAC_CONST(0.0038901)}, + {FRAC_CONST(0.888865), FRAC_CONST(0.888792), FRAC_CONST(0.888503), FRAC_CONST(0.887348), FRAC_CONST(0.882759), FRAC_CONST(0.864865), FRAC_CONST(0.8), FRAC_CONST(0.615385), FRAC_CONST(0.32), + FRAC_CONST(0.109589), FRAC_CONST(0.0301887), FRAC_CONST(0.00774443), FRAC_CONST(0.00194884)}, + {FRAC_CONST(0.799961), FRAC_CONST(0.799844), FRAC_CONST(0.799375), FRAC_CONST(0.797508), FRAC_CONST(0.790123), FRAC_CONST(0.761905), FRAC_CONST(0.666667), FRAC_CONST(0.444444), + FRAC_CONST(0.190476), FRAC_CONST(0.057971), FRAC_CONST(0.0153257), FRAC_CONST(0.00388727), FRAC_CONST(0.000975372)}, + {FRAC_CONST(0.666612), FRAC_CONST(0.66645), FRAC_CONST(0.6658), FRAC_CONST(0.663212), FRAC_CONST(0.653061), FRAC_CONST(0.615385), FRAC_CONST(0.5), FRAC_CONST(0.285714), FRAC_CONST(0.105263), + FRAC_CONST(0.0298507), FRAC_CONST(0.00772201), FRAC_CONST(0.00194742), FRAC_CONST(0.000487924)}, + {FRAC_CONST(0.499939), FRAC_CONST(0.499756), FRAC_CONST(0.499025), FRAC_CONST(0.496124), FRAC_CONST(0.484848), FRAC_CONST(0.444444), FRAC_CONST(0.333333), FRAC_CONST(0.166667), + FRAC_CONST(0.0555556), FRAC_CONST(0.0151515), FRAC_CONST(0.00387597), FRAC_CONST(0.000974659), FRAC_CONST(0.000244021)}, + {FRAC_CONST(0.333279), FRAC_CONST(0.333116), FRAC_CONST(0.332468), FRAC_CONST(0.329897), FRAC_CONST(0.32), FRAC_CONST(0.285714), FRAC_CONST(0.2), FRAC_CONST(0.0909091), FRAC_CONST(0.0285714), + FRAC_CONST(0.00763359), FRAC_CONST(0.00194175), FRAC_CONST(0.000487567), FRAC_CONST(0.000122026)}, + {FRAC_CONST(0.199961), FRAC_CONST(0.199844), FRAC_CONST(0.199377), FRAC_CONST(0.197531), FRAC_CONST(0.190476), FRAC_CONST(0.166667), FRAC_CONST(0.111111), FRAC_CONST(0.047619), + FRAC_CONST(0.0144928), FRAC_CONST(0.00383142), FRAC_CONST(0.000971817), FRAC_CONST(0.000243843), FRAC_CONST(6.10165E-005)}, + {FRAC_CONST(0.111087), FRAC_CONST(0.111015), FRAC_CONST(0.110727), FRAC_CONST(0.109589), FRAC_CONST(0.105263), FRAC_CONST(0.0909091), FRAC_CONST(0.0588235), FRAC_CONST(0.0243902), + FRAC_CONST(0.00729927), FRAC_CONST(0.00191939), FRAC_CONST(0.000486145), FRAC_CONST(0.000121936), FRAC_CONST(3.05092E-005)}, + {FRAC_CONST(0.05881), FRAC_CONST(0.0587695), FRAC_CONST(0.0586081), FRAC_CONST(0.057971), FRAC_CONST(0.0555556), FRAC_CONST(0.047619), FRAC_CONST(0.030303), FRAC_CONST(0.0123457), + FRAC_CONST(0.003663), FRAC_CONST(0.000960615), FRAC_CONST(0.000243132), FRAC_CONST(6.09719E-005), FRAC_CONST(1.52548E-005)}, + {FRAC_CONST(0.0302959), FRAC_CONST(0.0302744), FRAC_CONST(0.0301887), FRAC_CONST(0.0298507), FRAC_CONST(0.0285714), FRAC_CONST(0.0243902), FRAC_CONST(0.0153846), FRAC_CONST(0.00621118), + FRAC_CONST(0.00183486), FRAC_CONST(0.000480538), FRAC_CONST(0.000121581), FRAC_CONST(3.04869E-005), FRAC_CONST(7.62747E-006)}, + {FRAC_CONST(0.0153809), FRAC_CONST(0.0153698), FRAC_CONST(0.0153257), FRAC_CONST(0.0151515), FRAC_CONST(0.0144928), FRAC_CONST(0.0123457), FRAC_CONST(0.00775194), FRAC_CONST(0.00311526), + FRAC_CONST(0.000918274), FRAC_CONST(0.000240327), FRAC_CONST(6.0794E-005), FRAC_CONST(1.52437E-005), FRAC_CONST(3.81375E-006)}, + {FRAC_CONST(0.00775006), FRAC_CONST(0.00774443), FRAC_CONST(0.00772201), FRAC_CONST(0.00763359), FRAC_CONST(0.00729927), FRAC_CONST(0.00621118), FRAC_CONST(0.00389105), FRAC_CONST(0.00156006), + FRAC_CONST(0.000459348), FRAC_CONST(0.000120178), FRAC_CONST(3.03979E-005), FRAC_CONST(7.62189E-006), FRAC_CONST(1.90688E-006)}, + {FRAC_CONST(0.0038901), FRAC_CONST(0.00388727), FRAC_CONST(0.00387597), FRAC_CONST(0.00383142), FRAC_CONST(0.003663), FRAC_CONST(0.00311526), FRAC_CONST(0.00194932), FRAC_CONST(0.00078064), + FRAC_CONST(0.000229727), FRAC_CONST(6.00925E-005), FRAC_CONST(1.51992E-005), FRAC_CONST(3.81096E-006), FRAC_CONST(9.53441E-007)}, + {FRAC_CONST(0.00194884), FRAC_CONST(0.00194742), FRAC_CONST(0.00194175), FRAC_CONST(0.00191939), FRAC_CONST(0.00183486), FRAC_CONST(0.00156006), FRAC_CONST(0.00097561), FRAC_CONST(0.000390472), + FRAC_CONST(0.000114877), FRAC_CONST(3.00472E-005), FRAC_CONST(7.59965E-006), FRAC_CONST(1.90548E-006), FRAC_CONST(4.76721E-007)}, + {FRAC_CONST(0.000975372), FRAC_CONST(0.000974659), FRAC_CONST(0.000971817), FRAC_CONST(0.000960615), FRAC_CONST(0.000918274), FRAC_CONST(0.00078064), FRAC_CONST(0.000488043), + FRAC_CONST(0.000195274), FRAC_CONST(5.74416E-005), FRAC_CONST(1.50238E-005), FRAC_CONST(3.79984E-006), FRAC_CONST(9.52743E-007), FRAC_CONST(2.3836E-007)}, + {FRAC_CONST(0.000487924), FRAC_CONST(0.000487567), FRAC_CONST(0.000486145), FRAC_CONST(0.000480538), FRAC_CONST(0.000459348), FRAC_CONST(0.000390472), FRAC_CONST(0.000244081), + FRAC_CONST(9.76467E-005), FRAC_CONST(2.87216E-005), FRAC_CONST(7.51196E-006), FRAC_CONST(1.89992E-006), FRAC_CONST(4.76372E-007), FRAC_CONST(1.1918E-007)}, + {FRAC_CONST(0.000244021), FRAC_CONST(0.000243843), FRAC_CONST(0.000243132), FRAC_CONST(0.000240327), FRAC_CONST(0.000229727), FRAC_CONST(0.000195274), FRAC_CONST(0.000122055), + FRAC_CONST(4.88257E-005), FRAC_CONST(1.4361E-005), FRAC_CONST(3.756E-006), FRAC_CONST(9.49963E-007), FRAC_CONST(2.38186E-007), FRAC_CONST(5.95901E-008)}, + {FRAC_CONST(0.000122026), FRAC_CONST(0.000121936), FRAC_CONST(0.000121581), FRAC_CONST(0.000120178), FRAC_CONST(0.000114877), FRAC_CONST(9.76467E-005), FRAC_CONST(6.10314E-005), + FRAC_CONST(2.44135E-005), FRAC_CONST(7.18056E-006), FRAC_CONST(1.878E-006), FRAC_CONST(4.74982E-007), FRAC_CONST(1.19093E-007), FRAC_CONST(2.9795E-008)}, + {FRAC_CONST(6.10165E-005), FRAC_CONST(6.09719E-005), FRAC_CONST(6.0794E-005), FRAC_CONST(6.00925E-005), FRAC_CONST(5.74416E-005), FRAC_CONST(4.88257E-005), FRAC_CONST(3.05166E-005), + FRAC_CONST(1.22069E-005), FRAC_CONST(3.59029E-006), FRAC_CONST(9.39002E-007), FRAC_CONST(2.37491E-007), FRAC_CONST(5.95465E-008), FRAC_CONST(1.48975E-008)}, + {FRAC_CONST(3.05092E-005), FRAC_CONST(3.04869E-005), FRAC_CONST(3.03979E-005), FRAC_CONST(3.00472E-005), FRAC_CONST(2.87216E-005), FRAC_CONST(2.44135E-005), FRAC_CONST(1.52586E-005), + FRAC_CONST(6.10348E-006), FRAC_CONST(1.79515E-006), FRAC_CONST(4.69501E-007), FRAC_CONST(1.18745E-007), FRAC_CONST(2.97732E-008), FRAC_CONST(7.44876E-009)}, + {FRAC_CONST(1.52548E-005), FRAC_CONST(1.52437E-005), FRAC_CONST(1.51992E-005), FRAC_CONST(1.50238E-005), FRAC_CONST(1.4361E-005), FRAC_CONST(1.22069E-005), FRAC_CONST(7.62934E-006), + FRAC_CONST(3.05175E-006), FRAC_CONST(8.97575E-007), FRAC_CONST(2.34751E-007), FRAC_CONST(5.93727E-008), FRAC_CONST(1.48866E-008), FRAC_CONST(3.72438E-009)}, + {FRAC_CONST(7.62747E-006), FRAC_CONST(7.62189E-006), FRAC_CONST(7.59965E-006), FRAC_CONST(7.51196E-006), FRAC_CONST(7.18056E-006), FRAC_CONST(6.10348E-006), FRAC_CONST(3.81468E-006), + FRAC_CONST(1.52588E-006), FRAC_CONST(4.48788E-007), FRAC_CONST(1.17375E-007), FRAC_CONST(2.96864E-008), FRAC_CONST(7.44331E-009), FRAC_CONST(1.86219E-009)}, + {FRAC_CONST(3.81375E-006), FRAC_CONST(3.81096E-006), FRAC_CONST(3.79984E-006), FRAC_CONST(3.756E-006), FRAC_CONST(3.59029E-006), FRAC_CONST(3.05175E-006), FRAC_CONST(1.90734E-006), + FRAC_CONST(7.62939E-007), FRAC_CONST(2.24394E-007), FRAC_CONST(5.86876E-008), FRAC_CONST(1.48432E-008), FRAC_CONST(3.72166E-009), FRAC_CONST(9.31095E-010)}, + {FRAC_CONST(1.90688E-006), FRAC_CONST(1.90548E-006), FRAC_CONST(1.89992E-006), FRAC_CONST(1.878E-006), FRAC_CONST(1.79515E-006), FRAC_CONST(1.52588E-006), FRAC_CONST(9.53673E-007), + FRAC_CONST(3.8147E-007), FRAC_CONST(1.12197E-007), FRAC_CONST(2.93438E-008), FRAC_CONST(7.42159E-009), FRAC_CONST(1.86083E-009), FRAC_CONST(4.65548E-010)}, + {FRAC_CONST(9.53441E-007), FRAC_CONST(9.52743E-007), FRAC_CONST(9.49963E-007), FRAC_CONST(9.39002E-007), FRAC_CONST(8.97575E-007), FRAC_CONST(7.62939E-007), FRAC_CONST(4.76837E-007), + FRAC_CONST(1.90735E-007), FRAC_CONST(5.60985E-008), FRAC_CONST(1.46719E-008), FRAC_CONST(3.71079E-009), FRAC_CONST(9.30414E-010), FRAC_CONST(2.32774E-010)}, + {FRAC_CONST(4.76721E-007), FRAC_CONST(4.76372E-007), FRAC_CONST(4.74982E-007), FRAC_CONST(4.69501E-007), FRAC_CONST(4.48788E-007), FRAC_CONST(3.8147E-007), FRAC_CONST(2.38419E-007), + FRAC_CONST(9.53674E-008), FRAC_CONST(2.80492E-008), FRAC_CONST(7.33596E-009), FRAC_CONST(1.8554E-009), FRAC_CONST(4.65207E-010), FRAC_CONST(1.16387E-010)}, + {FRAC_CONST(2.3836E-007), FRAC_CONST(2.38186E-007), FRAC_CONST(2.37491E-007), FRAC_CONST(2.34751E-007), FRAC_CONST(2.24394E-007), FRAC_CONST(1.90735E-007), FRAC_CONST(1.19209E-007), + FRAC_CONST(4.76837E-008), FRAC_CONST(1.40246E-008), FRAC_CONST(3.66798E-009), FRAC_CONST(9.27699E-010), FRAC_CONST(2.32603E-010), FRAC_CONST(5.81935E-011)}, + {FRAC_CONST(1.1918E-007), FRAC_CONST(1.19093E-007), FRAC_CONST(1.18745E-007), FRAC_CONST(1.17375E-007), FRAC_CONST(1.12197E-007), FRAC_CONST(9.53674E-008), FRAC_CONST(5.96046E-008), + FRAC_CONST(2.38419E-008), FRAC_CONST(7.01231E-009), FRAC_CONST(1.83399E-009), FRAC_CONST(4.63849E-010), FRAC_CONST(1.16302E-010), FRAC_CONST(2.90967E-011)}}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +/* table for Q_div values when no coupling */ +static const real_t Q_div_tab[31] = {FRAC_CONST(0.0153846), FRAC_CONST(0.030303), FRAC_CONST(0.0588235), FRAC_CONST(0.111111), FRAC_CONST(0.2), FRAC_CONST(0.333333), FRAC_CONST(0.5), + FRAC_CONST(0.666667), FRAC_CONST(0.8), FRAC_CONST(0.888889), FRAC_CONST(0.941176), FRAC_CONST(0.969697), FRAC_CONST(0.984615), FRAC_CONST(0.992248), + FRAC_CONST(0.996109), FRAC_CONST(0.998051), FRAC_CONST(0.999024), FRAC_CONST(0.999512), FRAC_CONST(0.999756), FRAC_CONST(0.999878), FRAC_CONST(0.999939), + FRAC_CONST(0.999969), FRAC_CONST(0.999985), FRAC_CONST(0.999992), FRAC_CONST(0.999996), FRAC_CONST(0.999998), FRAC_CONST(0.999999), FRAC_CONST(1), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t Q_div_tab_left[31][13] = { + {FRAC_CONST(0.969704), FRAC_CONST(0.888985), FRAC_CONST(0.667532), FRAC_CONST(0.336788), FRAC_CONST(0.117241), FRAC_CONST(0.037594), FRAC_CONST(0.0153846), FRAC_CONST(0.00967118), + FRAC_CONST(0.00823245), FRAC_CONST(0.00787211), FRAC_CONST(0.00778198), FRAC_CONST(0.00775945), FRAC_CONST(0.00775382)}, + {FRAC_CONST(0.984619), FRAC_CONST(0.94123), FRAC_CONST(0.800623), FRAC_CONST(0.503876), FRAC_CONST(0.209877), FRAC_CONST(0.0724638), FRAC_CONST(0.030303), FRAC_CONST(0.0191571), + FRAC_CONST(0.0163305), FRAC_CONST(0.0156212), FRAC_CONST(0.0154438), FRAC_CONST(0.0153994), FRAC_CONST(0.0153883)}, + {FRAC_CONST(0.99225), FRAC_CONST(0.969726), FRAC_CONST(0.889273), FRAC_CONST(0.670103), FRAC_CONST(0.346939), FRAC_CONST(0.135135), FRAC_CONST(0.0588235), FRAC_CONST(0.037594), + FRAC_CONST(0.0321361), FRAC_CONST(0.0307619), FRAC_CONST(0.0304178), FRAC_CONST(0.0303317), FRAC_CONST(0.0303102)}, + {FRAC_CONST(0.99611), FRAC_CONST(0.98463), FRAC_CONST(0.941392), FRAC_CONST(0.802469), FRAC_CONST(0.515152), FRAC_CONST(0.238095), FRAC_CONST(0.111111), FRAC_CONST(0.0724638), + FRAC_CONST(0.0622711), FRAC_CONST(0.0596878), FRAC_CONST(0.0590397), FRAC_CONST(0.0588776), FRAC_CONST(0.058837)}, + {FRAC_CONST(0.998051), FRAC_CONST(0.992256), FRAC_CONST(0.969811), FRAC_CONST(0.890411), FRAC_CONST(0.68), FRAC_CONST(0.384615), FRAC_CONST(0.2), FRAC_CONST(0.135135), FRAC_CONST(0.117241), + FRAC_CONST(0.112652), FRAC_CONST(0.111497), FRAC_CONST(0.111208), FRAC_CONST(0.111135)}, + {FRAC_CONST(0.999025), FRAC_CONST(0.996113), FRAC_CONST(0.984674), FRAC_CONST(0.942029), FRAC_CONST(0.809524), FRAC_CONST(0.555556), FRAC_CONST(0.333333), FRAC_CONST(0.238095), + FRAC_CONST(0.209877), FRAC_CONST(0.202492), FRAC_CONST(0.200625), FRAC_CONST(0.200156), FRAC_CONST(0.200039)}, + {FRAC_CONST(0.999512), FRAC_CONST(0.998053), FRAC_CONST(0.992278), FRAC_CONST(0.970149), FRAC_CONST(0.894737), FRAC_CONST(0.714286), FRAC_CONST(0.5), FRAC_CONST(0.384615), FRAC_CONST(0.346939), + FRAC_CONST(0.336788), FRAC_CONST(0.3342), FRAC_CONST(0.33355), FRAC_CONST(0.333388)}, + {FRAC_CONST(0.999756), FRAC_CONST(0.999025), FRAC_CONST(0.996124), FRAC_CONST(0.984848), FRAC_CONST(0.944444), FRAC_CONST(0.833333), FRAC_CONST(0.666667), FRAC_CONST(0.555556), + FRAC_CONST(0.515152), FRAC_CONST(0.503876), FRAC_CONST(0.500975), FRAC_CONST(0.500244), FRAC_CONST(0.500061)}, + {FRAC_CONST(0.999878), FRAC_CONST(0.999512), FRAC_CONST(0.998058), FRAC_CONST(0.992366), FRAC_CONST(0.971429), FRAC_CONST(0.909091), FRAC_CONST(0.8), FRAC_CONST(0.714286), FRAC_CONST(0.68), + FRAC_CONST(0.670103), FRAC_CONST(0.667532), FRAC_CONST(0.666884), FRAC_CONST(0.666721)}, + {FRAC_CONST(0.999939), FRAC_CONST(0.999756), FRAC_CONST(0.999028), FRAC_CONST(0.996169), FRAC_CONST(0.985507), FRAC_CONST(0.952381), FRAC_CONST(0.888889), FRAC_CONST(0.833333), + FRAC_CONST(0.809524), FRAC_CONST(0.802469), FRAC_CONST(0.800623), FRAC_CONST(0.800156), FRAC_CONST(0.800039)}, + {FRAC_CONST(0.999969), FRAC_CONST(0.999878), FRAC_CONST(0.999514), FRAC_CONST(0.998081), FRAC_CONST(0.992701), FRAC_CONST(0.97561), FRAC_CONST(0.941176), FRAC_CONST(0.909091), + FRAC_CONST(0.894737), FRAC_CONST(0.890411), FRAC_CONST(0.889273), FRAC_CONST(0.888985), FRAC_CONST(0.888913)}, + {FRAC_CONST(0.999985), FRAC_CONST(0.999939), FRAC_CONST(0.999757), FRAC_CONST(0.999039), FRAC_CONST(0.996337), FRAC_CONST(0.987654), FRAC_CONST(0.969697), FRAC_CONST(0.952381), + FRAC_CONST(0.944444), FRAC_CONST(0.942029), FRAC_CONST(0.941392), FRAC_CONST(0.94123), FRAC_CONST(0.94119)}, + {FRAC_CONST(0.999992), FRAC_CONST(0.99997), FRAC_CONST(0.999878), FRAC_CONST(0.999519), FRAC_CONST(0.998165), FRAC_CONST(0.993789), FRAC_CONST(0.984615), FRAC_CONST(0.97561), FRAC_CONST(0.971429), + FRAC_CONST(0.970149), FRAC_CONST(0.969811), FRAC_CONST(0.969726), FRAC_CONST(0.969704)}, + {FRAC_CONST(0.999996), FRAC_CONST(0.999985), FRAC_CONST(0.999939), FRAC_CONST(0.99976), FRAC_CONST(0.999082), FRAC_CONST(0.996885), FRAC_CONST(0.992248), FRAC_CONST(0.987654), + FRAC_CONST(0.985507), FRAC_CONST(0.984848), FRAC_CONST(0.984674), FRAC_CONST(0.98463), FRAC_CONST(0.984619)}, + {FRAC_CONST(0.999998), FRAC_CONST(0.999992), FRAC_CONST(0.99997), FRAC_CONST(0.99988), FRAC_CONST(0.999541), FRAC_CONST(0.99844), FRAC_CONST(0.996109), FRAC_CONST(0.993789), FRAC_CONST(0.992701), + FRAC_CONST(0.992366), FRAC_CONST(0.992278), FRAC_CONST(0.992256), FRAC_CONST(0.99225)}, + {FRAC_CONST(0.999999), FRAC_CONST(0.999996), FRAC_CONST(0.999985), FRAC_CONST(0.99994), FRAC_CONST(0.99977), FRAC_CONST(0.999219), FRAC_CONST(0.998051), FRAC_CONST(0.996885), FRAC_CONST(0.996337), + FRAC_CONST(0.996169), FRAC_CONST(0.996124), FRAC_CONST(0.996113), FRAC_CONST(0.99611)}, + {FRAC_CONST(1), FRAC_CONST(0.999998), FRAC_CONST(0.999992), FRAC_CONST(0.99997), FRAC_CONST(0.999885), FRAC_CONST(0.99961), FRAC_CONST(0.999024), FRAC_CONST(0.99844), FRAC_CONST(0.998165), + FRAC_CONST(0.998081), FRAC_CONST(0.998058), FRAC_CONST(0.998053), FRAC_CONST(0.998051)}, + {FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999996), FRAC_CONST(0.999985), FRAC_CONST(0.999943), FRAC_CONST(0.999805), FRAC_CONST(0.999512), FRAC_CONST(0.999219), FRAC_CONST(0.999082), + FRAC_CONST(0.999039), FRAC_CONST(0.999028), FRAC_CONST(0.999025), FRAC_CONST(0.999025)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999998), FRAC_CONST(0.999992), FRAC_CONST(0.999971), FRAC_CONST(0.999902), FRAC_CONST(0.999756), FRAC_CONST(0.99961), FRAC_CONST(0.999541), + FRAC_CONST(0.999519), FRAC_CONST(0.999514), FRAC_CONST(0.999512), FRAC_CONST(0.999512)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999996), FRAC_CONST(0.999986), FRAC_CONST(0.999951), FRAC_CONST(0.999878), FRAC_CONST(0.999805), FRAC_CONST(0.99977), + FRAC_CONST(0.99976), FRAC_CONST(0.999757), FRAC_CONST(0.999756), FRAC_CONST(0.999756)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999998), FRAC_CONST(0.999993), FRAC_CONST(0.999976), FRAC_CONST(0.999939), FRAC_CONST(0.999902), FRAC_CONST(0.999885), + FRAC_CONST(0.99988), FRAC_CONST(0.999878), FRAC_CONST(0.999878), FRAC_CONST(0.999878)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999996), FRAC_CONST(0.999988), FRAC_CONST(0.999969), FRAC_CONST(0.999951), FRAC_CONST(0.999943), + FRAC_CONST(0.99994), FRAC_CONST(0.999939), FRAC_CONST(0.999939), FRAC_CONST(0.999939)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999998), FRAC_CONST(0.999994), FRAC_CONST(0.999985), FRAC_CONST(0.999976), FRAC_CONST(0.999971), FRAC_CONST(0.99997), + FRAC_CONST(0.99997), FRAC_CONST(0.99997), FRAC_CONST(0.999969)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999997), FRAC_CONST(0.999992), FRAC_CONST(0.999988), FRAC_CONST(0.999986), FRAC_CONST(0.999985), + FRAC_CONST(0.999985), FRAC_CONST(0.999985), FRAC_CONST(0.999985)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999998), FRAC_CONST(0.999996), FRAC_CONST(0.999994), FRAC_CONST(0.999993), FRAC_CONST(0.999992), + FRAC_CONST(0.999992), FRAC_CONST(0.999992), FRAC_CONST(0.999992)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999998), FRAC_CONST(0.999997), FRAC_CONST(0.999996), FRAC_CONST(0.999996), + FRAC_CONST(0.999996), FRAC_CONST(0.999996), FRAC_CONST(0.999996)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998), + FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), + FRAC_CONST(0.999999), FRAC_CONST(0.999999)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), + FRAC_CONST(1)}}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +static const real_t Q_div_tab_right[31][13] = { + {FRAC_CONST(0.00775382), FRAC_CONST(0.00775945), FRAC_CONST(0.00778198), FRAC_CONST(0.00787211), FRAC_CONST(0.00823245), FRAC_CONST(0.00967118), FRAC_CONST(0.0153846), FRAC_CONST(0.037594), + FRAC_CONST(0.117241), FRAC_CONST(0.336788), FRAC_CONST(0.667532), FRAC_CONST(0.888985), FRAC_CONST(0.969704)}, + {FRAC_CONST(0.0153883), FRAC_CONST(0.0153994), FRAC_CONST(0.0154438), FRAC_CONST(0.0156212), FRAC_CONST(0.0163305), FRAC_CONST(0.0191571), FRAC_CONST(0.030303), FRAC_CONST(0.0724638), + FRAC_CONST(0.209877), FRAC_CONST(0.503876), FRAC_CONST(0.800623), FRAC_CONST(0.94123), FRAC_CONST(0.984619)}, + {FRAC_CONST(0.0303102), FRAC_CONST(0.0303317), FRAC_CONST(0.0304178), FRAC_CONST(0.0307619), FRAC_CONST(0.0321361), FRAC_CONST(0.037594), FRAC_CONST(0.0588235), FRAC_CONST(0.135135), + FRAC_CONST(0.346939), FRAC_CONST(0.670103), FRAC_CONST(0.889273), FRAC_CONST(0.969726), FRAC_CONST(0.99225)}, + {FRAC_CONST(0.058837), FRAC_CONST(0.0588776), FRAC_CONST(0.0590397), FRAC_CONST(0.0596878), FRAC_CONST(0.0622711), FRAC_CONST(0.0724638), FRAC_CONST(0.111111), FRAC_CONST(0.238095), + FRAC_CONST(0.515152), FRAC_CONST(0.802469), FRAC_CONST(0.941392), FRAC_CONST(0.98463), FRAC_CONST(0.99611)}, + {FRAC_CONST(0.111135), FRAC_CONST(0.111208), FRAC_CONST(0.111497), FRAC_CONST(0.112652), FRAC_CONST(0.117241), FRAC_CONST(0.135135), FRAC_CONST(0.2), FRAC_CONST(0.384615), FRAC_CONST(0.68), + FRAC_CONST(0.890411), FRAC_CONST(0.969811), FRAC_CONST(0.992256), FRAC_CONST(0.998051)}, + {FRAC_CONST(0.200039), FRAC_CONST(0.200156), FRAC_CONST(0.200625), FRAC_CONST(0.202492), FRAC_CONST(0.209877), FRAC_CONST(0.238095), FRAC_CONST(0.333333), FRAC_CONST(0.555556), + FRAC_CONST(0.809524), FRAC_CONST(0.942029), FRAC_CONST(0.984674), FRAC_CONST(0.996113), FRAC_CONST(0.999025)}, + {FRAC_CONST(0.333388), FRAC_CONST(0.33355), FRAC_CONST(0.3342), FRAC_CONST(0.336788), FRAC_CONST(0.346939), FRAC_CONST(0.384615), FRAC_CONST(0.5), FRAC_CONST(0.714286), FRAC_CONST(0.894737), + FRAC_CONST(0.970149), FRAC_CONST(0.992278), FRAC_CONST(0.998053), FRAC_CONST(0.999512)}, + {FRAC_CONST(0.500061), FRAC_CONST(0.500244), FRAC_CONST(0.500975), FRAC_CONST(0.503876), FRAC_CONST(0.515152), FRAC_CONST(0.555556), FRAC_CONST(0.666667), FRAC_CONST(0.833333), + FRAC_CONST(0.944444), FRAC_CONST(0.984848), FRAC_CONST(0.996124), FRAC_CONST(0.999025), FRAC_CONST(0.999756)}, + {FRAC_CONST(0.666721), FRAC_CONST(0.666884), FRAC_CONST(0.667532), FRAC_CONST(0.670103), FRAC_CONST(0.68), FRAC_CONST(0.714286), FRAC_CONST(0.8), FRAC_CONST(0.909091), FRAC_CONST(0.971429), + FRAC_CONST(0.992366), FRAC_CONST(0.998058), FRAC_CONST(0.999512), FRAC_CONST(0.999878)}, + {FRAC_CONST(0.800039), FRAC_CONST(0.800156), FRAC_CONST(0.800623), FRAC_CONST(0.802469), FRAC_CONST(0.809524), FRAC_CONST(0.833333), FRAC_CONST(0.888889), FRAC_CONST(0.952381), + FRAC_CONST(0.985507), FRAC_CONST(0.996169), FRAC_CONST(0.999028), FRAC_CONST(0.999756), FRAC_CONST(0.999939)}, + {FRAC_CONST(0.888913), FRAC_CONST(0.888985), FRAC_CONST(0.889273), FRAC_CONST(0.890411), FRAC_CONST(0.894737), FRAC_CONST(0.909091), FRAC_CONST(0.941176), FRAC_CONST(0.97561), + FRAC_CONST(0.992701), FRAC_CONST(0.998081), FRAC_CONST(0.999514), FRAC_CONST(0.999878), FRAC_CONST(0.999969)}, + {FRAC_CONST(0.94119), FRAC_CONST(0.94123), FRAC_CONST(0.941392), FRAC_CONST(0.942029), FRAC_CONST(0.944444), FRAC_CONST(0.952381), FRAC_CONST(0.969697), FRAC_CONST(0.987654), FRAC_CONST(0.996337), + FRAC_CONST(0.999039), FRAC_CONST(0.999757), FRAC_CONST(0.999939), FRAC_CONST(0.999985)}, + {FRAC_CONST(0.969704), FRAC_CONST(0.969726), FRAC_CONST(0.969811), FRAC_CONST(0.970149), FRAC_CONST(0.971429), FRAC_CONST(0.97561), FRAC_CONST(0.984615), FRAC_CONST(0.993789), + FRAC_CONST(0.998165), FRAC_CONST(0.999519), FRAC_CONST(0.999878), FRAC_CONST(0.99997), FRAC_CONST(0.999992)}, + {FRAC_CONST(0.984619), FRAC_CONST(0.98463), FRAC_CONST(0.984674), FRAC_CONST(0.984848), FRAC_CONST(0.985507), FRAC_CONST(0.987654), FRAC_CONST(0.992248), FRAC_CONST(0.996885), + FRAC_CONST(0.999082), FRAC_CONST(0.99976), FRAC_CONST(0.999939), FRAC_CONST(0.999985), FRAC_CONST(0.999996)}, + {FRAC_CONST(0.99225), FRAC_CONST(0.992256), FRAC_CONST(0.992278), FRAC_CONST(0.992366), FRAC_CONST(0.992701), FRAC_CONST(0.993789), FRAC_CONST(0.996109), FRAC_CONST(0.99844), FRAC_CONST(0.999541), + FRAC_CONST(0.99988), FRAC_CONST(0.99997), FRAC_CONST(0.999992), FRAC_CONST(0.999998)}, + {FRAC_CONST(0.99611), FRAC_CONST(0.996113), FRAC_CONST(0.996124), FRAC_CONST(0.996169), FRAC_CONST(0.996337), FRAC_CONST(0.996885), FRAC_CONST(0.998051), FRAC_CONST(0.999219), FRAC_CONST(0.99977), + FRAC_CONST(0.99994), FRAC_CONST(0.999985), FRAC_CONST(0.999996), FRAC_CONST(0.999999)}, + {FRAC_CONST(0.998051), FRAC_CONST(0.998053), FRAC_CONST(0.998058), FRAC_CONST(0.998081), FRAC_CONST(0.998165), FRAC_CONST(0.99844), FRAC_CONST(0.999024), FRAC_CONST(0.99961), FRAC_CONST(0.999885), + FRAC_CONST(0.99997), FRAC_CONST(0.999992), FRAC_CONST(0.999998), FRAC_CONST(1)}, + {FRAC_CONST(0.999025), FRAC_CONST(0.999025), FRAC_CONST(0.999028), FRAC_CONST(0.999039), FRAC_CONST(0.999082), FRAC_CONST(0.999219), FRAC_CONST(0.999512), FRAC_CONST(0.999805), + FRAC_CONST(0.999943), FRAC_CONST(0.999985), FRAC_CONST(0.999996), FRAC_CONST(0.999999), FRAC_CONST(1)}, + {FRAC_CONST(0.999512), FRAC_CONST(0.999512), FRAC_CONST(0.999514), FRAC_CONST(0.999519), FRAC_CONST(0.999541), FRAC_CONST(0.99961), FRAC_CONST(0.999756), FRAC_CONST(0.999902), + FRAC_CONST(0.999971), FRAC_CONST(0.999992), FRAC_CONST(0.999998), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999756), FRAC_CONST(0.999756), FRAC_CONST(0.999757), FRAC_CONST(0.99976), FRAC_CONST(0.99977), FRAC_CONST(0.999805), FRAC_CONST(0.999878), FRAC_CONST(0.999951), FRAC_CONST(0.999986), + FRAC_CONST(0.999996), FRAC_CONST(0.999999), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999878), FRAC_CONST(0.999878), FRAC_CONST(0.999878), FRAC_CONST(0.99988), FRAC_CONST(0.999885), FRAC_CONST(0.999902), FRAC_CONST(0.999939), FRAC_CONST(0.999976), + FRAC_CONST(0.999993), FRAC_CONST(0.999998), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999939), FRAC_CONST(0.999939), FRAC_CONST(0.999939), FRAC_CONST(0.99994), FRAC_CONST(0.999943), FRAC_CONST(0.999951), FRAC_CONST(0.999969), FRAC_CONST(0.999988), + FRAC_CONST(0.999996), FRAC_CONST(0.999999), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999969), FRAC_CONST(0.99997), FRAC_CONST(0.99997), FRAC_CONST(0.99997), FRAC_CONST(0.999971), FRAC_CONST(0.999976), FRAC_CONST(0.999985), FRAC_CONST(0.999994), FRAC_CONST(0.999998), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999985), FRAC_CONST(0.999985), FRAC_CONST(0.999985), FRAC_CONST(0.999985), FRAC_CONST(0.999986), FRAC_CONST(0.999988), FRAC_CONST(0.999992), FRAC_CONST(0.999997), + FRAC_CONST(0.999999), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999992), FRAC_CONST(0.999992), FRAC_CONST(0.999992), FRAC_CONST(0.999992), FRAC_CONST(0.999993), FRAC_CONST(0.999994), FRAC_CONST(0.999996), FRAC_CONST(0.999998), FRAC_CONST(1), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999996), FRAC_CONST(0.999996), FRAC_CONST(0.999996), FRAC_CONST(0.999996), FRAC_CONST(0.999996), FRAC_CONST(0.999997), FRAC_CONST(0.999998), FRAC_CONST(0.999999), FRAC_CONST(1), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999998), FRAC_CONST(0.999999), FRAC_CONST(1), FRAC_CONST(1), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(0.999999), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), + FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1)}, + {FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), FRAC_CONST(1), + FRAC_CONST(1)}}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const int8_t t_huffman_env_1_5dB[120][2] = { + {1, 2}, {-64, -65}, {3, 4}, {-63, -66}, {5, 6}, {-62, -67}, {7, 8}, {-61, -68}, {9, 10}, {-60, -69}, {11, 12}, {-59, -70}, {13, 14}, {-58, -71}, + {15, 16}, {-57, -72}, {17, 18}, {-73, -56}, {19, 21}, {-74, 20}, {-55, -75}, {22, 26}, {23, 24}, {-54, -76}, {-77, 25}, {-53, -78}, {27, 34}, {28, 29}, + {-52, -79}, {30, 31}, {-80, -51}, {32, 33}, {-83, -82}, {-81, -50}, {35, 57}, {36, 40}, {37, 38}, {-88, -84}, {-48, 39}, {-90, -85}, {41, 46}, {42, 43}, + {-49, -87}, {44, 45}, {-89, -86}, {-124, -123}, {47, 50}, {48, 49}, {-122, -121}, {-120, -119}, {51, 54}, {52, 53}, {-118, -117}, {-116, -115}, {55, 56}, {-114, -113}, + {-112, -111}, {58, 89}, {59, 74}, {60, 67}, {61, 64}, {62, 63}, {-110, -109}, {-108, -107}, {65, 66}, {-106, -105}, {-104, -103}, {68, 71}, {69, 70}, {-102, -101}, + {-100, -99}, {72, 73}, {-98, -97}, {-96, -95}, {75, 82}, {76, 79}, {77, 78}, {-94, -93}, {-92, -91}, {80, 81}, {-47, -46}, {-45, -44}, {83, 86}, {84, 85}, + {-43, -42}, {-41, -40}, {87, 88}, {-39, -38}, {-37, -36}, {90, 105}, {91, 98}, {92, 95}, {93, 94}, {-35, -34}, {-33, -32}, {96, 97}, {-31, -30}, {-29, -28}, + {99, 102}, {100, 101}, {-27, -26}, {-25, -24}, {103, 104}, {-23, -22}, {-21, -20}, {106, 113}, {107, 110}, {108, 109}, {-19, -18}, {-17, -16}, {111, 112}, {-15, -14}, + {-13, -12}, {114, 117}, {115, 116}, {-11, -10}, {-9, -8}, {118, 119}, {-7, -6}, {-5, -4}}; + +static const int8_t f_huffman_env_1_5dB[120][2] = { + {1, 2}, {-64, -65}, {3, 4}, {-63, -66}, {5, 6}, {-67, -62}, {7, 8}, {-68, -61}, {9, 10}, {-69, -60}, {11, 13}, {-70, 12}, {-59, -71}, {14, 16}, + {-58, 15}, {-72, -57}, {17, 19}, {-73, 18}, {-56, -74}, {20, 23}, {21, 22}, {-55, -75}, {-54, -53}, {24, 27}, {25, 26}, {-76, -52}, {-77, -51}, {28, 31}, + {29, 30}, {-50, -78}, {-79, -49}, {32, 36}, {33, 34}, {-48, -47}, {-80, 35}, {-81, -82}, {37, 47}, {38, 41}, {39, 40}, {-83, -46}, {-45, -84}, {42, 44}, + {-85, 43}, {-44, -43}, {45, 46}, {-88, -87}, {-86, -90}, {48, 66}, {49, 56}, {50, 53}, {51, 52}, {-92, -42}, {-41, -39}, {54, 55}, {-105, -89}, {-38, -37}, + {57, 60}, {58, 59}, {-94, -91}, {-40, -36}, {61, 63}, {-20, 62}, {-115, -110}, {64, 65}, {-108, -107}, {-101, -97}, {67, 89}, {68, 75}, {69, 72}, {70, 71}, + {-95, -93}, {-34, -27}, {73, 74}, {-22, -17}, {-16, -124}, {76, 82}, {77, 79}, {-123, 78}, {-122, -121}, {80, 81}, {-120, -119}, {-118, -117}, {83, 86}, {84, 85}, + {-116, -114}, {-113, -112}, {87, 88}, {-111, -109}, {-106, -104}, {90, 105}, {91, 98}, {92, 95}, {93, 94}, {-103, -102}, {-100, -99}, {96, 97}, {-98, -96}, {-35, -33}, + {99, 102}, {100, 101}, {-32, -31}, {-30, -29}, {103, 104}, {-28, -26}, {-25, -24}, {106, 113}, {107, 110}, {108, 109}, {-23, -21}, {-19, -18}, {111, 112}, {-15, -14}, + {-13, -12}, {114, 117}, {115, 116}, {-11, -10}, {-9, -8}, {118, 119}, {-7, -6}, {-5, -4}}; + +static const int8_t t_huffman_env_bal_1_5dB[48][2] = {{-64, 1}, {-63, 2}, {-65, 3}, {-62, 4}, {-66, 5}, {-61, 6}, {-67, 7}, {-60, 8}, {-68, 9}, {10, 11}, {-69, -59}, {12, 13}, + {-70, -58}, {14, 28}, {15, 21}, {16, 18}, {-57, 17}, {-71, -56}, {19, 20}, {-88, -87}, {-86, -85}, {22, 25}, {23, 24}, {-84, -83}, + {-82, -81}, {26, 27}, {-80, -79}, {-78, -77}, {29, 36}, {30, 33}, {31, 32}, {-76, -75}, {-74, -73}, {34, 35}, {-72, -55}, {-54, -53}, + {37, 41}, {38, 39}, {-52, -51}, {-50, 40}, {-49, -48}, {42, 45}, {43, 44}, {-47, -46}, {-45, -44}, {46, 47}, {-43, -42}, {-41, -40}}; + +static const int8_t f_huffman_env_bal_1_5dB[48][2] = {{-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-61, 6}, {-67, 7}, {-68, 8}, {-60, 9}, {10, 11}, {-69, -59}, {-70, 12}, + {-58, 13}, {14, 17}, {-71, 15}, {-57, 16}, {-56, -73}, {18, 32}, {19, 25}, {20, 22}, {-72, 21}, {-88, -87}, {23, 24}, {-86, -85}, + {-84, -83}, {26, 29}, {27, 28}, {-82, -81}, {-80, -79}, {30, 31}, {-78, -77}, {-76, -75}, {33, 40}, {34, 37}, {35, 36}, {-74, -55}, + {-54, -53}, {38, 39}, {-52, -51}, {-50, -49}, {41, 44}, {42, 43}, {-48, -47}, {-46, -45}, {45, 46}, {-44, -43}, {-42, 47}, {-41, -40}}; + +static const int8_t t_huffman_env_3_0dB[62][2] = { + {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-67, 6}, {-61, 7}, {-68, 8}, {-60, 9}, {10, 11}, {-69, -59}, {12, 14}, {-70, 13}, {-71, -58}, {15, 18}, {16, 17}, + {-72, -57}, {-73, -74}, {19, 22}, {-56, 20}, {-55, 21}, {-54, -77}, {23, 31}, {24, 25}, {-75, -76}, {26, 27}, {-78, -53}, {28, 29}, {-52, -95}, {-94, 30}, {-93, -92}, {32, 47}, + {33, 40}, {34, 37}, {35, 36}, {-91, -90}, {-89, -88}, {38, 39}, {-87, -86}, {-85, -84}, {41, 44}, {42, 43}, {-83, -82}, {-81, -80}, {45, 46}, {-79, -51}, {-50, -49}, {48, 55}, + {49, 52}, {50, 51}, {-48, -47}, {-46, -45}, {53, 54}, {-44, -43}, {-42, -41}, {56, 59}, {57, 58}, {-40, -39}, {-38, -37}, {60, 61}, {-36, -35}, {-34, -33}}; + +static const int8_t f_huffman_env_3_0dB[62][2] = { + {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-67, 6}, {7, 8}, {-61, -68}, {9, 10}, {-60, -69}, {11, 12}, {-59, -70}, {13, 14}, {-58, -71}, {15, 16}, {-57, -72}, + {17, 19}, {-56, 18}, {-55, -73}, {20, 24}, {21, 22}, {-74, -54}, {-53, 23}, {-75, -76}, {25, 30}, {26, 27}, {-52, -51}, {28, 29}, {-77, -79}, {-50, -49}, {31, 39}, {32, 35}, + {33, 34}, {-78, -46}, {-82, -88}, {36, 37}, {-83, -48}, {-47, 38}, {-86, -85}, {40, 47}, {41, 44}, {42, 43}, {-80, -44}, {-43, -42}, {45, 46}, {-39, -87}, {-84, -40}, {48, 55}, + {49, 52}, {50, 51}, {-95, -94}, {-93, -92}, {53, 54}, {-91, -90}, {-89, -81}, {56, 59}, {57, 58}, {-45, -41}, {-38, -37}, {60, 61}, {-36, -35}, {-34, -33}}; + +static const int8_t t_huffman_env_bal_3_0dB[24][2] = {{-64, 1}, {-63, 2}, {-65, 3}, {-66, 4}, {-62, 5}, {-61, 6}, {-67, 7}, {-68, 8}, {-60, 9}, {10, 16}, {11, 13}, {-69, 12}, + {-76, -75}, {14, 15}, {-74, -73}, {-72, -71}, {17, 20}, {18, 19}, {-70, -59}, {-58, -57}, {21, 22}, {-56, -55}, {-54, 23}, {-53, -52}}; + +static const int8_t f_huffman_env_bal_3_0dB[24][2] = {{-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-61, 6}, {-67, 7}, {-68, 8}, {-60, 9}, {10, 13}, {-69, 11}, {-59, 12}, + {-58, -76}, {14, 17}, {15, 16}, {-75, -74}, {-73, -72}, {18, 21}, {19, 20}, {-71, -70}, {-57, -56}, {22, 23}, {-55, -54}, {-53, -52}}; + +static const int8_t t_huffman_noise_3_0dB[62][2] = { + {-64, 1}, {-63, 2}, {-65, 3}, {-66, 4}, {-62, 5}, {-67, 6}, {7, 8}, {-61, -68}, {9, 30}, {10, 15}, {-60, 11}, {-69, 12}, {13, 14}, {-59, -53}, {-95, -94}, {16, 23}, + {17, 20}, {18, 19}, {-93, -92}, {-91, -90}, {21, 22}, {-89, -88}, {-87, -86}, {24, 27}, {25, 26}, {-85, -84}, {-83, -82}, {28, 29}, {-81, -80}, {-79, -78}, {31, 46}, {32, 39}, + {33, 36}, {34, 35}, {-77, -76}, {-75, -74}, {37, 38}, {-73, -72}, {-71, -70}, {40, 43}, {41, 42}, {-58, -57}, {-56, -55}, {44, 45}, {-54, -52}, {-51, -50}, {47, 54}, {48, 51}, + {49, 50}, {-49, -48}, {-47, -46}, {52, 53}, {-45, -44}, {-43, -42}, {55, 58}, {56, 57}, {-41, -40}, {-39, -38}, {59, 60}, {-37, -36}, {-35, 61}, {-34, -33}}; + +static const int8_t t_huffman_noise_bal_3_0dB[24][2] = {{-64, 1}, {-65, 2}, {-63, 3}, {4, 9}, {-66, 5}, {-62, 6}, {7, 8}, {-76, -75}, {-74, -73}, {10, 17}, {11, 14}, {12, 13}, + {-72, -71}, {-70, -69}, {15, 16}, {-68, -67}, {-61, -60}, {18, 21}, {19, 20}, {-59, -58}, {-57, -56}, {22, 23}, {-55, -54}, {-53, -52}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +static const real_t log_Qplus1_pan[31][13] = { + {REAL_CONST(0.044383447617292), REAL_CONST(0.169768601655960), REAL_CONST(0.583090126514435), REAL_CONST(1.570089221000671), REAL_CONST(3.092446088790894), REAL_CONST(4.733354568481445), + REAL_CONST(6.022367954254150), REAL_CONST(6.692092418670654), REAL_CONST(6.924463272094727), REAL_CONST(6.989034175872803), REAL_CONST(7.005646705627441), REAL_CONST(7.009829998016357), + REAL_CONST(7.010877609252930)}, + {REAL_CONST(0.022362394258380), REAL_CONST(0.087379962205887), REAL_CONST(0.320804953575134), REAL_CONST(0.988859415054321), REAL_CONST(2.252387046813965), REAL_CONST(3.786596298217773), + REAL_CONST(5.044394016265869), REAL_CONST(5.705977916717529), REAL_CONST(5.936291694641113), REAL_CONST(6.000346660614014), REAL_CONST(6.016829967498779), REAL_CONST(6.020981311798096), + REAL_CONST(6.022020816802979)}, + {REAL_CONST(0.011224525049329), REAL_CONST(0.044351425021887), REAL_CONST(0.169301137328148), REAL_CONST(0.577544987201691), REAL_CONST(1.527246952056885), REAL_CONST(2.887525320053101), + REAL_CONST(4.087462902069092), REAL_CONST(4.733354568481445), REAL_CONST(4.959661006927490), REAL_CONST(5.022709369659424), REAL_CONST(5.038940429687500), REAL_CONST(5.043028831481934), + REAL_CONST(5.044052600860596)}, + {REAL_CONST(0.005623178556561), REAL_CONST(0.022346137091517), REAL_CONST(0.087132595479488), REAL_CONST(0.317482173442841), REAL_CONST(0.956931233406067), REAL_CONST(2.070389270782471), + REAL_CONST(3.169924974441528), REAL_CONST(3.786596298217773), REAL_CONST(4.005294322967529), REAL_CONST(4.066420555114746), REAL_CONST(4.082170009613037), REAL_CONST(4.086137294769287), + REAL_CONST(4.087131500244141)}, + {REAL_CONST(0.002814328996465), REAL_CONST(0.011216334067285), REAL_CONST(0.044224001467228), REAL_CONST(0.167456731200218), REAL_CONST(0.556393325328827), REAL_CONST(1.378511548042297), + REAL_CONST(2.321928024291992), REAL_CONST(2.887525320053101), REAL_CONST(3.092446088790894), REAL_CONST(3.150059700012207), REAL_CONST(3.164926528930664), REAL_CONST(3.168673276901245), + REAL_CONST(3.169611930847168)}, + {REAL_CONST(0.001407850766554), REAL_CONST(0.005619067233056), REAL_CONST(0.022281449288130), REAL_CONST(0.086156636476517), REAL_CONST(0.304854571819305), REAL_CONST(0.847996890544891), + REAL_CONST(1.584962487220764), REAL_CONST(2.070389270782471), REAL_CONST(2.252387046813965), REAL_CONST(2.304061651229858), REAL_CONST(2.317430257797241), REAL_CONST(2.320801734924316), + REAL_CONST(2.321646213531494)}, + {REAL_CONST(0.000704097095877), REAL_CONST(0.002812269143760), REAL_CONST(0.011183738708496), REAL_CONST(0.043721374124289), REAL_CONST(0.160464659333229), REAL_CONST(0.485426813364029), + REAL_CONST(1.000000000000000), REAL_CONST(1.378511548042297), REAL_CONST(1.527246952056885), REAL_CONST(1.570089221000671), REAL_CONST(1.581215262413025), REAL_CONST(1.584023833274841), + REAL_CONST(1.584727644920349)}, + {REAL_CONST(0.000352177477907), REAL_CONST(0.001406819908880), REAL_CONST(0.005602621007711), REAL_CONST(0.022026389837265), REAL_CONST(0.082462236285210), REAL_CONST(0.263034462928772), + REAL_CONST(0.584962487220764), REAL_CONST(0.847996890544891), REAL_CONST(0.956931233406067), REAL_CONST(0.988859415054321), REAL_CONST(0.997190535068512), REAL_CONST(0.999296069145203), + REAL_CONST(0.999823868274689)}, + {REAL_CONST(0.000176099492819), REAL_CONST(0.000703581434209), REAL_CONST(0.002804030198604), REAL_CONST(0.011055230163038), REAL_CONST(0.041820213198662), REAL_CONST(0.137503549456596), + REAL_CONST(0.321928083896637), REAL_CONST(0.485426813364029), REAL_CONST(0.556393325328827), REAL_CONST(0.577544987201691), REAL_CONST(0.583090126514435), REAL_CONST(0.584493279457092), + REAL_CONST(0.584845066070557)}, + {REAL_CONST(0.000088052431238), REAL_CONST(0.000351833587047), REAL_CONST(0.001402696361765), REAL_CONST(0.005538204684854), REAL_CONST(0.021061634644866), REAL_CONST(0.070389263331890), + REAL_CONST(0.169925004243851), REAL_CONST(0.263034462928772), REAL_CONST(0.304854571819305), REAL_CONST(0.317482173442841), REAL_CONST(0.320804953575134), REAL_CONST(0.321646571159363), + REAL_CONST(0.321857661008835)}, + {REAL_CONST(0.000044026888645), REAL_CONST(0.000175927518285), REAL_CONST(0.000701518612914), REAL_CONST(0.002771759871393), REAL_CONST(0.010569252073765), REAL_CONST(0.035623874515295), + REAL_CONST(0.087462842464447), REAL_CONST(0.137503549456596), REAL_CONST(0.160464659333229), REAL_CONST(0.167456731200218), REAL_CONST(0.169301137328148), REAL_CONST(0.169768601655960), + REAL_CONST(0.169885858893394)}, + {REAL_CONST(0.000022013611670), REAL_CONST(0.000088052431238), REAL_CONST(0.000350801943569), REAL_CONST(0.001386545598507), REAL_CONST(0.005294219125062), REAL_CONST(0.017921976745129), + REAL_CONST(0.044394120573997), REAL_CONST(0.070389263331890), REAL_CONST(0.082462236285210), REAL_CONST(0.086156636476517), REAL_CONST(0.087132595479488), REAL_CONST(0.087379962205887), + REAL_CONST(0.087442122399807)}, + {REAL_CONST(0.000011006847672), REAL_CONST(0.000044026888645), REAL_CONST(0.000175411638338), REAL_CONST(0.000693439331371), REAL_CONST(0.002649537986144), REAL_CONST(0.008988817222416), + REAL_CONST(0.022367812693119), REAL_CONST(0.035623874515295), REAL_CONST(0.041820213198662), REAL_CONST(0.043721374124289), REAL_CONST(0.044224001467228), REAL_CONST(0.044351425021887), + REAL_CONST(0.044383447617292)}, + {REAL_CONST(0.000005503434295), REAL_CONST(0.000022013611670), REAL_CONST(0.000087708482170), REAL_CONST(0.000346675369656), REAL_CONST(0.001325377263129), REAL_CONST(0.004501323681325), + REAL_CONST(0.011227255687118), REAL_CONST(0.017921976745129), REAL_CONST(0.021061634644866), REAL_CONST(0.022026389837265), REAL_CONST(0.022281449288130), REAL_CONST(0.022346137091517), + REAL_CONST(0.022362394258380)}, + {REAL_CONST(0.000002751719876), REAL_CONST(0.000011006847672), REAL_CONST(0.000043854910473), REAL_CONST(0.000173348103999), REAL_CONST(0.000662840844598), REAL_CONST(0.002252417383716), + REAL_CONST(0.005624548997730), REAL_CONST(0.008988817222416), REAL_CONST(0.010569252073765), REAL_CONST(0.011055230163038), REAL_CONST(0.011183738708496), REAL_CONST(0.011216334067285), + REAL_CONST(0.011224525049329)}, + {REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000022013611670), REAL_CONST(0.000086676649516), REAL_CONST(0.000331544462824), REAL_CONST(0.001126734190620), + REAL_CONST(0.002815015614033), REAL_CONST(0.004501323681325), REAL_CONST(0.005294219125062), REAL_CONST(0.005538204684854), REAL_CONST(0.005602621007711), REAL_CONST(0.005619067233056), + REAL_CONST(0.005623178556561)}, + {REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000011006847672), REAL_CONST(0.000043338975956), REAL_CONST(0.000165781748365), REAL_CONST(0.000563477107789), + REAL_CONST(0.001408194424585), REAL_CONST(0.002252417383716), REAL_CONST(0.002649537986144), REAL_CONST(0.002771759871393), REAL_CONST(0.002804030198604), REAL_CONST(0.002812269143760), + REAL_CONST(0.002814328996465)}, + {REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000021669651687), REAL_CONST(0.000082893253420), REAL_CONST(0.000281680084299), + REAL_CONST(0.000704268983100), REAL_CONST(0.001126734190620), REAL_CONST(0.001325377263129), REAL_CONST(0.001386545598507), REAL_CONST(0.001402696361765), REAL_CONST(0.001406819908880), + REAL_CONST(0.001407850766554)}, + {REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000010834866771), REAL_CONST(0.000041447223339), REAL_CONST(0.000140846910654), + REAL_CONST(0.000352177477907), REAL_CONST(0.000563477107789), REAL_CONST(0.000662840844598), REAL_CONST(0.000693439331371), REAL_CONST(0.000701518612914), REAL_CONST(0.000703581434209), + REAL_CONST(0.000704097095877)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000020637769921), REAL_CONST(0.000070511166996), + REAL_CONST(0.000176099492819), REAL_CONST(0.000281680084299), REAL_CONST(0.000331544462824), REAL_CONST(0.000346675369656), REAL_CONST(0.000350801943569), REAL_CONST(0.000351833587047), + REAL_CONST(0.000352177477907)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000010318922250), REAL_CONST(0.000035256012779), + REAL_CONST(0.000088052431238), REAL_CONST(0.000140846910654), REAL_CONST(0.000165781748365), REAL_CONST(0.000173348103999), REAL_CONST(0.000175411638338), REAL_CONST(0.000175927518285), + REAL_CONST(0.000176099492819)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005159470220), REAL_CONST(0.000017542124624), + REAL_CONST(0.000044026888645), REAL_CONST(0.000070511166996), REAL_CONST(0.000082893253420), REAL_CONST(0.000086676649516), REAL_CONST(0.000087708482170), REAL_CONST(0.000088052431238), + REAL_CONST(0.000088052431238)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002579737384), REAL_CONST(0.000008771088687), + REAL_CONST(0.000022013611670), REAL_CONST(0.000035256012779), REAL_CONST(0.000041447223339), REAL_CONST(0.000043338975956), REAL_CONST(0.000043854910473), REAL_CONST(0.000044026888645), + REAL_CONST(0.000044026888645)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000004471542070), + REAL_CONST(0.000011006847672), REAL_CONST(0.000017542124624), REAL_CONST(0.000020637769921), REAL_CONST(0.000021669651687), REAL_CONST(0.000022013611670), REAL_CONST(0.000022013611670), + REAL_CONST(0.000022013611670)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002235772627), + REAL_CONST(0.000005503434295), REAL_CONST(0.000008771088687), REAL_CONST(0.000010318922250), REAL_CONST(0.000010834866771), REAL_CONST(0.000011006847672), REAL_CONST(0.000011006847672), + REAL_CONST(0.000011006847672)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001031895522), + REAL_CONST(0.000002751719876), REAL_CONST(0.000004471542070), REAL_CONST(0.000005159470220), REAL_CONST(0.000005503434295), REAL_CONST(0.000005503434295), REAL_CONST(0.000005503434295), + REAL_CONST(0.000005503434295)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000515947875), + REAL_CONST(0.000001375860506), REAL_CONST(0.000002235772627), REAL_CONST(0.000002579737384), REAL_CONST(0.000002751719876), REAL_CONST(0.000002751719876), REAL_CONST(0.000002751719876), + REAL_CONST(0.000002751719876)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), + REAL_CONST(0.000000687930424), REAL_CONST(0.000001031895522), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), + REAL_CONST(0.000001375860506)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), + REAL_CONST(0.000000343965269), REAL_CONST(0.000000515947875), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), + REAL_CONST(0.000000687930424)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), + REAL_CONST(0.000000171982634), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), + REAL_CONST(0.000000343965269)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), + REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), + REAL_CONST(0.000000171982634)}}; + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.A.13 Noise table V */ +static const complex_t V[] = { + {FRAC_CONST(-0.99948155879974), FRAC_CONST(-0.59483414888382)}, {FRAC_CONST(0.97113454341888), FRAC_CONST(-0.67528516054153)}, {FRAC_CONST(0.14130051434040), FRAC_CONST(-0.95090985298157)}, + {FRAC_CONST(-0.47005495429039), FRAC_CONST(-0.37340548634529)}, {FRAC_CONST(0.80705064535141), FRAC_CONST(0.29653668403625)}, {FRAC_CONST(-0.38981479406357), FRAC_CONST(0.89572608470917)}, + {FRAC_CONST(-0.01053049881011), FRAC_CONST(-0.66959059238434)}, {FRAC_CONST(-0.91266369819641), FRAC_CONST(-0.11522938311100)}, {FRAC_CONST(0.54840421676636), FRAC_CONST(0.75221365690231)}, + {FRAC_CONST(0.40009254217148), FRAC_CONST(-0.98929399251938)}, {FRAC_CONST(-0.99867975711823), FRAC_CONST(-0.88147068023682)}, {FRAC_CONST(-0.95531076192856), FRAC_CONST(0.90908759832382)}, + {FRAC_CONST(-0.45725932717323), FRAC_CONST(-0.56716322898865)}, {FRAC_CONST(-0.72929674386978), FRAC_CONST(-0.98008275032043)}, {FRAC_CONST(0.75622802972794), FRAC_CONST(0.20950329303741)}, + {FRAC_CONST(0.07069442421198), FRAC_CONST(-0.78247898817062)}, {FRAC_CONST(0.74496251344681), FRAC_CONST(-0.91169005632401)}, {FRAC_CONST(-0.96440184116364), FRAC_CONST(-0.94739919900894)}, + {FRAC_CONST(0.30424630641937), FRAC_CONST(-0.49438267946243)}, {FRAC_CONST(0.66565030813217), FRAC_CONST(0.64652937650681)}, {FRAC_CONST(0.91697007417679), FRAC_CONST(0.17514097690582)}, + {FRAC_CONST(-0.70774918794632), FRAC_CONST(0.52548652887344)}, {FRAC_CONST(-0.70051413774490), FRAC_CONST(-0.45340028405190)}, {FRAC_CONST(-0.99496513605118), FRAC_CONST(-0.90071910619736)}, + {FRAC_CONST(0.98164492845535), FRAC_CONST(-0.77463155984879)}, {FRAC_CONST(-0.54671579599380), FRAC_CONST(-0.02570928446949)}, {FRAC_CONST(-0.01689629070461), FRAC_CONST(0.00287506449968)}, + {FRAC_CONST(-0.86110347509384), FRAC_CONST(0.42548584938049)}, {FRAC_CONST(-0.98892980813980), FRAC_CONST(-0.87881129980087)}, {FRAC_CONST(0.51756626367569), FRAC_CONST(0.66926783323288)}, + {FRAC_CONST(-0.99635028839111), FRAC_CONST(-0.58107727766037)}, {FRAC_CONST(-0.99969369173050), FRAC_CONST(0.98369991779327)}, {FRAC_CONST(0.55266261100769), FRAC_CONST(0.59449058771133)}, + {FRAC_CONST(0.34581178426743), FRAC_CONST(0.94879418611526)}, {FRAC_CONST(0.62664210796356), FRAC_CONST(-0.74402970075607)}, {FRAC_CONST(-0.77149701118469), FRAC_CONST(-0.33883658051491)}, + {FRAC_CONST(-0.91592246294022), FRAC_CONST(0.03687901422381)}, {FRAC_CONST(-0.76285493373871), FRAC_CONST(-0.91371870040894)}, {FRAC_CONST(0.79788339138031), FRAC_CONST(-0.93180972337723)}, + {FRAC_CONST(0.54473078250885), FRAC_CONST(-0.11919206380844)}, {FRAC_CONST(-0.85639280080795), FRAC_CONST(0.42429855465889)}, {FRAC_CONST(-0.92882400751114), FRAC_CONST(0.27871808409691)}, + {FRAC_CONST(-0.11708371341228), FRAC_CONST(-0.99800843000412)}, {FRAC_CONST(0.21356749534607), FRAC_CONST(-0.90716296434402)}, {FRAC_CONST(-0.76191693544388), FRAC_CONST(0.99768120050430)}, + {FRAC_CONST(0.98111045360565), FRAC_CONST(-0.95854461193085)}, {FRAC_CONST(-0.85913270711899), FRAC_CONST(0.95766568183899)}, {FRAC_CONST(-0.93307244777679), FRAC_CONST(0.49431759119034)}, + {FRAC_CONST(0.30485755205154), FRAC_CONST(-0.70540034770966)}, {FRAC_CONST(0.85289651155472), FRAC_CONST(0.46766132116318)}, {FRAC_CONST(0.91328084468842), FRAC_CONST(-0.99839597940445)}, + {FRAC_CONST(-0.05890199914575), FRAC_CONST(0.70741826295853)}, {FRAC_CONST(0.28398686647415), FRAC_CONST(0.34633556008339)}, {FRAC_CONST(0.95258164405823), FRAC_CONST(-0.54893416166306)}, + {FRAC_CONST(-0.78566324710846), FRAC_CONST(-0.75568538904190)}, {FRAC_CONST(-0.95789498090744), FRAC_CONST(-0.20423194766045)}, {FRAC_CONST(0.82411158084869), FRAC_CONST(0.96654617786407)}, + {FRAC_CONST(-0.65185445547104), FRAC_CONST(-0.88734990358353)}, {FRAC_CONST(-0.93643605709076), FRAC_CONST(0.99870789051056)}, {FRAC_CONST(0.91427159309387), FRAC_CONST(-0.98290503025055)}, + {FRAC_CONST(-0.70395684242249), FRAC_CONST(0.58796799182892)}, {FRAC_CONST(0.00563771976158), FRAC_CONST(0.61768198013306)}, {FRAC_CONST(0.89065051078796), FRAC_CONST(0.52783352136612)}, + {FRAC_CONST(-0.68683707714081), FRAC_CONST(0.80806946754456)}, {FRAC_CONST(0.72165340185165), FRAC_CONST(-0.69259858131409)}, {FRAC_CONST(-0.62928247451782), FRAC_CONST(0.13627037405968)}, + {FRAC_CONST(0.29938435554504), FRAC_CONST(-0.46051329374313)}, {FRAC_CONST(-0.91781955957413), FRAC_CONST(-0.74012714624405)}, {FRAC_CONST(0.99298715591431), FRAC_CONST(0.40816611051559)}, + {FRAC_CONST(0.82368296384811), FRAC_CONST(-0.74036049842834)}, {FRAC_CONST(-0.98512834310532), FRAC_CONST(-0.99972331523895)}, {FRAC_CONST(-0.95915371179581), FRAC_CONST(-0.99237799644470)}, + {FRAC_CONST(-0.21411126852036), FRAC_CONST(-0.93424820899963)}, {FRAC_CONST(-0.68821477890015), FRAC_CONST(-0.26892307400703)}, {FRAC_CONST(0.91851997375488), FRAC_CONST(0.09358228743076)}, + {FRAC_CONST(-0.96062767505646), FRAC_CONST(0.36099094152451)}, {FRAC_CONST(0.51646184921265), FRAC_CONST(-0.71373331546783)}, {FRAC_CONST(0.61130720376968), FRAC_CONST(0.46950140595436)}, + {FRAC_CONST(0.47336128354073), FRAC_CONST(-0.27333179116249)}, {FRAC_CONST(0.90998309850693), FRAC_CONST(0.96715664863586)}, {FRAC_CONST(0.44844800233841), FRAC_CONST(0.99211573600769)}, + {FRAC_CONST(0.66614890098572), FRAC_CONST(0.96590173244476)}, {FRAC_CONST(0.74922239780426), FRAC_CONST(-0.89879858493805)}, {FRAC_CONST(-0.99571585655212), FRAC_CONST(0.52785521745682)}, + {FRAC_CONST(0.97401082515717), FRAC_CONST(-0.16855870187283)}, {FRAC_CONST(0.72683745622635), FRAC_CONST(-0.48060774803162)}, {FRAC_CONST(0.95432192087173), FRAC_CONST(0.68849605321884)}, + {FRAC_CONST(-0.72962206602097), FRAC_CONST(-0.76608443260193)}, {FRAC_CONST(-0.85359477996826), FRAC_CONST(0.88738125562668)}, {FRAC_CONST(-0.81412428617477), FRAC_CONST(-0.97480767965317)}, + {FRAC_CONST(-0.87930774688721), FRAC_CONST(0.74748307466507)}, {FRAC_CONST(-0.71573328971863), FRAC_CONST(-0.98570609092712)}, {FRAC_CONST(0.83524298667908), FRAC_CONST(0.83702534437180)}, + {FRAC_CONST(-0.48086065053940), FRAC_CONST(-0.98848503828049)}, {FRAC_CONST(0.97139126062393), FRAC_CONST(0.80093622207642)}, {FRAC_CONST(0.51992827653885), FRAC_CONST(0.80247628688812)}, + {FRAC_CONST(-0.00848591234535), FRAC_CONST(-0.76670128107071)}, {FRAC_CONST(-0.70294374227524), FRAC_CONST(0.55359911918640)}, {FRAC_CONST(-0.95894426107407), FRAC_CONST(-0.43265503644943)}, + {FRAC_CONST(0.97079253196716), FRAC_CONST(0.09325857460499)}, {FRAC_CONST(-0.92404294013977), FRAC_CONST(0.85507702827454)}, {FRAC_CONST(-0.69506472349167), FRAC_CONST(0.98633414506912)}, + {FRAC_CONST(0.26559203863144), FRAC_CONST(0.73314309120178)}, {FRAC_CONST(0.28038442134857), FRAC_CONST(0.14537914097309)}, {FRAC_CONST(-0.74138122797012), FRAC_CONST(0.99310338497162)}, + {FRAC_CONST(-0.01752796024084), FRAC_CONST(-0.82616633176804)}, {FRAC_CONST(-0.55126774311066), FRAC_CONST(-0.98898541927338)}, {FRAC_CONST(0.97960901260376), FRAC_CONST(-0.94021445512772)}, + {FRAC_CONST(-0.99196308851242), FRAC_CONST(0.67019015550613)}, {FRAC_CONST(-0.67684930562973), FRAC_CONST(0.12631492316723)}, {FRAC_CONST(0.09140039235353), FRAC_CONST(-0.20537731051445)}, + {FRAC_CONST(-0.71658962965012), FRAC_CONST(-0.97788202762604)}, {FRAC_CONST(0.81014639139175), FRAC_CONST(0.53722649812698)}, {FRAC_CONST(0.40616992115974), FRAC_CONST(-0.26469007134438)}, + {FRAC_CONST(-0.67680186033249), FRAC_CONST(0.94502049684525)}, {FRAC_CONST(0.86849772930145), FRAC_CONST(-0.18333598971367)}, {FRAC_CONST(-0.99500381946564), FRAC_CONST(-0.02634122036397)}, + {FRAC_CONST(0.84329187870026), FRAC_CONST(0.10406957566738)}, {FRAC_CONST(-0.09215968847275), FRAC_CONST(0.69540011882782)}, {FRAC_CONST(0.99956172704697), FRAC_CONST(-0.12358541786671)}, + {FRAC_CONST(-0.79732781648636), FRAC_CONST(-0.91582524776459)}, {FRAC_CONST(0.96349972486496), FRAC_CONST(0.96640455722809)}, {FRAC_CONST(-0.79942780733109), FRAC_CONST(0.64323902130127)}, + {FRAC_CONST(-0.11566039919853), FRAC_CONST(0.28587844967842)}, {FRAC_CONST(-0.39922955632210), FRAC_CONST(0.94129604101181)}, {FRAC_CONST(0.99089199304581), FRAC_CONST(-0.92062628269196)}, + {FRAC_CONST(0.28631284832954), FRAC_CONST(-0.91035044193268)}, {FRAC_CONST(-0.83302724361420), FRAC_CONST(-0.67330408096313)}, {FRAC_CONST(0.95404446125031), FRAC_CONST(0.49162766337395)}, + {FRAC_CONST(-0.06449863314629), FRAC_CONST(0.03250560909510)}, {FRAC_CONST(-0.99575054645538), FRAC_CONST(0.42389783263206)}, {FRAC_CONST(-0.65501141548157), FRAC_CONST(0.82546114921570)}, + {FRAC_CONST(-0.81254440546036), FRAC_CONST(-0.51627236604691)}, {FRAC_CONST(-0.99646371603012), FRAC_CONST(0.84490531682968)}, {FRAC_CONST(0.00287840608507), FRAC_CONST(0.64768260717392)}, + {FRAC_CONST(0.70176988840103), FRAC_CONST(-0.20453028380871)}, {FRAC_CONST(0.96361881494522), FRAC_CONST(0.40706968307495)}, {FRAC_CONST(-0.68883758783340), FRAC_CONST(0.91338956356049)}, + {FRAC_CONST(-0.34875586628914), FRAC_CONST(0.71472293138504)}, {FRAC_CONST(0.91980081796646), FRAC_CONST(0.66507452726364)}, {FRAC_CONST(-0.99009048938751), FRAC_CONST(0.85868018865585)}, + {FRAC_CONST(0.68865793943405), FRAC_CONST(0.55660319328308)}, {FRAC_CONST(-0.99484401941299), FRAC_CONST(-0.20052559673786)}, {FRAC_CONST(0.94214510917664), FRAC_CONST(-0.99696427583694)}, + {FRAC_CONST(-0.67414629459381), FRAC_CONST(0.49548220634460)}, {FRAC_CONST(-0.47339352965355), FRAC_CONST(-0.85904330015182)}, {FRAC_CONST(0.14323651790619), FRAC_CONST(-0.94145596027374)}, + {FRAC_CONST(-0.29268294572830), FRAC_CONST(0.05759225040674)}, {FRAC_CONST(0.43793860077858), FRAC_CONST(-0.78904968500137)}, {FRAC_CONST(-0.36345127224922), FRAC_CONST(0.64874434471130)}, + {FRAC_CONST(-0.08750604838133), FRAC_CONST(0.97686946392059)}, {FRAC_CONST(-0.96495270729065), FRAC_CONST(-0.53960305452347)}, {FRAC_CONST(0.55526942014694), FRAC_CONST(0.78891521692276)}, + {FRAC_CONST(0.73538213968277), FRAC_CONST(0.96452075242996)}, {FRAC_CONST(-0.30889773368835), FRAC_CONST(-0.80664390325546)}, {FRAC_CONST(0.03574995696545), FRAC_CONST(-0.97325617074966)}, + {FRAC_CONST(0.98720687627792), FRAC_CONST(0.48409134149551)}, {FRAC_CONST(-0.81689298152924), FRAC_CONST(-0.90827703475952)}, {FRAC_CONST(0.67866861820221), FRAC_CONST(0.81284505128860)}, + {FRAC_CONST(-0.15808570384979), FRAC_CONST(0.85279554128647)}, {FRAC_CONST(0.80723392963409), FRAC_CONST(-0.24717418849468)}, {FRAC_CONST(0.47788757085800), FRAC_CONST(-0.46333149075508)}, + {FRAC_CONST(0.96367555856705), FRAC_CONST(0.38486748933792)}, {FRAC_CONST(-0.99143874645233), FRAC_CONST(-0.24945276975632)}, {FRAC_CONST(0.83081877231598), FRAC_CONST(-0.94780850410461)}, + {FRAC_CONST(-0.58753192424774), FRAC_CONST(0.01290772389621)}, {FRAC_CONST(0.95538109540939), FRAC_CONST(-0.85557049512863)}, {FRAC_CONST(-0.96490919589996), FRAC_CONST(-0.64020973443985)}, + {FRAC_CONST(-0.97327101230621), FRAC_CONST(0.12378127872944)}, {FRAC_CONST(0.91400367021561), FRAC_CONST(0.57972472906113)}, {FRAC_CONST(-0.99925839900970), FRAC_CONST(0.71084845066071)}, + {FRAC_CONST(-0.86875903606415), FRAC_CONST(-0.20291699469090)}, {FRAC_CONST(-0.26240035891533), FRAC_CONST(-0.68264555931091)}, {FRAC_CONST(-0.24664412438869), FRAC_CONST(-0.87642270326614)}, + {FRAC_CONST(0.02416275814176), FRAC_CONST(0.27192914485931)}, {FRAC_CONST(0.82068622112274), FRAC_CONST(-0.85087788105011)}, {FRAC_CONST(0.88547372817993), FRAC_CONST(-0.89636802673340)}, + {FRAC_CONST(-0.18173077702522), FRAC_CONST(-0.26152145862579)}, {FRAC_CONST(0.09355476498604), FRAC_CONST(0.54845124483109)}, {FRAC_CONST(-0.54668414592743), FRAC_CONST(0.95980775356293)}, + {FRAC_CONST(0.37050989270210), FRAC_CONST(-0.59910142421722)}, {FRAC_CONST(-0.70373594760895), FRAC_CONST(0.91227668523788)}, {FRAC_CONST(-0.34600785374641), FRAC_CONST(-0.99441426992416)}, + {FRAC_CONST(-0.68774479627609), FRAC_CONST(-0.30238837003708)}, {FRAC_CONST(-0.26843291521072), FRAC_CONST(0.83115667104721)}, {FRAC_CONST(0.49072334170341), FRAC_CONST(-0.45359709858894)}, + {FRAC_CONST(0.38975992798805), FRAC_CONST(0.95515358448029)}, {FRAC_CONST(-0.97757124900818), FRAC_CONST(0.05305894464254)}, {FRAC_CONST(-0.17325553297997), FRAC_CONST(-0.92770671844482)}, + {FRAC_CONST(0.99948036670685), FRAC_CONST(0.58285546302795)}, {FRAC_CONST(-0.64946246147156), FRAC_CONST(0.68645507097244)}, {FRAC_CONST(-0.12016920745373), FRAC_CONST(-0.57147324085236)}, + {FRAC_CONST(-0.58947455883026), FRAC_CONST(-0.34847131371498)}, {FRAC_CONST(-0.41815140843391), FRAC_CONST(0.16276422142982)}, {FRAC_CONST(0.99885648488998), FRAC_CONST(0.11136095225811)}, + {FRAC_CONST(-0.56649613380432), FRAC_CONST(-0.90494865179062)}, {FRAC_CONST(0.94138020277023), FRAC_CONST(0.35281917452812)}, {FRAC_CONST(-0.75725078582764), FRAC_CONST(0.53650552034378)}, + {FRAC_CONST(0.20541973412037), FRAC_CONST(-0.94435143470764)}, {FRAC_CONST(0.99980372190475), FRAC_CONST(0.79835915565491)}, {FRAC_CONST(0.29078277945518), FRAC_CONST(0.35393777489662)}, + {FRAC_CONST(-0.62858772277832), FRAC_CONST(0.38765692710876)}, {FRAC_CONST(0.43440905213356), FRAC_CONST(-0.98546332120895)}, {FRAC_CONST(-0.98298585414886), FRAC_CONST(0.21021524071693)}, + {FRAC_CONST(0.19513028860092), FRAC_CONST(-0.94239830970764)}, {FRAC_CONST(-0.95476663112640), FRAC_CONST(0.98364555835724)}, {FRAC_CONST(0.93379634618759), FRAC_CONST(-0.70881992578506)}, + {FRAC_CONST(-0.85235410928726), FRAC_CONST(-0.08342348039150)}, {FRAC_CONST(-0.86425095796585), FRAC_CONST(-0.45795026421547)}, {FRAC_CONST(0.38879778981209), FRAC_CONST(0.97274428606033)}, + {FRAC_CONST(0.92045122385025), FRAC_CONST(-0.62433654069901)}, {FRAC_CONST(0.89162534475327), FRAC_CONST(0.54950958490372)}, {FRAC_CONST(-0.36834338307381), FRAC_CONST(0.96458297967911)}, + {FRAC_CONST(0.93891763687134), FRAC_CONST(-0.89968353509903)}, {FRAC_CONST(0.99267655611038), FRAC_CONST(-0.03757034242153)}, {FRAC_CONST(-0.94063472747803), FRAC_CONST(0.41332337260246)}, + {FRAC_CONST(0.99740225076675), FRAC_CONST(-0.16830494999886)}, {FRAC_CONST(-0.35899412631989), FRAC_CONST(-0.46633225679398)}, {FRAC_CONST(0.05237237364054), FRAC_CONST(-0.25640362501144)}, + {FRAC_CONST(0.36703583598137), FRAC_CONST(-0.38653266429901)}, {FRAC_CONST(0.91653180122375), FRAC_CONST(-0.30587628483772)}, {FRAC_CONST(0.69000804424286), FRAC_CONST(0.90952169895172)}, + {FRAC_CONST(-0.38658750057220), FRAC_CONST(0.99501574039459)}, {FRAC_CONST(-0.29250815510750), FRAC_CONST(0.37444993853569)}, {FRAC_CONST(-0.60182201862335), FRAC_CONST(0.86779648065567)}, + {FRAC_CONST(-0.97418588399887), FRAC_CONST(0.96468526124954)}, {FRAC_CONST(0.88461571931839), FRAC_CONST(0.57508403062820)}, {FRAC_CONST(0.05198933184147), FRAC_CONST(0.21269661188126)}, + {FRAC_CONST(-0.53499621152878), FRAC_CONST(0.97241556644440)}, {FRAC_CONST(-0.49429559707642), FRAC_CONST(0.98183864355087)}, {FRAC_CONST(-0.98935145139694), FRAC_CONST(-0.40249159932137)}, + {FRAC_CONST(-0.98081380128860), FRAC_CONST(-0.72856897115707)}, {FRAC_CONST(-0.27338150143623), FRAC_CONST(0.99950921535492)}, {FRAC_CONST(0.06310802698135), FRAC_CONST(-0.54539585113525)}, + {FRAC_CONST(-0.20461677014828), FRAC_CONST(-0.14209978282452)}, {FRAC_CONST(0.66223841905594), FRAC_CONST(0.72528582811356)}, {FRAC_CONST(-0.84764343500137), FRAC_CONST(0.02372316829860)}, + {FRAC_CONST(-0.89039862155914), FRAC_CONST(0.88866579532623)}, {FRAC_CONST(0.95903307199478), FRAC_CONST(0.76744925975800)}, {FRAC_CONST(0.73504126071930), FRAC_CONST(-0.03747203201056)}, + {FRAC_CONST(-0.31744435429573), FRAC_CONST(-0.36834111809731)}, {FRAC_CONST(-0.34110826253891), FRAC_CONST(0.40211221575737)}, {FRAC_CONST(0.47803884744644), FRAC_CONST(-0.39423218369484)}, + {FRAC_CONST(0.98299193382263), FRAC_CONST(0.01989791356027)}, {FRAC_CONST(-0.30963072180748), FRAC_CONST(-0.18076720833778)}, {FRAC_CONST(0.99992591142654), FRAC_CONST(-0.26281872391701)}, + {FRAC_CONST(-0.93149733543396), FRAC_CONST(-0.98313164710999)}, {FRAC_CONST(0.99923473596573), FRAC_CONST(-0.80142992734909)}, {FRAC_CONST(-0.26024168729782), FRAC_CONST(-0.75999760627747)}, + {FRAC_CONST(-0.35712513327599), FRAC_CONST(0.19298963248730)}, {FRAC_CONST(-0.99899083375931), FRAC_CONST(0.74645155668259)}, {FRAC_CONST(0.86557173728943), FRAC_CONST(0.55593866109848)}, + {FRAC_CONST(0.33408042788506), FRAC_CONST(0.86185956001282)}, {FRAC_CONST(0.99010735750198), FRAC_CONST(0.04602397605777)}, {FRAC_CONST(-0.66694271564484), FRAC_CONST(-0.91643613576889)}, + {FRAC_CONST(0.64016789197922), FRAC_CONST(0.15649530291557)}, {FRAC_CONST(0.99570536613464), FRAC_CONST(0.45844584703445)}, {FRAC_CONST(-0.63431465625763), FRAC_CONST(0.21079117059708)}, + {FRAC_CONST(-0.07706847041845), FRAC_CONST(-0.89581435918808)}, {FRAC_CONST(0.98590087890625), FRAC_CONST(0.88241720199585)}, {FRAC_CONST(0.80099332332611), FRAC_CONST(-0.36851897835732)}, + {FRAC_CONST(0.78368133306503), FRAC_CONST(0.45506998896599)}, {FRAC_CONST(0.08707806468010), FRAC_CONST(0.80938994884491)}, {FRAC_CONST(-0.86811882257462), FRAC_CONST(0.39347308874130)}, + {FRAC_CONST(-0.39466530084610), FRAC_CONST(-0.66809433698654)}, {FRAC_CONST(0.97875326871872), FRAC_CONST(-0.72467839717865)}, {FRAC_CONST(-0.95038563013077), FRAC_CONST(0.89563220739365)}, + {FRAC_CONST(0.17005239427090), FRAC_CONST(0.54683053493500)}, {FRAC_CONST(-0.76910793781281), FRAC_CONST(-0.96226614713669)}, {FRAC_CONST(0.99743282794952), FRAC_CONST(0.42697158455849)}, + {FRAC_CONST(0.95437383651733), FRAC_CONST(0.97002321481705)}, {FRAC_CONST(0.99578905105591), FRAC_CONST(-0.54106825590134)}, {FRAC_CONST(0.28058260679245), FRAC_CONST(-0.85361421108246)}, + {FRAC_CONST(0.85256522893906), FRAC_CONST(-0.64567607641220)}, {FRAC_CONST(-0.50608539581299), FRAC_CONST(-0.65846014022827)}, {FRAC_CONST(-0.97210735082626), FRAC_CONST(-0.23095212876797)}, + {FRAC_CONST(0.95424050092697), FRAC_CONST(-0.99240148067474)}, {FRAC_CONST(-0.96926569938660), FRAC_CONST(0.73775655031204)}, {FRAC_CONST(0.30872163176537), FRAC_CONST(0.41514959931374)}, + {FRAC_CONST(-0.24523839354515), FRAC_CONST(0.63206630945206)}, {FRAC_CONST(-0.33813264966011), FRAC_CONST(-0.38661777973175)}, {FRAC_CONST(-0.05826828256249), FRAC_CONST(-0.06940773874521)}, + {FRAC_CONST(-0.22898460924625), FRAC_CONST(0.97054851055145)}, {FRAC_CONST(-0.18509915471077), FRAC_CONST(0.47565764188766)}, {FRAC_CONST(-0.10488238185644), FRAC_CONST(-0.87769949436188)}, + {FRAC_CONST(-0.71886587142944), FRAC_CONST(0.78030979633331)}, {FRAC_CONST(0.99793875217438), FRAC_CONST(0.90041309595108)}, {FRAC_CONST(0.57563304901123), FRAC_CONST(-0.91034334897995)}, + {FRAC_CONST(0.28909647464752), FRAC_CONST(0.96307784318924)}, {FRAC_CONST(0.42188999056816), FRAC_CONST(0.48148649930954)}, {FRAC_CONST(0.93335050344467), FRAC_CONST(-0.43537023663521)}, + {FRAC_CONST(-0.97087377309799), FRAC_CONST(0.86636447906494)}, {FRAC_CONST(0.36722871661186), FRAC_CONST(0.65291655063629)}, {FRAC_CONST(-0.81093025207520), FRAC_CONST(0.08778370171785)}, + {FRAC_CONST(-0.26240602135658), FRAC_CONST(-0.92774093151093)}, {FRAC_CONST(0.83996498584747), FRAC_CONST(0.55839848518372)}, {FRAC_CONST(-0.99909615516663), FRAC_CONST(-0.96024608612061)}, + {FRAC_CONST(0.74649465084076), FRAC_CONST(0.12144893407822)}, {FRAC_CONST(-0.74774593114853), FRAC_CONST(-0.26898062229156)}, {FRAC_CONST(0.95781666040421), FRAC_CONST(-0.79047924280167)}, + {FRAC_CONST(0.95472306013107), FRAC_CONST(-0.08588775992393)}, {FRAC_CONST(0.48708331584930), FRAC_CONST(0.99999040365219)}, {FRAC_CONST(0.46332037448883), FRAC_CONST(0.10964126139879)}, + {FRAC_CONST(-0.76497006416321), FRAC_CONST(0.89210927486420)}, {FRAC_CONST(0.57397389411926), FRAC_CONST(0.35289704799652)}, {FRAC_CONST(0.75374317169189), FRAC_CONST(0.96705216169357)}, + {FRAC_CONST(-0.59174400568008), FRAC_CONST(-0.89405369758606)}, {FRAC_CONST(0.75087904930115), FRAC_CONST(-0.29612672328949)}, {FRAC_CONST(-0.98607856035233), FRAC_CONST(0.25034910440445)}, + {FRAC_CONST(-0.40761056542397), FRAC_CONST(-0.90045571327209)}, {FRAC_CONST(0.66929268836975), FRAC_CONST(0.98629492521286)}, {FRAC_CONST(-0.97463697195053), FRAC_CONST(-0.00190223299433)}, + {FRAC_CONST(0.90145510435104), FRAC_CONST(0.99781388044357)}, {FRAC_CONST(-0.87259286642075), FRAC_CONST(0.99233585596085)}, {FRAC_CONST(-0.91529458761215), FRAC_CONST(-0.15698707103729)}, + {FRAC_CONST(-0.03305738791823), FRAC_CONST(-0.37205263972282)}, {FRAC_CONST(0.07223051041365), FRAC_CONST(-0.88805001974106)}, {FRAC_CONST(0.99498009681702), FRAC_CONST(0.97094357013702)}, + {FRAC_CONST(-0.74904936552048), FRAC_CONST(0.99985486268997)}, {FRAC_CONST(0.04585228487849), FRAC_CONST(0.99812334775925)}, {FRAC_CONST(-0.89054954051971), FRAC_CONST(-0.31791913509369)}, + {FRAC_CONST(-0.83782142400742), FRAC_CONST(0.97637635469437)}, {FRAC_CONST(0.33454805612564), FRAC_CONST(-0.86231517791748)}, {FRAC_CONST(-0.99707579612732), FRAC_CONST(0.93237990140915)}, + {FRAC_CONST(-0.22827528417110), FRAC_CONST(0.18874759972095)}, {FRAC_CONST(0.67248046398163), FRAC_CONST(-0.03646211326122)}, {FRAC_CONST(-0.05146538093686), FRAC_CONST(-0.92599701881409)}, + {FRAC_CONST(0.99947297573090), FRAC_CONST(0.93625229597092)}, {FRAC_CONST(0.66951125860214), FRAC_CONST(0.98905825614929)}, {FRAC_CONST(-0.99602955579758), FRAC_CONST(-0.44654715061188)}, + {FRAC_CONST(0.82104903459549), FRAC_CONST(0.99540740251541)}, {FRAC_CONST(0.99186509847641), FRAC_CONST(0.72022998332977)}, {FRAC_CONST(-0.65284591913223), FRAC_CONST(0.52186721563339)}, + {FRAC_CONST(0.93885445594788), FRAC_CONST(-0.74895310401917)}, {FRAC_CONST(0.96735250949860), FRAC_CONST(0.90891814231873)}, {FRAC_CONST(-0.22225968539715), FRAC_CONST(0.57124030590057)}, + {FRAC_CONST(-0.44132784008980), FRAC_CONST(-0.92688840627670)}, {FRAC_CONST(-0.85694974660873), FRAC_CONST(0.88844531774521)}, {FRAC_CONST(0.91783040761948), FRAC_CONST(-0.46356892585754)}, + {FRAC_CONST(0.72556972503662), FRAC_CONST(-0.99899554252625)}, {FRAC_CONST(-0.99711579084396), FRAC_CONST(0.58211559057236)}, {FRAC_CONST(0.77638977766037), FRAC_CONST(0.94321835041046)}, + {FRAC_CONST(0.07717324048281), FRAC_CONST(0.58638399839401)}, {FRAC_CONST(-0.56049829721451), FRAC_CONST(0.82522302865982)}, {FRAC_CONST(0.98398894071579), FRAC_CONST(0.39467439055443)}, + {FRAC_CONST(0.47546947002411), FRAC_CONST(0.68613046407700)}, {FRAC_CONST(0.65675091743469), FRAC_CONST(0.18331636488438)}, {FRAC_CONST(0.03273375332355), FRAC_CONST(-0.74933111667633)}, + {FRAC_CONST(-0.38684144616127), FRAC_CONST(0.51337349414825)}, {FRAC_CONST(-0.97346270084381), FRAC_CONST(-0.96549361944199)}, {FRAC_CONST(-0.53282153606415), FRAC_CONST(-0.91423267126083)}, + {FRAC_CONST(0.99817311763763), FRAC_CONST(0.61133575439453)}, {FRAC_CONST(-0.50254499912262), FRAC_CONST(-0.88829338550568)}, {FRAC_CONST(0.01995873264968), FRAC_CONST(0.85223513841629)}, + {FRAC_CONST(0.99930381774902), FRAC_CONST(0.94578897953033)}, {FRAC_CONST(0.82907766103745), FRAC_CONST(-0.06323442608118)}, {FRAC_CONST(-0.58660709857941), FRAC_CONST(0.96840775012970)}, + {FRAC_CONST(-0.17573736608028), FRAC_CONST(-0.48166921734810)}, {FRAC_CONST(0.83434289693832), FRAC_CONST(-0.13023450970650)}, {FRAC_CONST(0.05946491286159), FRAC_CONST(0.20511047542095)}, + {FRAC_CONST(0.81505483388901), FRAC_CONST(-0.94685947895050)}, {FRAC_CONST(-0.44976380467415), FRAC_CONST(0.40894573926926)}, {FRAC_CONST(-0.89746475219727), FRAC_CONST(0.99846577644348)}, + {FRAC_CONST(0.39677256345749), FRAC_CONST(-0.74854665994644)}, {FRAC_CONST(-0.07588948309422), FRAC_CONST(0.74096214771271)}, {FRAC_CONST(0.76343196630478), FRAC_CONST(0.41746628284454)}, + {FRAC_CONST(-0.74490106105804), FRAC_CONST(0.94725912809372)}, {FRAC_CONST(0.64880120754242), FRAC_CONST(0.41336661577225)}, {FRAC_CONST(0.62319535017014), FRAC_CONST(-0.93098312616348)}, + {FRAC_CONST(0.42215818166733), FRAC_CONST(-0.07712787389755)}, {FRAC_CONST(0.02704554051161), FRAC_CONST(-0.05417517945170)}, {FRAC_CONST(0.80001771450043), FRAC_CONST(0.91542196273804)}, + {FRAC_CONST(-0.79351830482483), FRAC_CONST(-0.36208897829056)}, {FRAC_CONST(0.63872361183167), FRAC_CONST(0.08128252625465)}, {FRAC_CONST(0.52890521287918), FRAC_CONST(0.60048872232437)}, + {FRAC_CONST(0.74238550662994), FRAC_CONST(0.04491915181279)}, {FRAC_CONST(0.99096131324768), FRAC_CONST(-0.19451183080673)}, {FRAC_CONST(-0.80412328243256), FRAC_CONST(-0.88513815402985)}, + {FRAC_CONST(-0.64612615108490), FRAC_CONST(0.72198677062988)}, {FRAC_CONST(0.11657770723104), FRAC_CONST(-0.83662831783295)}, {FRAC_CONST(-0.95053184032440), FRAC_CONST(-0.96939903497696)}, + {FRAC_CONST(-0.62228870391846), FRAC_CONST(0.82767260074615)}, {FRAC_CONST(0.03004475869238), FRAC_CONST(-0.99738895893097)}, {FRAC_CONST(-0.97987216711044), FRAC_CONST(0.36526128649712)}, + {FRAC_CONST(-0.99986982345581), FRAC_CONST(-0.36021611094475)}, {FRAC_CONST(0.89110648632050), FRAC_CONST(-0.97894251346588)}, {FRAC_CONST(0.10407960414886), FRAC_CONST(0.77357792854309)}, + {FRAC_CONST(0.95964735746384), FRAC_CONST(-0.35435819625854)}, {FRAC_CONST(0.50843232870102), FRAC_CONST(0.96107691526413)}, {FRAC_CONST(0.17006334662437), FRAC_CONST(-0.76854026317596)}, + {FRAC_CONST(0.25872674584389), FRAC_CONST(0.99893301725388)}, {FRAC_CONST(-0.01115998718888), FRAC_CONST(0.98496019840240)}, {FRAC_CONST(-0.79598701000214), FRAC_CONST(0.97138410806656)}, + {FRAC_CONST(-0.99264711141586), FRAC_CONST(-0.99542820453644)}, {FRAC_CONST(-0.99829661846161), FRAC_CONST(0.01877138763666)}, {FRAC_CONST(-0.70801013708115), FRAC_CONST(0.33680686354637)}, + {FRAC_CONST(-0.70467054843903), FRAC_CONST(0.93272775411606)}, {FRAC_CONST(0.99846023321152), FRAC_CONST(-0.98725748062134)}, {FRAC_CONST(-0.63364970684052), FRAC_CONST(-0.16473594307899)}, + {FRAC_CONST(-0.16258217394352), FRAC_CONST(-0.95939123630524)}, {FRAC_CONST(-0.43645593523979), FRAC_CONST(-0.94805032014847)}, {FRAC_CONST(-0.99848473072052), FRAC_CONST(0.96245169639587)}, + {FRAC_CONST(-0.16796459257603), FRAC_CONST(-0.98987513780594)}, {FRAC_CONST(-0.87979227304459), FRAC_CONST(-0.71725726127625)}, {FRAC_CONST(0.44183099269867), FRAC_CONST(-0.93568974733353)}, + {FRAC_CONST(0.93310177326202), FRAC_CONST(-0.99913311004639)}, {FRAC_CONST(-0.93941932916641), FRAC_CONST(-0.56409376859665)}, {FRAC_CONST(-0.88590002059937), FRAC_CONST(0.47624599933624)}, + {FRAC_CONST(0.99971461296082), FRAC_CONST(-0.83889955282211)}, {FRAC_CONST(-0.75376385450363), FRAC_CONST(0.00814643409103)}, {FRAC_CONST(0.93887686729431), FRAC_CONST(-0.11284527927637)}, + {FRAC_CONST(0.85126435756683), FRAC_CONST(0.52349251508713)}, {FRAC_CONST(0.39701420068741), FRAC_CONST(0.81779634952545)}, {FRAC_CONST(-0.37024465203285), FRAC_CONST(-0.87071657180786)}, + {FRAC_CONST(-0.36024826765060), FRAC_CONST(0.34655734896660)}, {FRAC_CONST(-0.93388813734055), FRAC_CONST(-0.84476542472839)}, {FRAC_CONST(-0.65298801660538), FRAC_CONST(-0.18439576029778)}, + {FRAC_CONST(0.11960318684578), FRAC_CONST(0.99899345636368)}, {FRAC_CONST(0.94292563199997), FRAC_CONST(0.83163905143738)}, {FRAC_CONST(0.75081145763397), FRAC_CONST(-0.35533222556114)}, + {FRAC_CONST(0.56721979379654), FRAC_CONST(-0.24076835811138)}, {FRAC_CONST(0.46857765316963), FRAC_CONST(-0.30140233039856)}, {FRAC_CONST(0.97312313318253), FRAC_CONST(-0.99548190832138)}, + {FRAC_CONST(-0.38299977779388), FRAC_CONST(0.98516911268234)}, {FRAC_CONST(0.41025799512863), FRAC_CONST(0.02116736955941)}, {FRAC_CONST(0.09638062119484), FRAC_CONST(0.04411984235048)}, + {FRAC_CONST(-0.85283249616623), FRAC_CONST(0.91475564241409)}, {FRAC_CONST(0.88866806030273), FRAC_CONST(-0.99735265970230)}, {FRAC_CONST(-0.48202428221703), FRAC_CONST(-0.96805608272552)}, + {FRAC_CONST(0.27572581171989), FRAC_CONST(0.58634752035141)}, {FRAC_CONST(-0.65889132022858), FRAC_CONST(0.58835631608963)}, {FRAC_CONST(0.98838084936142), FRAC_CONST(0.99994349479675)}, + {FRAC_CONST(-0.20651349425316), FRAC_CONST(0.54593044519424)}, {FRAC_CONST(-0.62126415967941), FRAC_CONST(-0.59893679618835)}, {FRAC_CONST(0.20320105552673), FRAC_CONST(-0.86879181861877)}, + {FRAC_CONST(-0.97790551185608), FRAC_CONST(0.96290808916092)}, {FRAC_CONST(0.11112534999847), FRAC_CONST(0.21484763920307)}, {FRAC_CONST(-0.41368338465691), FRAC_CONST(0.28216838836670)}, + {FRAC_CONST(0.24133038520813), FRAC_CONST(0.51294362545013)}, {FRAC_CONST(-0.66393411159515), FRAC_CONST(-0.08249679952860)}, {FRAC_CONST(-0.53697830438614), FRAC_CONST(-0.97649902105331)}, + {FRAC_CONST(-0.97224736213684), FRAC_CONST(0.22081333398819)}, {FRAC_CONST(0.87392479181290), FRAC_CONST(-0.12796173989773)}, {FRAC_CONST(0.19050361216068), FRAC_CONST(0.01602615416050)}, + {FRAC_CONST(-0.46353441476822), FRAC_CONST(-0.95249038934708)}, {FRAC_CONST(-0.07064096629620), FRAC_CONST(-0.94479805231094)}, {FRAC_CONST(-0.92444086074829), FRAC_CONST(-0.10457590222359)}, + {FRAC_CONST(-0.83822596073151), FRAC_CONST(-0.01695043221116)}, {FRAC_CONST(0.75214684009552), FRAC_CONST(-0.99955683946609)}, {FRAC_CONST(-0.42102998495102), FRAC_CONST(0.99720942974091)}, + {FRAC_CONST(-0.72094786167145), FRAC_CONST(-0.35008960962296)}, {FRAC_CONST(0.78843313455582), FRAC_CONST(0.52851396799088)}, {FRAC_CONST(0.97394025325775), FRAC_CONST(-0.26695942878723)}, + {FRAC_CONST(0.99206465482712), FRAC_CONST(-0.57010120153427)}, {FRAC_CONST(0.76789611577988), FRAC_CONST(-0.76519358158112)}, {FRAC_CONST(-0.82002419233322), FRAC_CONST(-0.73530179262161)}, + {FRAC_CONST(0.81924992799759), FRAC_CONST(0.99698424339294)}, {FRAC_CONST(-0.26719850301743), FRAC_CONST(0.68903368711472)}, {FRAC_CONST(-0.43311259150505), FRAC_CONST(0.85321813821793)}, + {FRAC_CONST(0.99194979667664), FRAC_CONST(0.91876250505447)}, {FRAC_CONST(-0.80691999197006), FRAC_CONST(-0.32627540826797)}, {FRAC_CONST(0.43080005049706), FRAC_CONST(-0.21919095516205)}, + {FRAC_CONST(0.67709493637085), FRAC_CONST(-0.95478075742722)}, {FRAC_CONST(0.56151771545410), FRAC_CONST(-0.70693808794022)}, {FRAC_CONST(0.10831862688065), FRAC_CONST(-0.08628837019205)}, + {FRAC_CONST(0.91229414939880), FRAC_CONST(-0.65987348556519)}, {FRAC_CONST(-0.48972892761230), FRAC_CONST(0.56289243698120)}, {FRAC_CONST(-0.89033657312393), FRAC_CONST(-0.71656566858292)}, + {FRAC_CONST(0.65269446372986), FRAC_CONST(0.65916007757187)}, {FRAC_CONST(0.67439478635788), FRAC_CONST(-0.81684380769730)}, {FRAC_CONST(-0.47770830988884), FRAC_CONST(-0.16789555549622)}, + {FRAC_CONST(-0.99715977907181), FRAC_CONST(-0.93565785884857)}, {FRAC_CONST(-0.90889590978622), FRAC_CONST(0.62034398317337)}, {FRAC_CONST(-0.06618622690439), FRAC_CONST(-0.23812216520309)}, + {FRAC_CONST(0.99430269002914), FRAC_CONST(0.18812555074692)}, {FRAC_CONST(0.97686403989792), FRAC_CONST(-0.28664535284042)}, {FRAC_CONST(0.94813650846481), FRAC_CONST(-0.97506642341614)}, + {FRAC_CONST(-0.95434498786926), FRAC_CONST(-0.79607981443405)}, {FRAC_CONST(-0.49104782938957), FRAC_CONST(0.32895213365555)}, {FRAC_CONST(0.99881172180176), FRAC_CONST(0.88993984460831)}, + {FRAC_CONST(0.50449168682098), FRAC_CONST(-0.85995072126389)}, {FRAC_CONST(0.47162890434265), FRAC_CONST(-0.18680204451084)}, {FRAC_CONST(-0.62081581354141), FRAC_CONST(0.75000673532486)}, + {FRAC_CONST(-0.43867015838623), FRAC_CONST(0.99998068809509)}, {FRAC_CONST(0.98630565404892), FRAC_CONST(-0.53578901290894)}, {FRAC_CONST(-0.61510360240936), FRAC_CONST(-0.89515018463135)}, + {FRAC_CONST(-0.03841517493129), FRAC_CONST(-0.69888818264008)}, {FRAC_CONST(-0.30102157592773), FRAC_CONST(-0.07667808979750)}, {FRAC_CONST(0.41881284117699), FRAC_CONST(0.02188098989427)}, + {FRAC_CONST(-0.86135452985764), FRAC_CONST(0.98947483301163)}, {FRAC_CONST(0.67226862907410), FRAC_CONST(-0.13494388759136)}, {FRAC_CONST(-0.70737397670746), FRAC_CONST(-0.76547348499298)}, + {FRAC_CONST(0.94044947624207), FRAC_CONST(0.09026201069355)}, {FRAC_CONST(-0.82386350631714), FRAC_CONST(0.08924768865108)}, {FRAC_CONST(-0.32070666551590), FRAC_CONST(0.50143420696259)}, + {FRAC_CONST(0.57593160867691), FRAC_CONST(-0.98966425657272)}, {FRAC_CONST(-0.36326017975807), FRAC_CONST(0.07440242916346)}, {FRAC_CONST(0.99979043006897), FRAC_CONST(-0.14130286872387)}, + {FRAC_CONST(-0.92366021871567), FRAC_CONST(-0.97979295253754)}, {FRAC_CONST(-0.44607177376747), FRAC_CONST(-0.54233253002167)}, {FRAC_CONST(0.44226801395416), FRAC_CONST(0.71326756477356)}, + {FRAC_CONST(0.03671907261014), FRAC_CONST(0.63606387376785)}, {FRAC_CONST(0.52175426483154), FRAC_CONST(-0.85396826267242)}, {FRAC_CONST(-0.94701141119003), FRAC_CONST(-0.01826348155737)}, + {FRAC_CONST(-0.98759609460831), FRAC_CONST(0.82288712263107)}, {FRAC_CONST(0.87434792518616), FRAC_CONST(0.89399492740631)}, {FRAC_CONST(-0.93412041664124), FRAC_CONST(0.41374051570892)}, + {FRAC_CONST(0.96063941717148), FRAC_CONST(0.93116706609726)}, {FRAC_CONST(0.97534251213074), FRAC_CONST(0.86150932312012)}, {FRAC_CONST(0.99642467498779), FRAC_CONST(0.70190042257309)}, + {FRAC_CONST(-0.94705086946487), FRAC_CONST(-0.29580041766167)}, {FRAC_CONST(0.91599804162979), FRAC_CONST(-0.98147833347321)}}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +static const real_t log_Qplus1[31] = {REAL_CONST(6.022367813028454), REAL_CONST(5.044394119358453), REAL_CONST(4.087462841250339), REAL_CONST(3.169925001442313), REAL_CONST(2.321928094887362), + REAL_CONST(1.584962500721156), REAL_CONST(1.000000000000000), REAL_CONST(0.584962500721156), REAL_CONST(0.321928094887362), REAL_CONST(0.169925001442312), + REAL_CONST(0.087462841250339), REAL_CONST(0.044394119358453), REAL_CONST(0.022367813028455), REAL_CONST(0.011227255423254), REAL_CONST(0.005624549193878), + REAL_CONST(0.002815015607054), REAL_CONST(0.001408194392808), REAL_CONST(0.000704269011247), REAL_CONST(0.000352177480301), REAL_CONST(0.000176099486443), + REAL_CONST(0.000088052430122), REAL_CONST(0.000044026886827), REAL_CONST(0.000022013611360), REAL_CONST(0.000011006847667), REAL_CONST(0.000005503434331), + REAL_CONST(0.000002751719790), REAL_CONST(0.000001375860551), REAL_CONST(0.000000687930439), REAL_CONST(0.000000343965261), REAL_CONST(0.000000171982641), + REAL_CONST(0.000000000000000)}; + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +/* log2 values of [0..63] */ +static const real_t log2_int_tab[] = {LOG2_MIN_INF, + REAL_CONST(0.000000000000000), + REAL_CONST(1.000000000000000), + REAL_CONST(1.584962500721156), + REAL_CONST(2.000000000000000), + REAL_CONST(2.321928094887362), + REAL_CONST(2.584962500721156), + REAL_CONST(2.807354922057604), + REAL_CONST(3.000000000000000), + REAL_CONST(3.169925001442313), + REAL_CONST(3.321928094887363), + REAL_CONST(3.459431618637297), + REAL_CONST(3.584962500721156), + REAL_CONST(3.700439718141092), + REAL_CONST(3.807354922057604), + REAL_CONST(3.906890595608519), + REAL_CONST(4.000000000000000), + REAL_CONST(4.087462841250339), + REAL_CONST(4.169925001442312), + REAL_CONST(4.247927513443585), + REAL_CONST(4.321928094887362), + REAL_CONST(4.392317422778761), + REAL_CONST(4.459431618637297), + REAL_CONST(4.523561956057013), + REAL_CONST(4.584962500721156), + REAL_CONST(4.643856189774724), + REAL_CONST(4.700439718141093), + REAL_CONST(4.754887502163468), + REAL_CONST(4.807354922057604), + REAL_CONST(4.857980995127572), + REAL_CONST(4.906890595608519), + REAL_CONST(4.954196310386875), + REAL_CONST(5.000000000000000), + REAL_CONST(5.044394119358453), + REAL_CONST(5.087462841250340), + REAL_CONST(5.129283016944966), + REAL_CONST(5.169925001442312), + REAL_CONST(5.209453365628949), + REAL_CONST(5.247927513443585), + REAL_CONST(5.285402218862248), + REAL_CONST(5.321928094887363), + REAL_CONST(5.357552004618084), + REAL_CONST(5.392317422778761), + REAL_CONST(5.426264754702098), + REAL_CONST(5.459431618637297), + REAL_CONST(5.491853096329675), + REAL_CONST(5.523561956057013), + REAL_CONST(5.554588851677637), + REAL_CONST(5.584962500721156), + REAL_CONST(5.614709844115208), + REAL_CONST(5.643856189774724), + REAL_CONST(5.672425341971495), + REAL_CONST(5.700439718141093), + REAL_CONST(5.727920454563200), + REAL_CONST(5.754887502163469), + REAL_CONST(5.781359713524660), + REAL_CONST(5.807354922057605), + REAL_CONST(5.832890014164742), + REAL_CONST(5.857980995127572), + REAL_CONST(5.882643049361842), + REAL_CONST(5.906890595608518), + REAL_CONST(5.930737337562887), + REAL_CONST(5.954196310386876), + REAL_CONST(5.977279923499916)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +static const real_t pan_log2_tab[] = {REAL_CONST(1.000000000000000), REAL_CONST(0.584962500721156), REAL_CONST(0.321928094887362), REAL_CONST(0.169925001442312), REAL_CONST(0.087462841250339), + REAL_CONST(0.044394119358453), REAL_CONST(0.022367813028455), REAL_CONST(0.011227255423254), REAL_CONST(0.005624549193878), REAL_CONST(0.002815015607054), + REAL_CONST(0.001408194392808), REAL_CONST(0.000704269011247), REAL_CONST(0.000352177480301), REAL_CONST(0.000176099486443), REAL_CONST(0.000088052430122), + REAL_CONST(0.000044026886827), REAL_CONST(0.000022013611360), REAL_CONST(0.000011006847667)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +static const real_t log_Qplus1_pan[31][13] = { + {REAL_CONST(0.044383447617292), REAL_CONST(0.169768601655960), REAL_CONST(0.583090126514435), REAL_CONST(1.570089221000671), REAL_CONST(3.092446088790894), REAL_CONST(4.733354568481445), + REAL_CONST(6.022367954254150), REAL_CONST(6.692092418670654), REAL_CONST(6.924463272094727), REAL_CONST(6.989034175872803), REAL_CONST(7.005646705627441), REAL_CONST(7.009829998016357), + REAL_CONST(7.010877609252930)}, + {REAL_CONST(0.022362394258380), REAL_CONST(0.087379962205887), REAL_CONST(0.320804953575134), REAL_CONST(0.988859415054321), REAL_CONST(2.252387046813965), REAL_CONST(3.786596298217773), + REAL_CONST(5.044394016265869), REAL_CONST(5.705977916717529), REAL_CONST(5.936291694641113), REAL_CONST(6.000346660614014), REAL_CONST(6.016829967498779), REAL_CONST(6.020981311798096), + REAL_CONST(6.022020816802979)}, + {REAL_CONST(0.011224525049329), REAL_CONST(0.044351425021887), REAL_CONST(0.169301137328148), REAL_CONST(0.577544987201691), REAL_CONST(1.527246952056885), REAL_CONST(2.887525320053101), + REAL_CONST(4.087462902069092), REAL_CONST(4.733354568481445), REAL_CONST(4.959661006927490), REAL_CONST(5.022709369659424), REAL_CONST(5.038940429687500), REAL_CONST(5.043028831481934), + REAL_CONST(5.044052600860596)}, + {REAL_CONST(0.005623178556561), REAL_CONST(0.022346137091517), REAL_CONST(0.087132595479488), REAL_CONST(0.317482173442841), REAL_CONST(0.956931233406067), REAL_CONST(2.070389270782471), + REAL_CONST(3.169924974441528), REAL_CONST(3.786596298217773), REAL_CONST(4.005294322967529), REAL_CONST(4.066420555114746), REAL_CONST(4.082170009613037), REAL_CONST(4.086137294769287), + REAL_CONST(4.087131500244141)}, + {REAL_CONST(0.002814328996465), REAL_CONST(0.011216334067285), REAL_CONST(0.044224001467228), REAL_CONST(0.167456731200218), REAL_CONST(0.556393325328827), REAL_CONST(1.378511548042297), + REAL_CONST(2.321928024291992), REAL_CONST(2.887525320053101), REAL_CONST(3.092446088790894), REAL_CONST(3.150059700012207), REAL_CONST(3.164926528930664), REAL_CONST(3.168673276901245), + REAL_CONST(3.169611930847168)}, + {REAL_CONST(0.001407850766554), REAL_CONST(0.005619067233056), REAL_CONST(0.022281449288130), REAL_CONST(0.086156636476517), REAL_CONST(0.304854571819305), REAL_CONST(0.847996890544891), + REAL_CONST(1.584962487220764), REAL_CONST(2.070389270782471), REAL_CONST(2.252387046813965), REAL_CONST(2.304061651229858), REAL_CONST(2.317430257797241), REAL_CONST(2.320801734924316), + REAL_CONST(2.321646213531494)}, + {REAL_CONST(0.000704097095877), REAL_CONST(0.002812269143760), REAL_CONST(0.011183738708496), REAL_CONST(0.043721374124289), REAL_CONST(0.160464659333229), REAL_CONST(0.485426813364029), + REAL_CONST(1.000000000000000), REAL_CONST(1.378511548042297), REAL_CONST(1.527246952056885), REAL_CONST(1.570089221000671), REAL_CONST(1.581215262413025), REAL_CONST(1.584023833274841), + REAL_CONST(1.584727644920349)}, + {REAL_CONST(0.000352177477907), REAL_CONST(0.001406819908880), REAL_CONST(0.005602621007711), REAL_CONST(0.022026389837265), REAL_CONST(0.082462236285210), REAL_CONST(0.263034462928772), + REAL_CONST(0.584962487220764), REAL_CONST(0.847996890544891), REAL_CONST(0.956931233406067), REAL_CONST(0.988859415054321), REAL_CONST(0.997190535068512), REAL_CONST(0.999296069145203), + REAL_CONST(0.999823868274689)}, + {REAL_CONST(0.000176099492819), REAL_CONST(0.000703581434209), REAL_CONST(0.002804030198604), REAL_CONST(0.011055230163038), REAL_CONST(0.041820213198662), REAL_CONST(0.137503549456596), + REAL_CONST(0.321928083896637), REAL_CONST(0.485426813364029), REAL_CONST(0.556393325328827), REAL_CONST(0.577544987201691), REAL_CONST(0.583090126514435), REAL_CONST(0.584493279457092), + REAL_CONST(0.584845066070557)}, + {REAL_CONST(0.000088052431238), REAL_CONST(0.000351833587047), REAL_CONST(0.001402696361765), REAL_CONST(0.005538204684854), REAL_CONST(0.021061634644866), REAL_CONST(0.070389263331890), + REAL_CONST(0.169925004243851), REAL_CONST(0.263034462928772), REAL_CONST(0.304854571819305), REAL_CONST(0.317482173442841), REAL_CONST(0.320804953575134), REAL_CONST(0.321646571159363), + REAL_CONST(0.321857661008835)}, + {REAL_CONST(0.000044026888645), REAL_CONST(0.000175927518285), REAL_CONST(0.000701518612914), REAL_CONST(0.002771759871393), REAL_CONST(0.010569252073765), REAL_CONST(0.035623874515295), + REAL_CONST(0.087462842464447), REAL_CONST(0.137503549456596), REAL_CONST(0.160464659333229), REAL_CONST(0.167456731200218), REAL_CONST(0.169301137328148), REAL_CONST(0.169768601655960), + REAL_CONST(0.169885858893394)}, + {REAL_CONST(0.000022013611670), REAL_CONST(0.000088052431238), REAL_CONST(0.000350801943569), REAL_CONST(0.001386545598507), REAL_CONST(0.005294219125062), REAL_CONST(0.017921976745129), + REAL_CONST(0.044394120573997), REAL_CONST(0.070389263331890), REAL_CONST(0.082462236285210), REAL_CONST(0.086156636476517), REAL_CONST(0.087132595479488), REAL_CONST(0.087379962205887), + REAL_CONST(0.087442122399807)}, + {REAL_CONST(0.000011006847672), REAL_CONST(0.000044026888645), REAL_CONST(0.000175411638338), REAL_CONST(0.000693439331371), REAL_CONST(0.002649537986144), REAL_CONST(0.008988817222416), + REAL_CONST(0.022367812693119), REAL_CONST(0.035623874515295), REAL_CONST(0.041820213198662), REAL_CONST(0.043721374124289), REAL_CONST(0.044224001467228), REAL_CONST(0.044351425021887), + REAL_CONST(0.044383447617292)}, + {REAL_CONST(0.000005503434295), REAL_CONST(0.000022013611670), REAL_CONST(0.000087708482170), REAL_CONST(0.000346675369656), REAL_CONST(0.001325377263129), REAL_CONST(0.004501323681325), + REAL_CONST(0.011227255687118), REAL_CONST(0.017921976745129), REAL_CONST(0.021061634644866), REAL_CONST(0.022026389837265), REAL_CONST(0.022281449288130), REAL_CONST(0.022346137091517), + REAL_CONST(0.022362394258380)}, + {REAL_CONST(0.000002751719876), REAL_CONST(0.000011006847672), REAL_CONST(0.000043854910473), REAL_CONST(0.000173348103999), REAL_CONST(0.000662840844598), REAL_CONST(0.002252417383716), + REAL_CONST(0.005624548997730), REAL_CONST(0.008988817222416), REAL_CONST(0.010569252073765), REAL_CONST(0.011055230163038), REAL_CONST(0.011183738708496), REAL_CONST(0.011216334067285), + REAL_CONST(0.011224525049329)}, + {REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000022013611670), REAL_CONST(0.000086676649516), REAL_CONST(0.000331544462824), REAL_CONST(0.001126734190620), + REAL_CONST(0.002815015614033), REAL_CONST(0.004501323681325), REAL_CONST(0.005294219125062), REAL_CONST(0.005538204684854), REAL_CONST(0.005602621007711), REAL_CONST(0.005619067233056), + REAL_CONST(0.005623178556561)}, + {REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000011006847672), REAL_CONST(0.000043338975956), REAL_CONST(0.000165781748365), REAL_CONST(0.000563477107789), + REAL_CONST(0.001408194424585), REAL_CONST(0.002252417383716), REAL_CONST(0.002649537986144), REAL_CONST(0.002771759871393), REAL_CONST(0.002804030198604), REAL_CONST(0.002812269143760), + REAL_CONST(0.002814328996465)}, + {REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000021669651687), REAL_CONST(0.000082893253420), REAL_CONST(0.000281680084299), + REAL_CONST(0.000704268983100), REAL_CONST(0.001126734190620), REAL_CONST(0.001325377263129), REAL_CONST(0.001386545598507), REAL_CONST(0.001402696361765), REAL_CONST(0.001406819908880), + REAL_CONST(0.001407850766554)}, + {REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000010834866771), REAL_CONST(0.000041447223339), REAL_CONST(0.000140846910654), + REAL_CONST(0.000352177477907), REAL_CONST(0.000563477107789), REAL_CONST(0.000662840844598), REAL_CONST(0.000693439331371), REAL_CONST(0.000701518612914), REAL_CONST(0.000703581434209), + REAL_CONST(0.000704097095877)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005503434295), REAL_CONST(0.000020637769921), REAL_CONST(0.000070511166996), + REAL_CONST(0.000176099492819), REAL_CONST(0.000281680084299), REAL_CONST(0.000331544462824), REAL_CONST(0.000346675369656), REAL_CONST(0.000350801943569), REAL_CONST(0.000351833587047), + REAL_CONST(0.000352177477907)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002751719876), REAL_CONST(0.000010318922250), REAL_CONST(0.000035256012779), + REAL_CONST(0.000088052431238), REAL_CONST(0.000140846910654), REAL_CONST(0.000165781748365), REAL_CONST(0.000173348103999), REAL_CONST(0.000175411638338), REAL_CONST(0.000175927518285), + REAL_CONST(0.000176099492819)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000005159470220), REAL_CONST(0.000017542124624), + REAL_CONST(0.000044026888645), REAL_CONST(0.000070511166996), REAL_CONST(0.000082893253420), REAL_CONST(0.000086676649516), REAL_CONST(0.000087708482170), REAL_CONST(0.000088052431238), + REAL_CONST(0.000088052431238)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002579737384), REAL_CONST(0.000008771088687), + REAL_CONST(0.000022013611670), REAL_CONST(0.000035256012779), REAL_CONST(0.000041447223339), REAL_CONST(0.000043338975956), REAL_CONST(0.000043854910473), REAL_CONST(0.000044026888645), + REAL_CONST(0.000044026888645)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001375860506), REAL_CONST(0.000004471542070), + REAL_CONST(0.000011006847672), REAL_CONST(0.000017542124624), REAL_CONST(0.000020637769921), REAL_CONST(0.000021669651687), REAL_CONST(0.000022013611670), REAL_CONST(0.000022013611670), + REAL_CONST(0.000022013611670)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000687930424), REAL_CONST(0.000002235772627), + REAL_CONST(0.000005503434295), REAL_CONST(0.000008771088687), REAL_CONST(0.000010318922250), REAL_CONST(0.000010834866771), REAL_CONST(0.000011006847672), REAL_CONST(0.000011006847672), + REAL_CONST(0.000011006847672)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), REAL_CONST(0.000001031895522), + REAL_CONST(0.000002751719876), REAL_CONST(0.000004471542070), REAL_CONST(0.000005159470220), REAL_CONST(0.000005503434295), REAL_CONST(0.000005503434295), REAL_CONST(0.000005503434295), + REAL_CONST(0.000005503434295)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000515947875), + REAL_CONST(0.000001375860506), REAL_CONST(0.000002235772627), REAL_CONST(0.000002579737384), REAL_CONST(0.000002751719876), REAL_CONST(0.000002751719876), REAL_CONST(0.000002751719876), + REAL_CONST(0.000002751719876)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000343965269), + REAL_CONST(0.000000687930424), REAL_CONST(0.000001031895522), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), REAL_CONST(0.000001375860506), + REAL_CONST(0.000001375860506)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), + REAL_CONST(0.000000343965269), REAL_CONST(0.000000515947875), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), REAL_CONST(0.000000687930424), + REAL_CONST(0.000000687930424)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), + REAL_CONST(0.000000171982634), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), REAL_CONST(0.000000343965269), + REAL_CONST(0.000000343965269)}, + {REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), REAL_CONST(0.000000000000000), + REAL_CONST(0.000000000000000), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), REAL_CONST(0.000000171982634), + REAL_CONST(0.000000171982634)}}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +static const real_t log_Qplus1[31] = {REAL_CONST(6.022367813028454), REAL_CONST(5.044394119358453), REAL_CONST(4.087462841250339), REAL_CONST(3.169925001442313), REAL_CONST(2.321928094887362), + REAL_CONST(1.584962500721156), REAL_CONST(1.000000000000000), REAL_CONST(0.584962500721156), REAL_CONST(0.321928094887362), REAL_CONST(0.169925001442312), + REAL_CONST(0.087462841250339), REAL_CONST(0.044394119358453), REAL_CONST(0.022367813028455), REAL_CONST(0.011227255423254), REAL_CONST(0.005624549193878), + REAL_CONST(0.002815015607054), REAL_CONST(0.001408194392808), REAL_CONST(0.000704269011247), REAL_CONST(0.000352177480301), REAL_CONST(0.000176099486443), + REAL_CONST(0.000088052430122), REAL_CONST(0.000044026886827), REAL_CONST(0.000022013611360), REAL_CONST(0.000011006847667), REAL_CONST(0.000005503434331), + REAL_CONST(0.000002751719790), REAL_CONST(0.000001375860551), REAL_CONST(0.000000687930439), REAL_CONST(0.000000343965261), REAL_CONST(0.000000171982641), + REAL_CONST(0.000000000000000)}; + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +/* log2 values of [0..63] */ +static const real_t log2_int_tab[] = {LOG2_MIN_INF, 0.000000000000000, 1.000000000000000, 1.584962500721156, 2.000000000000000, 2.321928094887362, 2.584962500721156, 2.807354922057604, + 3.000000000000000, 3.169925001442313, 3.321928094887363, 3.459431618637297, 3.584962500721156, 3.700439718141092, 3.807354922057604, 3.906890595608519, + 4.000000000000000, 4.087462841250339, 4.169925001442312, 4.247927513443585, 4.321928094887362, 4.392317422778761, 4.459431618637297, 4.523561956057013, + 4.584962500721156, 4.643856189774724, 4.700439718141093, 4.754887502163468, 4.807354922057604, 4.857980995127572, 4.906890595608519, 4.954196310386875, + 5.000000000000000, 5.044394119358453, 5.087462841250340, 5.129283016944966, 5.169925001442312, 5.209453365628949, 5.247927513443585, 5.285402218862248, + 5.321928094887363, 5.357552004618084, 5.392317422778761, 5.426264754702098, 5.459431618637297, 5.491853096329675, 5.523561956057013, 5.554588851677637, + 5.584962500721156, 5.614709844115208, 5.643856189774724, 5.672425341971495, 5.700439718141093, 5.727920454563200, 5.754887502163469, 5.781359713524660, + 5.807354922057605, 5.832890014164742, 5.857980995127572, 5.882643049361842, 5.906890595608518, 5.930737337562887, 5.954196310386876, 5.977279923499916}; +static const real_t pan_log2_tab[] = {1.000000000000000, 0.584962500721156, 0.321928094887362, 0.169925001442312, 0.087462841250339, 0.044394119358453, + 0.022367813028455, 0.011227255423254, 0.005624549193878, 0.002815015607054, 0.001408194392808, 0.000704269011247, + 0.000352177480301, 0.000176099486443, 0.000088052430122, 0.000044026886827, 0.000022013611360, 0.000011006847667}; + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const real_t qmf_c[640] = { + FRAC_CONST(0.0000000000000), FRAC_CONST(-0.00055252865047), FRAC_CONST(-0.00056176925738), FRAC_CONST(-0.00049475180896), FRAC_CONST(-0.00048752279712), FRAC_CONST(-0.00048937912498), + FRAC_CONST(-0.00050407143497), FRAC_CONST(-0.00052265642972), FRAC_CONST(-0.00054665656337), FRAC_CONST(-0.00056778025613), FRAC_CONST(-0.00058709304852), FRAC_CONST(-0.00061327473938), + FRAC_CONST(-0.00063124935319), FRAC_CONST(-0.00065403333621), FRAC_CONST(-0.00067776907764), FRAC_CONST(-0.00069416146273), FRAC_CONST(-0.00071577364744), FRAC_CONST(-0.00072550431222), + FRAC_CONST(-0.00074409418541), FRAC_CONST(-0.00074905980532), FRAC_CONST(-0.0007681371927), FRAC_CONST(-0.00077248485949), FRAC_CONST(-0.00078343322877), FRAC_CONST(-0.00077798694927), + FRAC_CONST(-0.000780366471), FRAC_CONST(-0.00078014496257), FRAC_CONST(-0.0007757977331), FRAC_CONST(-0.00076307935757), FRAC_CONST(-0.00075300014201), FRAC_CONST(-0.00073193571525), + FRAC_CONST(-0.00072153919876), FRAC_CONST(-0.00069179375372), FRAC_CONST(-0.00066504150893), FRAC_CONST(-0.00063415949025), FRAC_CONST(-0.0005946118933), FRAC_CONST(-0.00055645763906), + FRAC_CONST(-0.00051455722108), FRAC_CONST(-0.00046063254803), FRAC_CONST(-0.00040951214522), FRAC_CONST(-0.00035011758756), FRAC_CONST(-0.00028969811748), FRAC_CONST(-0.0002098337344), + FRAC_CONST(-0.00014463809349), FRAC_CONST(-6.173344072E-005), FRAC_CONST(1.349497418E-005), FRAC_CONST(0.00010943831274), FRAC_CONST(0.00020430170688), FRAC_CONST(0.00029495311041), + FRAC_CONST(0.0004026540216), FRAC_CONST(0.00051073884952), FRAC_CONST(0.00062393761391), FRAC_CONST(0.00074580258865), FRAC_CONST(0.00086084433262), FRAC_CONST(0.00098859883015), + FRAC_CONST(0.00112501551307), FRAC_CONST(0.00125778846475), FRAC_CONST(0.00139024948272), FRAC_CONST(0.00154432198471), FRAC_CONST(0.00168680832531), FRAC_CONST(0.00183482654224), + FRAC_CONST(0.00198411407369), FRAC_CONST(0.00214615835557), FRAC_CONST(0.00230172547746), FRAC_CONST(0.00246256169126), FRAC_CONST(0.00262017586902), FRAC_CONST(0.00278704643465), + FRAC_CONST(0.00294694477165), FRAC_CONST(0.00311254206525), FRAC_CONST(0.00327396134847), FRAC_CONST(0.00344188741828), FRAC_CONST(0.00360082681231), FRAC_CONST(0.00376039229104), + FRAC_CONST(0.00392074323703), FRAC_CONST(0.00408197531935), FRAC_CONST(0.0042264269227), FRAC_CONST(0.00437307196781), FRAC_CONST(0.00452098527825), FRAC_CONST(0.00466064606118), + FRAC_CONST(0.00479325608498), FRAC_CONST(0.00491376035745), FRAC_CONST(0.00503930226013), FRAC_CONST(0.00514073539032), FRAC_CONST(0.00524611661324), FRAC_CONST(0.00534716811982), + FRAC_CONST(0.00541967759307), FRAC_CONST(0.00548760401507), FRAC_CONST(0.00554757145088), FRAC_CONST(0.00559380230045), FRAC_CONST(0.00562206432097), FRAC_CONST(0.00564551969164), + FRAC_CONST(0.00563891995151), FRAC_CONST(0.00562661141932), FRAC_CONST(0.0055917128663), FRAC_CONST(0.005540436394), FRAC_CONST(0.0054753783077), FRAC_CONST(0.0053838975897), + FRAC_CONST(0.00527157587272), FRAC_CONST(0.00513822754514), FRAC_CONST(0.00498396877629), FRAC_CONST(0.004810946906), FRAC_CONST(0.00460395301471), FRAC_CONST(0.00438018617447), + FRAC_CONST(0.0041251642327), FRAC_CONST(0.00384564081246), FRAC_CONST(0.00354012465507), FRAC_CONST(0.00320918858098), FRAC_CONST(0.00284467578623), FRAC_CONST(0.00245085400321), + FRAC_CONST(0.0020274176185), FRAC_CONST(0.00157846825768), FRAC_CONST(0.00109023290512), FRAC_CONST(0.0005832264248), FRAC_CONST(2.760451905E-005), FRAC_CONST(-0.00054642808664), + FRAC_CONST(-0.00115681355227), FRAC_CONST(-0.00180394725893), FRAC_CONST(-0.00248267236449), FRAC_CONST(-0.003193377839), FRAC_CONST(-0.00394011240522), FRAC_CONST(-0.004722259624), + FRAC_CONST(-0.00553372111088), FRAC_CONST(-0.00637922932685), FRAC_CONST(-0.00726158168517), FRAC_CONST(-0.00817982333726), FRAC_CONST(-0.00913253296085), FRAC_CONST(-0.01011502154986), + FRAC_CONST(-0.01113155480321), FRAC_CONST(-0.01218499959508), FRAC_CONST(0.01327182200351), FRAC_CONST(0.01439046660792), FRAC_CONST(0.01554055533423), FRAC_CONST(0.01673247129989), + FRAC_CONST(0.01794333813443), FRAC_CONST(0.01918724313698), FRAC_CONST(0.02045317933555), FRAC_CONST(0.02174675502535), FRAC_CONST(0.02306801692862), FRAC_CONST(0.02441609920285), + FRAC_CONST(0.02578758475467), FRAC_CONST(0.02718594296329), FRAC_CONST(0.02860721736385), FRAC_CONST(0.03005026574279), FRAC_CONST(0.03150176087389), FRAC_CONST(0.03297540810337), + FRAC_CONST(0.03446209487686), FRAC_CONST(0.03596975605542), FRAC_CONST(0.03748128504252), FRAC_CONST(0.03900536794745), FRAC_CONST(0.04053491705584), FRAC_CONST(0.04206490946367), + FRAC_CONST(0.04360975421304), FRAC_CONST(0.04514884056413), FRAC_CONST(0.04668430272642), FRAC_CONST(0.04821657200672), FRAC_CONST(0.04973857556014), FRAC_CONST(0.05125561555216), + FRAC_CONST(0.05276307465207), FRAC_CONST(0.05424527683589), FRAC_CONST(0.05571736482138), FRAC_CONST(0.05716164501299), FRAC_CONST(0.0585915683626), FRAC_CONST(0.05998374801761), + FRAC_CONST(0.06134551717207), FRAC_CONST(0.06268578081172), FRAC_CONST(0.06397158980681), FRAC_CONST(0.0652247106438), FRAC_CONST(0.06643675122104), FRAC_CONST(0.06760759851228), + FRAC_CONST(0.06870438283512), FRAC_CONST(0.06976302447127), FRAC_CONST(0.07076287107266), FRAC_CONST(0.07170026731102), FRAC_CONST(0.07256825833083), FRAC_CONST(0.07336202550803), + FRAC_CONST(0.07410036424342), FRAC_CONST(0.07474525581194), FRAC_CONST(0.07531373362019), FRAC_CONST(0.07580083586584), FRAC_CONST(0.07619924793396), FRAC_CONST(0.07649921704119), + FRAC_CONST(0.07670934904245), FRAC_CONST(0.07681739756964), FRAC_CONST(0.07682300113923), FRAC_CONST(0.07672049241746), FRAC_CONST(0.07650507183194), FRAC_CONST(0.07617483218536), + FRAC_CONST(0.07573057565061), FRAC_CONST(0.0751576255287), FRAC_CONST(0.07446643947564), FRAC_CONST(0.0736406005762), FRAC_CONST(0.07267746427299), FRAC_CONST(0.07158263647903), + FRAC_CONST(0.07035330735093), FRAC_CONST(0.06896640131951), FRAC_CONST(0.06745250215166), FRAC_CONST(0.06576906686508), FRAC_CONST(0.06394448059633), FRAC_CONST(0.06196027790387), + FRAC_CONST(0.0598166570809), FRAC_CONST(0.05751526919867), FRAC_CONST(0.05504600343009), FRAC_CONST(0.05240938217366), FRAC_CONST(0.04959786763445), FRAC_CONST(0.04663033051701), + FRAC_CONST(0.04347687821958), FRAC_CONST(0.04014582784127), FRAC_CONST(0.03664181168133), FRAC_CONST(0.03295839306691), FRAC_CONST(0.02908240060125), FRAC_CONST(0.02503075618909), + FRAC_CONST(0.02079970728622), FRAC_CONST(0.01637012582228), FRAC_CONST(0.01176238327857), FRAC_CONST(0.00696368621617), FRAC_CONST(0.00197656014503), FRAC_CONST(-0.00320868968304), + FRAC_CONST(-0.00857117491366), FRAC_CONST(-0.01412888273558), FRAC_CONST(-0.01988341292573), FRAC_CONST(-0.02582272888064), FRAC_CONST(-0.03195312745332), FRAC_CONST(-0.03827765720822), + FRAC_CONST(-0.04478068215856), FRAC_CONST(-0.05148041767934), FRAC_CONST(-0.05837053268336), FRAC_CONST(-0.06544098531359), FRAC_CONST(-0.07269433008129), FRAC_CONST(-0.08013729344279), + FRAC_CONST(-0.08775475365593), FRAC_CONST(-0.09555333528914), FRAC_CONST(-0.10353295311463), FRAC_CONST(-0.1116826931773), FRAC_CONST(-0.120007798468), FRAC_CONST(-0.12850028503878), + FRAC_CONST(-0.13715517611934), FRAC_CONST(-0.1459766491187), FRAC_CONST(-0.15496070710605), FRAC_CONST(-0.16409588556669), FRAC_CONST(-0.17338081721706), FRAC_CONST(-0.18281725485142), + FRAC_CONST(-0.19239667457267), FRAC_CONST(-0.20212501768103), FRAC_CONST(-0.21197358538056), FRAC_CONST(-0.22196526964149), FRAC_CONST(-0.23206908706791), FRAC_CONST(-0.24230168845974), + FRAC_CONST(-0.25264803095722), FRAC_CONST(-0.26310532994603), FRAC_CONST(-0.27366340405625), FRAC_CONST(-0.28432141891085), FRAC_CONST(-0.29507167170646), FRAC_CONST(-0.30590985751916), + FRAC_CONST(-0.31682789136456), FRAC_CONST(-0.32781137272105), FRAC_CONST(-0.33887226938665), FRAC_CONST(-0.3499914122931), FRAC_CONST(0.36115899031355), FRAC_CONST(0.37237955463061), + FRAC_CONST(0.38363500139043), FRAC_CONST(0.39492117615675), FRAC_CONST(0.40623176767625), FRAC_CONST(0.41756968968409), FRAC_CONST(0.42891199207373), FRAC_CONST(0.44025537543665), + FRAC_CONST(0.45159965356824), FRAC_CONST(0.46293080852757), FRAC_CONST(0.47424532146115), FRAC_CONST(0.48552530911099), FRAC_CONST(0.49677082545707), FRAC_CONST(0.50798175000434), + FRAC_CONST(0.51912349702391), FRAC_CONST(0.53022408956855), FRAC_CONST(0.54125534487322), FRAC_CONST(0.55220512585061), FRAC_CONST(0.5630789140137), FRAC_CONST(0.57385241316923), + FRAC_CONST(0.58454032354679), FRAC_CONST(0.59511230862496), FRAC_CONST(0.6055783538918), FRAC_CONST(0.61591099320291), FRAC_CONST(0.62612426956055), FRAC_CONST(0.63619801077286), + FRAC_CONST(0.64612696959461), FRAC_CONST(0.65590163024671), FRAC_CONST(0.66551398801627), FRAC_CONST(0.67496631901712), FRAC_CONST(0.68423532934598), FRAC_CONST(0.69332823767032), + FRAC_CONST(0.70223887193539), FRAC_CONST(0.71094104263095), FRAC_CONST(0.71944626349561), FRAC_CONST(0.72774489002994), FRAC_CONST(0.73582117582769), FRAC_CONST(0.74368278636488), + FRAC_CONST(0.75131374561237), FRAC_CONST(0.75870807608242), FRAC_CONST(0.76586748650939), FRAC_CONST(0.77277808813327), FRAC_CONST(0.77942875190216), FRAC_CONST(0.7858353120392), + FRAC_CONST(0.79197358416424), FRAC_CONST(0.797846641377), FRAC_CONST(0.80344857518505), FRAC_CONST(0.80876950044491), FRAC_CONST(0.81381912706217), FRAC_CONST(0.81857760046468), + FRAC_CONST(0.82304198905409), FRAC_CONST(0.8272275347336), FRAC_CONST(0.8311038457152), FRAC_CONST(0.83469373618402), FRAC_CONST(0.83797173378865), FRAC_CONST(0.84095413924722), + FRAC_CONST(0.84362382812005), FRAC_CONST(0.84598184698206), FRAC_CONST(0.84803157770763), FRAC_CONST(0.84978051984268), FRAC_CONST(0.85119715249343), FRAC_CONST(0.85230470352147), + FRAC_CONST(0.85310209497017), FRAC_CONST(0.85357205739107), FRAC_CONST(0.85373856005937 /*max*/), FRAC_CONST(0.85357205739107), FRAC_CONST(0.85310209497017), FRAC_CONST(0.85230470352147), + FRAC_CONST(0.85119715249343), FRAC_CONST(0.84978051984268), FRAC_CONST(0.84803157770763), FRAC_CONST(0.84598184698206), FRAC_CONST(0.84362382812005), FRAC_CONST(0.84095413924722), + FRAC_CONST(0.83797173378865), FRAC_CONST(0.83469373618402), FRAC_CONST(0.8311038457152), FRAC_CONST(0.8272275347336), FRAC_CONST(0.82304198905409), FRAC_CONST(0.81857760046468), + FRAC_CONST(0.81381912706217), FRAC_CONST(0.80876950044491), FRAC_CONST(0.80344857518505), FRAC_CONST(0.797846641377), FRAC_CONST(0.79197358416424), FRAC_CONST(0.7858353120392), + FRAC_CONST(0.77942875190216), FRAC_CONST(0.77277808813327), FRAC_CONST(0.76586748650939), FRAC_CONST(0.75870807608242), FRAC_CONST(0.75131374561237), FRAC_CONST(0.74368278636488), + FRAC_CONST(0.73582117582769), FRAC_CONST(0.72774489002994), FRAC_CONST(0.71944626349561), FRAC_CONST(0.71094104263095), FRAC_CONST(0.70223887193539), FRAC_CONST(0.69332823767032), + FRAC_CONST(0.68423532934598), FRAC_CONST(0.67496631901712), FRAC_CONST(0.66551398801627), FRAC_CONST(0.65590163024671), FRAC_CONST(0.64612696959461), FRAC_CONST(0.63619801077286), + FRAC_CONST(0.62612426956055), FRAC_CONST(0.61591099320291), FRAC_CONST(0.6055783538918), FRAC_CONST(0.59511230862496), FRAC_CONST(0.58454032354679), FRAC_CONST(0.57385241316923), + FRAC_CONST(0.5630789140137), FRAC_CONST(0.55220512585061), FRAC_CONST(0.54125534487322), FRAC_CONST(0.53022408956855), FRAC_CONST(0.51912349702391), FRAC_CONST(0.50798175000434), + FRAC_CONST(0.49677082545707), FRAC_CONST(0.48552530911099), FRAC_CONST(0.47424532146115), FRAC_CONST(0.46293080852757), FRAC_CONST(0.45159965356824), FRAC_CONST(0.44025537543665), + FRAC_CONST(0.42891199207373), FRAC_CONST(0.41756968968409), FRAC_CONST(0.40623176767625), FRAC_CONST(0.39492117615675), FRAC_CONST(0.38363500139043), FRAC_CONST(0.37237955463061), + FRAC_CONST(-0.36115899031355), FRAC_CONST(-0.3499914122931), FRAC_CONST(-0.33887226938665), FRAC_CONST(-0.32781137272105), FRAC_CONST(-0.31682789136456), FRAC_CONST(-0.30590985751916), + FRAC_CONST(-0.29507167170646), FRAC_CONST(-0.28432141891085), FRAC_CONST(-0.27366340405625), FRAC_CONST(-0.26310532994603), FRAC_CONST(-0.25264803095722), FRAC_CONST(-0.24230168845974), + FRAC_CONST(-0.23206908706791), FRAC_CONST(-0.22196526964149), FRAC_CONST(-0.21197358538056), FRAC_CONST(-0.20212501768103), FRAC_CONST(-0.19239667457267), FRAC_CONST(-0.18281725485142), + FRAC_CONST(-0.17338081721706), FRAC_CONST(-0.16409588556669), FRAC_CONST(-0.15496070710605), FRAC_CONST(-0.1459766491187), FRAC_CONST(-0.13715517611934), FRAC_CONST(-0.12850028503878), + FRAC_CONST(-0.120007798468), FRAC_CONST(-0.1116826931773), FRAC_CONST(-0.10353295311463), FRAC_CONST(-0.09555333528914), FRAC_CONST(-0.08775475365593), FRAC_CONST(-0.08013729344279), + FRAC_CONST(-0.07269433008129), FRAC_CONST(-0.06544098531359), FRAC_CONST(-0.05837053268336), FRAC_CONST(-0.05148041767934), FRAC_CONST(-0.04478068215856), FRAC_CONST(-0.03827765720822), + FRAC_CONST(-0.03195312745332), FRAC_CONST(-0.02582272888064), FRAC_CONST(-0.01988341292573), FRAC_CONST(-0.01412888273558), FRAC_CONST(-0.00857117491366), FRAC_CONST(-0.00320868968304), + FRAC_CONST(0.00197656014503), FRAC_CONST(0.00696368621617), FRAC_CONST(0.01176238327857), FRAC_CONST(0.01637012582228), FRAC_CONST(0.02079970728622), FRAC_CONST(0.02503075618909), + FRAC_CONST(0.02908240060125), FRAC_CONST(0.03295839306691), FRAC_CONST(0.03664181168133), FRAC_CONST(0.04014582784127), FRAC_CONST(0.04347687821958), FRAC_CONST(0.04663033051701), + FRAC_CONST(0.04959786763445), FRAC_CONST(0.05240938217366), FRAC_CONST(0.05504600343009), FRAC_CONST(0.05751526919867), FRAC_CONST(0.0598166570809), FRAC_CONST(0.06196027790387), + FRAC_CONST(0.06394448059633), FRAC_CONST(0.06576906686508), FRAC_CONST(0.06745250215166), FRAC_CONST(0.06896640131951), FRAC_CONST(0.07035330735093), FRAC_CONST(0.07158263647903), + FRAC_CONST(0.07267746427299), FRAC_CONST(0.0736406005762), FRAC_CONST(0.07446643947564), FRAC_CONST(0.0751576255287), FRAC_CONST(0.07573057565061), FRAC_CONST(0.07617483218536), + FRAC_CONST(0.07650507183194), FRAC_CONST(0.07672049241746), FRAC_CONST(0.07682300113923), FRAC_CONST(0.07681739756964), FRAC_CONST(0.07670934904245), FRAC_CONST(0.07649921704119), + FRAC_CONST(0.07619924793396), FRAC_CONST(0.07580083586584), FRAC_CONST(0.07531373362019), FRAC_CONST(0.07474525581194), FRAC_CONST(0.07410036424342), FRAC_CONST(0.07336202550803), + FRAC_CONST(0.07256825833083), FRAC_CONST(0.07170026731102), FRAC_CONST(0.07076287107266), FRAC_CONST(0.06976302447127), FRAC_CONST(0.06870438283512), FRAC_CONST(0.06760759851228), + FRAC_CONST(0.06643675122104), FRAC_CONST(0.0652247106438), FRAC_CONST(0.06397158980681), FRAC_CONST(0.06268578081172), FRAC_CONST(0.06134551717207), FRAC_CONST(0.05998374801761), + FRAC_CONST(0.0585915683626), FRAC_CONST(0.05716164501299), FRAC_CONST(0.05571736482138), FRAC_CONST(0.05424527683589), FRAC_CONST(0.05276307465207), FRAC_CONST(0.05125561555216), + FRAC_CONST(0.04973857556014), FRAC_CONST(0.04821657200672), FRAC_CONST(0.04668430272642), FRAC_CONST(0.04514884056413), FRAC_CONST(0.04360975421304), FRAC_CONST(0.04206490946367), + FRAC_CONST(0.04053491705584), FRAC_CONST(0.03900536794745), FRAC_CONST(0.03748128504252), FRAC_CONST(0.03596975605542), FRAC_CONST(0.03446209487686), FRAC_CONST(0.03297540810337), + FRAC_CONST(0.03150176087389), FRAC_CONST(0.03005026574279), FRAC_CONST(0.02860721736385), FRAC_CONST(0.02718594296329), FRAC_CONST(0.02578758475467), FRAC_CONST(0.02441609920285), + FRAC_CONST(0.02306801692862), FRAC_CONST(0.02174675502535), FRAC_CONST(0.02045317933555), FRAC_CONST(0.01918724313698), FRAC_CONST(0.01794333813443), FRAC_CONST(0.01673247129989), + FRAC_CONST(0.01554055533423), FRAC_CONST(0.01439046660792), FRAC_CONST(-0.01327182200351), FRAC_CONST(-0.01218499959508), FRAC_CONST(-0.01113155480321), FRAC_CONST(-0.01011502154986), + FRAC_CONST(-0.00913253296085), FRAC_CONST(-0.00817982333726), FRAC_CONST(-0.00726158168517), FRAC_CONST(-0.00637922932685), FRAC_CONST(-0.00553372111088), FRAC_CONST(-0.004722259624), + FRAC_CONST(-0.00394011240522), FRAC_CONST(-0.003193377839), FRAC_CONST(-0.00248267236449), FRAC_CONST(-0.00180394725893), FRAC_CONST(-0.00115681355227), FRAC_CONST(-0.00054642808664), + FRAC_CONST(2.760451905E-005), FRAC_CONST(0.0005832264248), FRAC_CONST(0.00109023290512), FRAC_CONST(0.00157846825768), FRAC_CONST(0.0020274176185), FRAC_CONST(0.00245085400321), + FRAC_CONST(0.00284467578623), FRAC_CONST(0.00320918858098), FRAC_CONST(0.00354012465507), FRAC_CONST(0.00384564081246), FRAC_CONST(0.0041251642327), FRAC_CONST(0.00438018617447), + FRAC_CONST(0.00460395301471), FRAC_CONST(0.004810946906), FRAC_CONST(0.00498396877629), FRAC_CONST(0.00513822754514), FRAC_CONST(0.00527157587272), FRAC_CONST(0.0053838975897), + FRAC_CONST(0.0054753783077), FRAC_CONST(0.005540436394), FRAC_CONST(0.0055917128663), FRAC_CONST(0.00562661141932), FRAC_CONST(0.00563891995151), FRAC_CONST(0.00564551969164), + FRAC_CONST(0.00562206432097), FRAC_CONST(0.00559380230045), FRAC_CONST(0.00554757145088), FRAC_CONST(0.00548760401507), FRAC_CONST(0.00541967759307), FRAC_CONST(0.00534716811982), + FRAC_CONST(0.00524611661324), FRAC_CONST(0.00514073539032), FRAC_CONST(0.00503930226013), FRAC_CONST(0.00491376035745), FRAC_CONST(0.00479325608498), FRAC_CONST(0.00466064606118), + FRAC_CONST(0.00452098527825), FRAC_CONST(0.00437307196781), FRAC_CONST(0.0042264269227), FRAC_CONST(0.00408197531935), FRAC_CONST(0.00392074323703), FRAC_CONST(0.00376039229104), + FRAC_CONST(0.00360082681231), FRAC_CONST(0.00344188741828), FRAC_CONST(0.00327396134847), FRAC_CONST(0.00311254206525), FRAC_CONST(0.00294694477165), FRAC_CONST(0.00278704643465), + FRAC_CONST(0.00262017586902), FRAC_CONST(0.00246256169126), FRAC_CONST(0.00230172547746), FRAC_CONST(0.00214615835557), FRAC_CONST(0.00198411407369), FRAC_CONST(0.00183482654224), + FRAC_CONST(0.00168680832531), FRAC_CONST(0.00154432198471), FRAC_CONST(0.00139024948272), FRAC_CONST(0.00125778846475), FRAC_CONST(0.00112501551307), FRAC_CONST(0.00098859883015), + FRAC_CONST(0.00086084433262), FRAC_CONST(0.00074580258865), FRAC_CONST(0.00062393761391), FRAC_CONST(0.00051073884952), FRAC_CONST(0.0004026540216), FRAC_CONST(0.00029495311041), + FRAC_CONST(0.00020430170688), FRAC_CONST(0.00010943831274), FRAC_CONST(1.349497418E-005), FRAC_CONST(-6.173344072E-005), FRAC_CONST(-0.00014463809349), FRAC_CONST(-0.0002098337344), + FRAC_CONST(-0.00028969811748), FRAC_CONST(-0.00035011758756), FRAC_CONST(-0.00040951214522), FRAC_CONST(-0.00046063254803), FRAC_CONST(-0.00051455722108), FRAC_CONST(-0.00055645763906), + FRAC_CONST(-0.0005946118933), FRAC_CONST(-0.00063415949025), FRAC_CONST(-0.00066504150893), FRAC_CONST(-0.00069179375372), FRAC_CONST(-0.00072153919876), FRAC_CONST(-0.00073193571525), + FRAC_CONST(-0.00075300014201), FRAC_CONST(-0.00076307935757), FRAC_CONST(-0.0007757977331), FRAC_CONST(-0.00078014496257), FRAC_CONST(-0.000780366471), FRAC_CONST(-0.00077798694927), + FRAC_CONST(-0.00078343322877), FRAC_CONST(-0.00077248485949), FRAC_CONST(-0.0007681371927), FRAC_CONST(-0.00074905980532), FRAC_CONST(-0.00074409418541), FRAC_CONST(-0.00072550431222), + FRAC_CONST(-0.00071577364744), FRAC_CONST(-0.00069416146273), FRAC_CONST(-0.00067776907764), FRAC_CONST(-0.00065403333621), FRAC_CONST(-0.00063124935319), FRAC_CONST(-0.00061327473938), + FRAC_CONST(-0.00058709304852), FRAC_CONST(-0.00056778025613), FRAC_CONST(-0.00054665656337), FRAC_CONST(-0.00052265642972), FRAC_CONST(-0.00050407143497), FRAC_CONST(-0.00048937912498), + FRAC_CONST(-0.00048752279712), FRAC_CONST(-0.00049475180896), FRAC_CONST(-0.00056176925738), FRAC_CONST(-0.00055252865047)}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +__unused static const complex_t qmf32_pre_twiddle[] = { + {FRAC_CONST(0.999924701839145), FRAC_CONST(-0.012271538285720)}, {FRAC_CONST(0.999322384588350), FRAC_CONST(-0.036807222941359)}, {FRAC_CONST(0.998118112900149), FRAC_CONST(-0.061320736302209)}, + {FRAC_CONST(0.996312612182778), FRAC_CONST(-0.085797312344440)}, {FRAC_CONST(0.993906970002356), FRAC_CONST(-0.110222207293883)}, {FRAC_CONST(0.990902635427780), FRAC_CONST(-0.134580708507126)}, + {FRAC_CONST(0.987301418157858), FRAC_CONST(-0.158858143333861)}, {FRAC_CONST(0.983105487431216), FRAC_CONST(-0.183039887955141)}, {FRAC_CONST(0.978317370719628), FRAC_CONST(-0.207111376192219)}, + {FRAC_CONST(0.972939952205560), FRAC_CONST(-0.231058108280671)}, {FRAC_CONST(0.966976471044852), FRAC_CONST(-0.254865659604515)}, {FRAC_CONST(0.960430519415566), FRAC_CONST(-0.278519689385053)}, + {FRAC_CONST(0.953306040354194), FRAC_CONST(-0.302005949319228)}, {FRAC_CONST(0.945607325380521), FRAC_CONST(-0.325310292162263)}, {FRAC_CONST(0.937339011912575), FRAC_CONST(-0.348418680249435)}, + {FRAC_CONST(0.928506080473216), FRAC_CONST(-0.371317193951838)}, {FRAC_CONST(0.919113851690058), FRAC_CONST(-0.393992040061048)}, {FRAC_CONST(0.909167983090522), FRAC_CONST(-0.416429560097637)}, + {FRAC_CONST(0.898674465693954), FRAC_CONST(-0.438616238538528)}, {FRAC_CONST(0.887639620402854), FRAC_CONST(-0.460538710958240)}, {FRAC_CONST(0.876070094195407), FRAC_CONST(-0.482183772079123)}, + {FRAC_CONST(0.863972856121587), FRAC_CONST(-0.503538383725718)}, {FRAC_CONST(0.851355193105265), FRAC_CONST(-0.524589682678469)}, {FRAC_CONST(0.838224705554838), FRAC_CONST(-0.545324988422046)}, + {FRAC_CONST(0.824589302785025), FRAC_CONST(-0.565731810783613)}, {FRAC_CONST(0.810457198252595), FRAC_CONST(-0.585797857456439)}, {FRAC_CONST(0.795836904608884), FRAC_CONST(-0.605511041404326)}, + {FRAC_CONST(0.780737228572094), FRAC_CONST(-0.624859488142386)}, {FRAC_CONST(0.765167265622459), FRAC_CONST(-0.643831542889791)}, {FRAC_CONST(0.749136394523459), FRAC_CONST(-0.662415777590172)}, + {FRAC_CONST(0.732654271672413), FRAC_CONST(-0.680600997795453)}, {FRAC_CONST(0.715730825283819), FRAC_CONST(-0.698376249408973)}}; +#endif /*SBR_DEC*/ +#ifdef LD_DEC +static const uint16_t* swb_offset_512_window[] = { + 0, /* 96000 */ + 0, /* 88200 */ + 0, /* 64000 */ + swb_offset_512_48, /* 48000 */ + swb_offset_512_48, /* 44100 */ + swb_offset_512_32, /* 32000 */ + swb_offset_512_24, /* 24000 */ + swb_offset_512_24, /* 22050 */ + 0, /* 16000 */ + 0, /* 12000 */ + 0, /* 11025 */ + 0 /* 8000 */ +}; +#endif // LD_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LD_DEC +static const uint16_t* swb_offset_480_window[] = { + 0, /* 96000 */ + 0, /* 88200 */ + 0, /* 64000 */ + swb_offset_480_48, /* 48000 */ + swb_offset_480_48, /* 44100 */ + swb_offset_480_32, /* 32000 */ + swb_offset_480_24, /* 24000 */ + swb_offset_480_24, /* 22050 */ + 0, /* 16000 */ + 0, /* 12000 */ + 0, /* 11025 */ + 0 /* 8000 */ +}; +#endif // LD_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +static const uint16_t* swb_offset_128_window[] = { + swb_offset_128_96, /* 96000 */ + swb_offset_128_96, /* 88200 */ + swb_offset_128_64, /* 64000 */ + swb_offset_128_48, /* 48000 */ + swb_offset_128_48, /* 44100 */ + swb_offset_128_48, /* 32000 */ + swb_offset_128_24, /* 24000 */ + swb_offset_128_24, /* 22050 */ + swb_offset_128_16, /* 16000 */ + swb_offset_128_16, /* 12000 */ + swb_offset_128_16, /* 11025 */ + swb_offset_128_8 /* 8000 */ +}; +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +/* index == 99 means not allowed codeword */ +static rvlc_huff_table book_rvlc[] = { + /*index length codeword */ + {0, 1, 0}, /* 0 */ + {-1, 3, 5}, /* 101 */ + {1, 3, 7}, /* 111 */ + {-2, 4, 9}, /* 1001 */ + {-3, 5, 17}, /* 10001 */ + {2, 5, 27}, /* 11011 */ + {-4, 6, 33}, /* 100001 */ + {99, 6, 50}, /* 110010 */ + {3, 6, 51}, /* 110011 */ + {99, 6, 52}, /* 110100 */ + {-7, 7, 65}, /* 1000001 */ + {99, 7, 96}, /* 1100000 */ + {99, 7, 98}, /* 1100010 */ + {7, 7, 99}, /* 1100011 */ + {4, 7, 107}, /* 1101011 */ + {-5, 8, 129}, /* 10000001 */ + {99, 8, 194}, /* 11000010 */ + {5, 8, 195}, /* 11000011 */ + {99, 8, 212}, /* 11010100 */ + {99, 9, 256}, /* 100000000 */ + {-6, 9, 257}, /* 100000001 */ + {99, 9, 426}, /* 110101010 */ + {6, 9, 427}, /* 110101011 */ + {99, 10, 0} /* Shouldn't come this far */ +}; +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +static const real_t codebook[8] = {REAL_CONST(0.570829), REAL_CONST(0.696616), REAL_CONST(0.813004), REAL_CONST(0.911304), + REAL_CONST(0.984900), REAL_CONST(1.067894), REAL_CONST(1.194601), REAL_CONST(1.369533)}; +#endif // LPT_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +static const real_t ipdopd_cos_tab[] = {FRAC_CONST(1.000000000000000), FRAC_CONST(0.707106781186548), FRAC_CONST(0.000000000000000), FRAC_CONST(-0.707106781186547), FRAC_CONST(-1.000000000000000), + FRAC_CONST(-0.707106781186548), FRAC_CONST(-0.000000000000000), FRAC_CONST(0.707106781186547), FRAC_CONST(1.000000000000000)}; +static const real_t ipdopd_sin_tab[] = {FRAC_CONST(0.000000000000000), FRAC_CONST(0.707106781186547), FRAC_CONST(1.000000000000000), FRAC_CONST(0.707106781186548), FRAC_CONST(0.000000000000000), + FRAC_CONST(-0.707106781186547), FRAC_CONST(-1.000000000000000), FRAC_CONST(-0.707106781186548), FRAC_CONST(-0.000000000000000)}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* data tables */ +static const uint8_t nr_iid_par_tab[] = {10, 20, 34, 10, 20, 34, 0, 0}; +static const uint8_t nr_ipdopd_par_tab[] = {5, 11, 17, 5, 11, 17, 0, 0}; +static const uint8_t nr_icc_par_tab[] = {10, 20, 34, 10, 20, 34, 0, 0}; +static const uint8_t num_env_tab[][4] = {{0, 1, 2, 4}, {1, 2, 3, 4}}; +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.cpp b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.cpp new file mode 100644 index 0000000..4cf5e10 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.cpp @@ -0,0 +1,15670 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: bits.c,v 1.44 2007/11/01 12:33:29 menno Exp $ +**/ +#include "neaacdec.h" +#include "Arduino.h" +#include +#include + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::get_sr_index(const uint32_t samplerate) { + if (92017 <= samplerate) return 0; + if (75132 <= samplerate) return 1; + if (55426 <= samplerate) return 2; + if (46009 <= samplerate) return 3; + if (37566 <= samplerate) return 4; + if (27713 <= samplerate) return 5; + if (23004 <= samplerate) return 6; + if (18783 <= samplerate) return 7; + if (13856 <= samplerate) return 8; + if (11502 <= samplerate) return 9; + if (9391 <= samplerate) return 10; + if (16428320 <= samplerate) return 11; + return 11; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Returns the sample rate based on the sample rate index */ +uint32_t NeaacDecoder::get_sample_rate(const uint8_t sr_index) { + const uint32_t sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000}; + if (sr_index < 12) return sample_rates[sr_index]; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::max_pred_sfb(const uint8_t sr_index) { + const uint8_t pred_sfb_max[] = {33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34}; + if (sr_index < 12) return pred_sfb_max[sr_index]; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::max_tns_sfb(const uint8_t sr_index, const uint8_t object_type, const uint8_t is_short) { + /* entry for each sampling rate + * 1 Main/LC long window + * 2 Main/LC short window + * 3 SSR long window + * 4 SSR short window + */ + const uint8_t tns_sbf_max[][4] = {{31, 9, 28, 7}, /* 96000 */ + {31, 9, 28, 7}, /* 88200 */ + {34, 10, 27, 7}, /* 64000 */ + {40, 14, 26, 6}, /* 48000 */ + {42, 14, 26, 6}, /* 44100 */ + {51, 14, 26, 6}, /* 32000 */ + {46, 14, 29, 7}, /* 24000 */ + {46, 14, 29, 7}, /* 22050 */ + {42, 14, 23, 8}, /* 16000 */ + {42, 14, 23, 8}, /* 12000 */ + {42, 14, 23, 8}, /* 11025 */ + {39, 14, 19, 7}, /* 8000 */ + {39, 14, 19, 7}, /* 7350 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; + uint8_t i = 0; + if (is_short) i++; + if (object_type == SSR) i += 2; + return tns_sbf_max[sr_index][i]; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Returns 0 if an object type is decodable, otherwise returns -1 */ +int8_t NeaacDecoder::can_decode_ot(const uint8_t object_type) { + switch (object_type) { + case LC: return 0; + case MAIN: +#ifdef MAIN_DEC + return 0; +#else + return -1; +#endif + case SSR: +#ifdef SSR_DEC + return 0; +#else + return -1; +#endif + case LTP: +#ifdef LTP_DEC + return 0; +#else + return -1; +#endif + /* ER object types */ +#ifdef ERROR_RESILIENCE + case ER_LC: + #ifdef DRM + case DRM_ER_LC: + #endif + return 0; + case ER_LTP: + #ifdef LTP_DEC + return 0; + #else + return -1; + #endif + case LD: + #ifdef LD_DEC + return 0; + #else + return -1; + #endif +#endif + } + return -1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void* NeaacDecoder::faad_malloc(size_t size) { + char* ps_str = NULL; + if (psramFound()) { + ps_str = (char*)ps_malloc(size); + } else { + ps_str = (char*)malloc(size); + } + return ps_str; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void* NeaacDecoder::faad_calloc(size_t len, size_t size) { + char* ps_str = NULL; + if (psramFound()) { + ps_str = (char*)ps_calloc(len, size); + } else { + ps_str = (char*)calloc(len, size); + } + return ps_str; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* common free function */ +template void NeaacDecoder::faad_free(freeType** b) { + if (*b) { + free(*b); + *b = NULL; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::ne_rng(uint32_t* __r1, uint32_t* __r2) { + uint32_t t1, t2, t3, t4; + t3 = t1 = *__r1; + t4 = t2 = *__r2; // Parity calculation is done via table lookup, this is also available + t1 &= 0xF5; + t2 >>= 25; // on CPUs without parity, can be implemented in C and avoid unpredictable + t1 = Parity[t1]; + t2 &= 0x63; // jumps and slow rotate through the carry flag operations. + t1 <<= 31; + t2 = Parity[t2]; + return (*__r1 = (t3 >> 1) | t1) ^ (*__r2 = (t4 + t4) | t2); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::ones32(uint32_t x) { + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return (x & 0x0000003f); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::floor_log2(uint32_t x) { +#if 1 + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return (ones32(x) - 1); +#else + uint32_t count = 0; + while (x >>= 1) count++; + return count; +#endif +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* returns position of first bit that is not 0 from msb, + * starting count at lsb */ +uint32_t NeaacDecoder::wl_min_lzc(uint32_t x) { +#if 1 + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return (ones32(x)); +#else + uint32_t count = 0; + while (x >>= 1) count++; + return (count + 1); +#endif +} +#ifdef FIXED_POINT +real_t NeaacDecoder::pow2_fix(real_t val) { + uint32_t x1, x2; + uint32_t errcorr; + uint32_t index_frac; + real_t retval; + int32_t whole = (val >> REAL_BITS); + /* rest = [0..1] */ + int32_t rest = val - (whole << REAL_BITS); + /* index into pow2_tab */ + int32_t index = rest >> (REAL_BITS - TABLE_BITS); + if (val == 0) return (1 << REAL_BITS); + /* leave INTERP_BITS bits */ + index_frac = rest >> (REAL_BITS - TABLE_BITS - INTERP_BITS); + index_frac = index_frac & ((1 << INTERP_BITS) - 1); + if (whole > 0) { + retval = 1 << whole; + } else { + retval = REAL_CONST(1) >> -whole; + } + x1 = pow2_tab[index & ((1 << TABLE_BITS) - 1)]; + x2 = pow2_tab[(index & ((1 << TABLE_BITS) - 1)) + 1]; + errcorr = ((index_frac * (x2 - x1))) >> INTERP_BITS; + if (whole > 0) { + retval = retval * (errcorr + x1); + } else { + retval = MUL_R(retval, (errcorr + x1)); + } + return retval; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +int32_t NeaacDecoder::pow2_int(real_t val) { + uint32_t x1, x2; + uint32_t errcorr; + uint32_t index_frac; + real_t retval; + int32_t whole = (val >> REAL_BITS); + /* rest = [0..1] */ + int32_t rest = val - (whole << REAL_BITS); + /* index into pow2_tab */ + int32_t index = rest >> (REAL_BITS - TABLE_BITS); + if (val == 0) return 1; + /* leave INTERP_BITS bits */ + index_frac = rest >> (REAL_BITS - TABLE_BITS - INTERP_BITS); + index_frac = index_frac & ((1 << INTERP_BITS) - 1); + if (whole > 0) + retval = 1 << whole; + else + retval = 0; + x1 = pow2_tab[index & ((1 << TABLE_BITS) - 1)]; + x2 = pow2_tab[(index & ((1 << TABLE_BITS) - 1)) + 1]; + errcorr = ((index_frac * (x2 - x1))) >> INTERP_BITS; + retval = MUL_R(retval, (errcorr + x1)); + return retval; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +/* ld(x) = ld(x*y/y) = ld(x/y) + ld(y), with y=2^N and [1 <= (x/y) < 2] */ +int32_t NeaacDecoder::log2_int(uint32_t val) { + uint32_t frac; + uint32_t whole = (val); + (void)whole; + int32_t exp = 0; + uint32_t index; + uint32_t index_frac; + uint32_t x1, x2; + uint32_t errcorr; + /* error */ + if (val == 0) return -10000; + exp = floor_log2(val); + exp -= REAL_BITS; + /* frac = [1..2] */ + if (exp >= 0) + frac = val >> exp; + else + frac = val << -exp; + /* index in the log2 table */ + index = frac >> (REAL_BITS - TABLE_BITS); + /* leftover part for linear interpolation */ + index_frac = frac & ((1 << (REAL_BITS - TABLE_BITS)) - 1); + /* leave INTERP_BITS bits */ + index_frac = index_frac >> (REAL_BITS - TABLE_BITS - INTERP_BITS); + x1 = log2_tab[index & ((1 << TABLE_BITS) - 1)]; + x2 = log2_tab[(index & ((1 << TABLE_BITS) - 1)) + 1]; + /* linear interpolation */ + /* retval = exp + ((index_frac)*x2 + (1-index_frac)*x1) */ + errcorr = (index_frac * (x2 - x1)) >> INTERP_BITS; + return ((exp + REAL_BITS) << REAL_BITS) + errcorr + x1; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +/* ld(x) = ld(x*y/y) = ld(x/y) + ld(y), with y=2^N and [1 <= (x/y) < 2] */ +real_t NeaacDecoder::log2_fix(uint32_t val) { + uint32_t frac; + uint32_t whole = (val >> REAL_BITS); + (void)whole; + int8_t exp = 0; + uint32_t index; + uint32_t index_frac; + uint32_t x1, x2; + uint32_t errcorr; + /* error */ + if (val == 0) return -100000; + exp = floor_log2(val); + exp -= REAL_BITS; + /* frac = [1..2] */ + if (exp >= 0) + frac = val >> exp; + else + frac = val << -exp; + /* index in the log2 table */ + index = frac >> (REAL_BITS - TABLE_BITS); + /* leftover part for linear interpolation */ + index_frac = frac & ((1 << (REAL_BITS - TABLE_BITS)) - 1); + /* leave INTERP_BITS bits */ + index_frac = index_frac >> (REAL_BITS - TABLE_BITS - INTERP_BITS); + x1 = log2_tab[index & ((1 << TABLE_BITS) - 1)]; + x2 = log2_tab[(index & ((1 << TABLE_BITS) - 1)) + 1]; + /* linear interpolation */ + /* retval = exp + ((index_frac)*x2 + (1-index_frac)*x1) */ + errcorr = (index_frac * (x2 - x1)) >> INTERP_BITS; + return (exp << REAL_BITS) + errcorr + x1; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int NeaacDecoder::NeAACDecGetVersion(const char** faad_id_string, const char** faad_copyright_string) { + const char* libfaadName = "2.20.1"; + const char* libCopyright = " Copyright 2002-2004: Ahead Software AG\n" + " http://www.audiocoding.com\n" + " bug tracking: https://sourceforge.net/p/faac/bugs/\n"; + if (faad_id_string) *faad_id_string = libfaadName; + if (faad_copyright_string) *faad_copyright_string = libCopyright; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +error_info_t NeaacDecoder::NeAACDecGetErrorMessage(const uint8_t errcode) { + if (errcode > NUM_ERROR_MESSAGES) return err_msg[NUM_ERROR_MESSAGES]; // unspecified + return err_msg[errcode]; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::NeAACDecGetCapabilities(void) { + uint32_t cap = 0; + /* can't do without it */ + cap += LC_DEC_CAP; +#ifdef MAIN_DEC + cap += MAIN_DEC_CAP; +#endif +#ifdef LTP_DEC + cap += LTP_DEC_CAP; +#endif +#ifdef LD_DEC + cap += LD_DEC_CAP; +#endif +#ifdef ERROR_RESILIENCE + cap += ERROR_RESILIENCE_CAP; +#endif +#ifdef FIXED_POINT + cap += FIXED_POINT_CAP; +#endif + return cap; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +NeAACDecHandle NeaacDecoder::NeAACDecOpen() { + uint8_t i; + NeAACDecStruct* hDecoder = NULL; + if ((hDecoder = (NeAACDecStruct*)faad_calloc(1, sizeof(NeAACDecStruct))) == NULL) return NULL; + memset(hDecoder, 0, sizeof(NeAACDecStruct)); + hDecoder->cmes = mes; + hDecoder->config.outputFormat = FAAD_FMT_16BIT; + hDecoder->config.defObjectType = MAIN; + hDecoder->config.defSampleRate = 44100; /* Default: 44.1kHz */ + hDecoder->config.downMatrix = 0; + hDecoder->adts_header_present = 0; + hDecoder->adif_header_present = 0; + hDecoder->latm_header_present = 0; +#ifdef ERROR_RESILIENCE + hDecoder->aacSectionDataResilienceFlag = 0; + hDecoder->aacScalefactorDataResilienceFlag = 0; + hDecoder->aacSpectralDataResilienceFlag = 0; +#endif + hDecoder->frameLength = 1024; + hDecoder->frame = 0; + hDecoder->sample_buffer = NULL; + hDecoder->__r1 = 1; + hDecoder->__r2 = 1; + for (i = 0; i < MAX_CHANNELS; i++) { + hDecoder->element_id[i] = INVALID_ELEMENT_ID; + hDecoder->window_shape_prev[i] = 0; + hDecoder->time_out[i] = NULL; + hDecoder->fb_intermed[i] = NULL; +#ifdef SSR_DEC + hDecoder->ssr_overlap[i] = NULL; + hDecoder->prev_fmd[i] = NULL; +#endif +#ifdef MAIN_DEC + hDecoder->pred_stat[i] = NULL; +#endif +#ifdef LTP_DEC + hDecoder->ltp_lag[i] = 0; + hDecoder->lt_pred_stat[i] = NULL; +#endif + } +#ifdef SBR_DEC + for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++) { hDecoder->sbr[i] = NULL; } +#endif + hDecoder->drc = drc_init(REAL_CONST(1.0), REAL_CONST(1.0)); + return hDecoder; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +NeAACDecConfigurationPtr NeaacDecoder::NeAACDecGetCurrentConfiguration(NeAACDecHandle hpDecoder) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if (hDecoder) { + NeAACDecConfigurationPtr config = &(hDecoder->config); + return config; + } + return NULL; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::NeAACDecSetConfiguration(NeAACDecHandle hpDecoder, NeAACDecConfigurationPtr config) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if (hDecoder && config) { + /* check if we can decode this object type */ + if (can_decode_ot(config->defObjectType) < 0) return 0; + hDecoder->config.defObjectType = config->defObjectType; + /* samplerate: anything but 0 should be possible */ + if (config->defSampleRate == 0) return 0; + hDecoder->config.defSampleRate = config->defSampleRate; + /* check output format */ + +#ifdef FIXED_POINT + if ((config->outputFormat < 1) || (config->outputFormat > 4)) return 0; +#else + if ((config->outputFormat < 1) || (config->outputFormat > 5)) return 0; +#endif + hDecoder->config.outputFormat = config->outputFormat; + if (config->downMatrix > 1) return 0; + hDecoder->config.downMatrix = config->downMatrix; + /* OK */ + return 1; + } + + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t NeaacDecoder::NeAACDecInit(NeAACDecHandle hpDecoder, uint8_t* buffer, uint32_t buffer_size, uint32_t* samplerate, uint8_t* channels) { + uint32_t bits = 0; + int32_t ret = 0; + m_ld.calloc_array(1, "m_ld"); + m_adif.calloc_array(1, "m_adif"); + m_adts.alloc_array(1, "m_adts"); + adif_header* adif = m_adif.get(); + adts_header* adts = m_adts.get(); + bitfile* ld = m_ld.get(); + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if ((hDecoder == NULL) || (samplerate == NULL) || (channels == NULL) || (buffer_size == 0)) { + ret = -1; + goto exit; + } + hDecoder->sf_index = get_sr_index(hDecoder->config.defSampleRate); + hDecoder->object_type = hDecoder->config.defObjectType; + *samplerate = get_sample_rate(hDecoder->sf_index); + *channels = 1; + if (buffer != NULL) { + faad_initbits(ld, buffer, buffer_size); + /* Check if an ADIF header is present */ + if ((buffer[0] == 'A') && (buffer[1] == 'D') && (buffer[2] == 'I') && (buffer[3] == 'F')) { + hDecoder->adif_header_present = 1; + get_adif_header(adif, ld); + faad_byte_align(ld); + hDecoder->sf_index = adif->pce[0].sf_index; + hDecoder->object_type = adif->pce[0].object_type + 1; + *samplerate = get_sample_rate(hDecoder->sf_index); + *channels = adif->pce[0].channels; + memcpy(&(hDecoder->pce), &(adif->pce[0]), sizeof(program_config)); + hDecoder->pce_set = 1; + bits = bit2byte(faad_get_processed_bits(ld)); + /* Check if an ADTS header is present */ + } else if (faad_showbits(ld, 12) == 0xfff) { + /* Check if an ADTS header is present */ + hDecoder->adts_header_present = 1; + adts->old_format = hDecoder->config.useOldADTSFormat; + adts_frame(adts, ld); + hDecoder->sf_index = adts->sf_index; + hDecoder->object_type = adts->profile + 1; + *samplerate = get_sample_rate(hDecoder->sf_index); + *channels = (adts->channel_configuration > 6) ? 2 : adts->channel_configuration; + } + if (ld->error) { + faad_endbits(ld); + ret = -1; + goto exit; + } + faad_endbits(ld); + } + if (!*samplerate) { + ret = -1; + goto exit; + } + +#if (defined(PS_DEC) || defined(DRM_PS)) + /* check if we have a mono file */ + if (*channels == 1) { + /* upMatrix to 2 channels for implicit signalling of PS */ + *channels = 2; + } +#endif + hDecoder->channelConfiguration = *channels; +#ifdef SBR_DEC + /* implicit signalling */ + if (*samplerate <= 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) { + *samplerate *= 2; + hDecoder->forceUpSampling = 1; + } else if (*samplerate > 24000 && (hDecoder->config.dontUpSampleImplicitSBR == 0)) { + hDecoder->downSampledSBR = 1; + } +#endif + /* must be done before frameLength is divided by 2 for LD */ +#ifdef SSR_DEC + if (hDecoder->object_type == SSR) + hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength / SSR_BANDS); + else +#endif + hDecoder->fb = filter_bank_init(hDecoder->frameLength); +#ifdef LD_DEC + if (hDecoder->object_type == LD) hDecoder->frameLength >>= 1; +#endif + if (can_decode_ot(hDecoder->object_type) < 0) { + ret = -1; + goto exit; + } + ret = bits; + goto exit; +exit: + m_ld.reset(); + m_adif.reset(); + m_adts.reset(); + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Init the library using a DecoderSpecificInfo */ +char NeaacDecoder::NeAACDecInit2(NeAACDecHandle hpDecoder, uint8_t* pBuffer, uint32_t SizeOfDecoderSpecificInfo, uint32_t* samplerate, uint8_t* channels) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + int8_t rc; + mp4AudioSpecificConfig mp4ASC; + if ((hDecoder == NULL) || (pBuffer == NULL) || (SizeOfDecoderSpecificInfo < 2) || (samplerate == NULL) || (channels == NULL)) { return -1; } + hDecoder->adif_header_present = 0; + hDecoder->adts_header_present = 0; + /* decode the audio specific config */ + rc = AudioSpecificConfig2(pBuffer, SizeOfDecoderSpecificInfo, &mp4ASC, &(hDecoder->pce), hDecoder->latm_header_present); + /* copy the relevant info to the decoder handle */ + *samplerate = mp4ASC.samplingFrequency; + if (mp4ASC.channelsConfiguration) { + *channels = mp4ASC.channelsConfiguration; + } else { + *channels = hDecoder->pce.channels; + hDecoder->pce_set = 1; + } +#if (defined(PS_DEC) || defined(DRM_PS)) + /* check if we have a mono file */ + if (*channels == 1) { + /* upMatrix to 2 channels for implicit signalling of PS */ + *channels = 2; + } +#endif + hDecoder->sf_index = mp4ASC.samplingFrequencyIndex; + hDecoder->object_type = mp4ASC.objectTypeIndex; +#ifdef ERROR_RESILIENCE + hDecoder->aacSectionDataResilienceFlag = mp4ASC.aacSectionDataResilienceFlag; + hDecoder->aacScalefactorDataResilienceFlag = mp4ASC.aacScalefactorDataResilienceFlag; + hDecoder->aacSpectralDataResilienceFlag = mp4ASC.aacSpectralDataResilienceFlag; +#endif +#ifdef SBR_DEC + hDecoder->sbr_present_flag = mp4ASC.sbr_present_flag; + hDecoder->downSampledSBR = mp4ASC.downSampledSBR; + if (hDecoder->config.dontUpSampleImplicitSBR == 0) + hDecoder->forceUpSampling = mp4ASC.forceUpSampling; + else + hDecoder->forceUpSampling = 0; + /* AAC core decoder samplerate is 2 times as low */ + if (((hDecoder->sbr_present_flag == 1) && (!hDecoder->downSampledSBR)) || hDecoder->forceUpSampling == 1) { hDecoder->sf_index = get_sr_index(mp4ASC.samplingFrequency / 2); } +#endif + if (rc != 0) { return rc; } + hDecoder->channelConfiguration = mp4ASC.channelsConfiguration; + if (mp4ASC.frameLengthFlag) +#ifdef ALLOW_SMALL_FRAMELENGTH + hDecoder->frameLength = 960; +#else + return -1; +#endif + /* must be done before frameLength is divided by 2 for LD */ +#ifdef SSR_DEC + if (hDecoder->object_type == SSR) + hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength / SSR_BANDS); + else +#endif + hDecoder->fb = filter_bank_init(hDecoder->frameLength); +#ifdef LD_DEC + if (hDecoder->object_type == LD) hDecoder->frameLength >>= 1; +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +char NeaacDecoder::NeAACDecInitDRM(NeAACDecHandle* hpDecoder, uint32_t samplerate, uint8_t channels) { + NeAACDecStruct** hDecoder = (NeAACDecStruct**)hpDecoder; + if (hDecoder == NULL) return 1; /* error */ + NeAACDecClose(*hDecoder); + *hpDecoder = NeAACDecOpen(); + /* Special object type defined for DRM */ + (*hDecoder)->config.defObjectType = DRM_ER_LC; + (*hDecoder)->config.defSampleRate = samplerate; + #ifdef ERROR_RESILIENCE // This shoudl always be defined for DRM + (*hDecoder)->aacSectionDataResilienceFlag = 1; /* VCB11 */ + (*hDecoder)->aacScalefactorDataResilienceFlag = 0; /* no RVLC */ + (*hDecoder)->aacSpectralDataResilienceFlag = 1; /* HCR */ + #endif + (*hDecoder)->frameLength = 960; + (*hDecoder)->sf_index = get_sr_index((*hDecoder)->config.defSampleRate); + (*hDecoder)->object_type = (*hDecoder)->config.defObjectType; + if ((channels == DRMCH_STEREO) || (channels == DRMCH_SBR_STEREO)) + (*hDecoder)->channelConfiguration = 2; + else + (*hDecoder)->channelConfiguration = 1; + #ifdef SBR_DEC + if ((channels == DRMCH_MONO) || (channels == DRMCH_STEREO)) + (*hDecoder)->sbr_present_flag = 0; + else + (*hDecoder)->sbr_present_flag = 1; + #endif + (*hDecoder)->fb = filter_bank_init((*hDecoder)->frameLength); + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::NeAACDecClose(NeAACDecHandle hpDecoder) { + uint8_t i; + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if (hDecoder == NULL) return; +#ifdef PROFILE + printf("AAC decoder total: %I64d cycles\n", hDecoder->cycles); + printf("requant: %I64d cycles\n", hDecoder->requant_cycles); + printf("spectral_data: %I64d cycles\n", hDecoder->spectral_cycles); + printf("scalefactors: %I64d cycles\n", hDecoder->scalefac_cycles); + printf("output: %I64d cycles\n", hDecoder->output_cycles); +#endif + for (i = 0; i < MAX_CHANNELS; i++) { + if (hDecoder->time_out[i]) faad_free(&hDecoder->time_out[i]); + if (hDecoder->fb_intermed[i]) faad_free(&hDecoder->fb_intermed[i]); +#ifdef SSR_DEC + if (hDecoder->ssr_overlap[i]) faad_free(&hDecoder->ssr_overlap[i]); + if (hDecoder->prev_fmd[i]) faad_free(&hDecoder->prev_fmd[i]); +#endif +#ifdef MAIN_DEC + if (hDecoder->pred_stat[i]) faad_free(&hDecoder->pred_stat[i]); +#endif +#ifdef LTP_DEC + if (hDecoder->lt_pred_stat[i]) faad_free(&hDecoder->lt_pred_stat[i]); +#endif + } +#ifdef SSR_DEC + if (hDecoder->object_type == SSR) + ssr_filter_bank_end(hDecoder->fb); + else +#endif + filter_bank_end(hDecoder->fb); + drc_end(hDecoder->drc); + if (hDecoder->sample_buffer) { + m_sample_buffer.reset(); + hDecoder->sample_buffer = NULL; + } +#ifdef SBR_DEC + for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++) { + if (hDecoder->sbr[i]) sbrDecodeEnd(hDecoder->sbr[i], i); + } +#endif + if (hDecoder) faad_free(&hDecoder); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::NeAACDecPostSeekReset(NeAACDecHandle hpDecoder, long frame) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if (hDecoder) { + hDecoder->postSeekResetFlag = 1; + if (frame != -1) hDecoder->frame = frame; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::create_channel_config(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo) { + hInfo->num_front_channels = 0; + hInfo->num_side_channels = 0; + hInfo->num_back_channels = 0; + hInfo->num_lfe_channels = 0; + memset(hInfo->channel_position, 0, MAX_CHANNELS * sizeof(uint8_t)); + if (hDecoder->downMatrix) { + hInfo->num_front_channels = 2; + hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; + return; + } + /* check if there is a PCE */ + if (hDecoder->pce_set) { + uint8_t i, chpos = 0; + uint8_t chdir, back_center = 0, total = 0; + hInfo->num_front_channels = hDecoder->pce.num_front_channels; + total += hInfo->num_front_channels; + hInfo->num_side_channels = hDecoder->pce.num_side_channels; + total += hInfo->num_side_channels; + hInfo->num_back_channels = hDecoder->pce.num_back_channels; + total += hInfo->num_back_channels; + hInfo->num_lfe_channels = hDecoder->pce.num_lfe_channels; + total += hInfo->num_lfe_channels; + chdir = hInfo->num_front_channels; + if (chdir & 1) { +#if (defined(PS_DEC) || defined(DRM_PS)) + if (total == 1) { + /* When PS is enabled output is always stereo */ + hInfo->channel_position[chpos++] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[chpos++] = FRONT_CHANNEL_RIGHT; + } else +#endif + hInfo->channel_position[chpos++] = FRONT_CHANNEL_CENTER; + chdir--; + } + for (i = 0; i < chdir; i += 2) { + hInfo->channel_position[chpos++] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[chpos++] = FRONT_CHANNEL_RIGHT; + } + for (i = 0; i < hInfo->num_side_channels; i += 2) { + hInfo->channel_position[chpos++] = SIDE_CHANNEL_LEFT; + hInfo->channel_position[chpos++] = SIDE_CHANNEL_RIGHT; + } + chdir = hInfo->num_back_channels; + if (chdir & 1) { + back_center = 1; + chdir--; + } + for (i = 0; i < chdir; i += 2) { + hInfo->channel_position[chpos++] = BACK_CHANNEL_LEFT; + hInfo->channel_position[chpos++] = BACK_CHANNEL_RIGHT; + } + if (back_center) { hInfo->channel_position[chpos++] = BACK_CHANNEL_CENTER; } + for (i = 0; i < hInfo->num_lfe_channels; i++) { hInfo->channel_position[chpos++] = LFE_CHANNEL; } + } else { + switch (hDecoder->channelConfiguration) { + case 1: +#if (defined(PS_DEC) || defined(DRM_PS)) + /* When PS is enabled output is always stereo */ + hInfo->num_front_channels = 2; + hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; +#else + hInfo->num_front_channels = 1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; +#endif + break; + case 2: + hInfo->num_front_channels = 2; + hInfo->channel_position[0] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT; + break; + case 3: + hInfo->num_front_channels = 3; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; + break; + case 4: + hInfo->num_front_channels = 3; + hInfo->num_back_channels = 1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; + hInfo->channel_position[3] = BACK_CHANNEL_CENTER; + break; + case 5: + hInfo->num_front_channels = 3; + hInfo->num_back_channels = 2; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; + hInfo->channel_position[3] = BACK_CHANNEL_LEFT; + hInfo->channel_position[4] = BACK_CHANNEL_RIGHT; + break; + case 6: + hInfo->num_front_channels = 3; + hInfo->num_back_channels = 2; + hInfo->num_lfe_channels = 1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; + hInfo->channel_position[3] = BACK_CHANNEL_LEFT; + hInfo->channel_position[4] = BACK_CHANNEL_RIGHT; + hInfo->channel_position[5] = LFE_CHANNEL; + break; + case 7: + hInfo->num_front_channels = 3; + hInfo->num_side_channels = 2; + hInfo->num_back_channels = 2; + hInfo->num_lfe_channels = 1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + hInfo->channel_position[1] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT; + hInfo->channel_position[3] = SIDE_CHANNEL_LEFT; + hInfo->channel_position[4] = SIDE_CHANNEL_RIGHT; + hInfo->channel_position[5] = BACK_CHANNEL_LEFT; + hInfo->channel_position[6] = BACK_CHANNEL_RIGHT; + hInfo->channel_position[7] = LFE_CHANNEL; + break; + default: /* channelConfiguration == 0 || channelConfiguration > 7 */ + { + uint8_t i; + uint8_t ch = hDecoder->fr_channels - hDecoder->has_lfe; + if (ch & 1) /* there's either a center front or a center back channel */ + { + uint8_t ch1 = (ch - 1) / 2; + if (hDecoder->first_syn_ele == ID_SCE) { + hInfo->num_front_channels = ch1 + 1; + hInfo->num_back_channels = ch1; + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + for (i = 1; i <= ch1; i += 2) { + hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = FRONT_CHANNEL_RIGHT; + } + for (i = ch1 + 1; i < ch; i += 2) { + hInfo->channel_position[i] = BACK_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = BACK_CHANNEL_RIGHT; + } + } else { + hInfo->num_front_channels = ch1; + hInfo->num_back_channels = ch1 + 1; + for (i = 0; i < ch1; i += 2) { + hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = FRONT_CHANNEL_RIGHT; + } + for (i = ch1; i < ch - 1; i += 2) { + hInfo->channel_position[i] = BACK_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = BACK_CHANNEL_RIGHT; + } + hInfo->channel_position[ch - 1] = BACK_CHANNEL_CENTER; + } + } else { + uint8_t ch1 = (ch) / 2; + hInfo->num_front_channels = ch1; + hInfo->num_back_channels = ch1; + if (ch1 & 1) { + hInfo->channel_position[0] = FRONT_CHANNEL_CENTER; + for (i = 1; i <= ch1; i += 2) { + hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = FRONT_CHANNEL_RIGHT; + } + for (i = ch1 + 1; i < ch - 1; i += 2) { + hInfo->channel_position[i] = BACK_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = BACK_CHANNEL_RIGHT; + } + hInfo->channel_position[ch - 1] = BACK_CHANNEL_CENTER; + } else { + for (i = 0; i < ch1; i += 2) { + hInfo->channel_position[i] = FRONT_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = FRONT_CHANNEL_RIGHT; + } + for (i = ch1; i < ch; i += 2) { + hInfo->channel_position[i] = BACK_CHANNEL_LEFT; + hInfo->channel_position[i + 1] = BACK_CHANNEL_RIGHT; + } + } + } + hInfo->num_lfe_channels = hDecoder->has_lfe; + for (i = ch; i < hDecoder->fr_channels; i++) { hInfo->channel_position[i] = LFE_CHANNEL; } + } break; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void* NeaacDecoder::NeAACDecDecode(NeAACDecHandle hpDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + return aac_frame_decode(hDecoder, hInfo, buffer, buffer_size, NULL, 0); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void* NeaacDecoder::NeAACDecDecode2(NeAACDecHandle hpDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size, void** sample_buffer, uint32_t sample_buffer_size) { + NeAACDecStruct* hDecoder = (NeAACDecStruct*)hpDecoder; + if ((sample_buffer == NULL) || (sample_buffer_size == 0)) { + hInfo->error = 27; + return NULL; + } + return aac_frame_decode(hDecoder, hInfo, buffer, buffer_size, sample_buffer, sample_buffer_size); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM + #define ERROR_STATE_INIT 6 +void NeaacDecoder::conceal_output(NeAACDecStruct* hDecoder, uint16_t frame_len, uint8_t out_ch, void* sample_buffer) { + return; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void* NeaacDecoder::aac_frame_decode(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size, void** sample_buffer2, uint32_t sample_buffer_size) { + uint16_t i; + uint8_t channels = 0; + uint8_t output_channels = 0; + bitfile ld = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t bitsconsumed; + uint16_t frame_len; + void* sample_buffer; + uint32_t startbit = 0, endbit = 0, payload_bits = 0; + (void)endbit; + (void)startbit; + (void)payload_bits; +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif + /* safety checks */ + if ((hDecoder == NULL) || (hInfo == NULL) || (buffer == NULL)) { return NULL; } +#if 0 + printf("%d\n", buffer_size*8); +#endif + frame_len = hDecoder->frameLength; + memset(hInfo, 0, sizeof(NeAACDecFrameInfo)); + memset(hDecoder->internal_channel, 0, MAX_CHANNELS * sizeof(hDecoder->internal_channel[0])); +#ifdef USE_TIME_LIMIT + if ((TIME_LIMIT * get_sample_rate(hDecoder->sf_index)) > hDecoder->TL_count) { + hDecoder->TL_count += 1024; + } else { + hInfo->error = (NUM_ERROR_MESSAGES - 1); + goto error; + } +#endif + /* check for some common metadata tag types in the bitstream + * No need to return an error + */ + /* ID3 */ + if (buffer_size >= 128) { + if (memcmp(buffer, "TAG", 3) == 0) { + /* found it */ + hInfo->bytesconsumed = 128; /* 128 bytes fixed size */ + /* no error, but no output either */ + return NULL; + } + } + /* initialize the bitstream */ + faad_initbits(&ld, buffer, buffer_size); +#if 0 + { + int i; + for (i = 0; i < ((buffer_size+3)>>2); i++) + { + uint8_t *buf; + uint32_t temp = 0; + buf = faad_getbitbuffer(&ld, 32); + //temp = getdword((void*)buf); + temp = *((uint32_t*)buf); + printf("0x%.8X\n", temp); + faad_free(&buf); + } + faad_endbits(&ld); + faad_initbits(&ld, buffer, buffer_size); + } +#endif +#if 0 + if(hDecoder->latm_header_present) + { + payload_bits = faad_latm_frame(&hDecoder->latm_config, &ld); + startbit = faad_get_processed_bits(&ld); + if(payload_bits == -1U) + { + hInfo->error = 1; + goto error; + } + } +#endif +#ifdef DRM + if (hDecoder->object_type == DRM_ER_LC) { + /* We do not support stereo right now */ + if (0) //(hDecoder->channelConfiguration == 2) + { + hInfo->error = 28; // Throw CRC error + goto error; + } + faad_getbits(&ld, 8); + } +#endif + if (hDecoder->adts_header_present) { + adts_header adts; + adts.old_format = hDecoder->config.useOldADTSFormat; + if ((hInfo->error = adts_frame(&adts, &ld)) > 0) goto error; + /* MPEG2 does byte_alignment() here, + * but ADTS header is always multiple of 8 bits in MPEG2 + * so not needed to actually do it. + */ + } +#ifdef ANALYSIS + dbg_count = 0; +#endif + /* decode the complete bitstream */ +#ifdef DRM + if (/*(hDecoder->object_type == 6) ||*/ (hDecoder->object_type == DRM_ER_LC)) { + DRM_aac_scalable_main_element(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc); + } else { +#endif + raw_data_block(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc); +#ifdef DRM + } +#endif + channels = hDecoder->fr_channels; + if (hInfo->error > 0) goto error; + /* safety check */ + if (channels == 0 || channels > MAX_CHANNELS) { + /* invalid number of channels */ + hInfo->error = 12; + goto error; + } + /* no more bit reading after this */ + bitsconsumed = faad_get_processed_bits(&ld); + hInfo->bytesconsumed = bit2byte(bitsconsumed); + if (ld.error) { + hInfo->error = 14; + goto error; + } + faad_endbits(&ld); + if (!hDecoder->adts_header_present && !hDecoder->adif_header_present) { + if (hDecoder->channelConfiguration == 0) hDecoder->channelConfiguration = channels; + if (channels == 8) /* 7.1 */ + hDecoder->channelConfiguration = 7; + if (channels == 7) /* not a standard channelConfiguration */ + hDecoder->channelConfiguration = 0; + } + if ((channels == 5 || channels == 6) && hDecoder->config.downMatrix) { + hDecoder->downMatrix = 1; + output_channels = 2; + } else { + output_channels = channels; + } +#if (defined(PS_DEC) || defined(DRM_PS)) + hDecoder->upMatrix = 0; + /* check if we have a mono file */ + if (output_channels == 1) { + /* upMatrix to 2 channels for implicit signalling of PS */ + hDecoder->upMatrix = 1; + output_channels = 2; + } +#endif + /* Make a channel configuration based on either a PCE or a channelConfiguration */ + create_channel_config(hDecoder, hInfo); + /* number of samples in this frame */ + hInfo->samples = frame_len * output_channels; + /* number of channels in this frame */ + hInfo->channels = output_channels; + /* samplerate */ + hInfo->samplerate = get_sample_rate(hDecoder->sf_index); + /* object type */ + hInfo->object_type = hDecoder->object_type; + /* sbr */ + hInfo->sbr = NO_SBR; + /* header type */ + hInfo->header_type = RAW; + if (hDecoder->adif_header_present) hInfo->header_type = ADIF; + if (hDecoder->adts_header_present) hInfo->header_type = ADTS; +#if (defined(PS_DEC) || defined(DRM_PS)) + hInfo->ps = hDecoder->ps_used_global; + hInfo->isPS = hDecoder->isPS; +#endif + /* check if frame has channel elements */ + if (channels == 0) { + hDecoder->frame++; + return NULL; + } + /* allocate the buffer for the final samples */ + if ((hDecoder->sample_buffer == NULL) || (hDecoder->alloced_channels != output_channels)) { + const uint8_t str[] = {sizeof(int16_t), sizeof(int32_t), sizeof(int32_t), sizeof(float), sizeof(double), sizeof(int16_t), sizeof(int16_t), sizeof(int16_t), sizeof(int16_t), 0, 0, 0}; + uint8_t stride = str[hDecoder->config.outputFormat - 1]; +#ifdef SBR_DEC + if (((hDecoder->sbr_present_flag == 1) && (!hDecoder->downSampledSBR)) || (hDecoder->forceUpSampling == 1)) { stride = 2 * stride; } +#endif + /* check if we want to use internal sample_buffer */ + if (sample_buffer_size == 0) { + m_sample_buffer.alloc(frame_len * output_channels * stride, "m_sample_buffer"); + hDecoder->sample_buffer = m_sample_buffer.get(); + } else if (sample_buffer_size < frame_len * output_channels * stride) { + /* provided sample buffer is not big enough */ + hInfo->error = 27; + return NULL; + } + hDecoder->alloced_channels = output_channels; + } + if (sample_buffer_size == 0) { + sample_buffer = hDecoder->sample_buffer; + } else { + sample_buffer = *sample_buffer2; + } +#ifdef SBR_DEC + if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) { + uint8_t ele; + /* this data is different when SBR is used or when the data is upsampled */ + if (!hDecoder->downSampledSBR) { + frame_len *= 2; + hInfo->samples *= 2; + hInfo->samplerate *= 2; + } + /* check if every element was provided with SBR data */ + for (ele = 0; ele < hDecoder->fr_ch_ele; ele++) { + if (hDecoder->sbr[ele] == NULL) { + hInfo->error = 25; + goto error; + } + } + /* sbr */ + if (hDecoder->sbr_present_flag == 1) { + hInfo->object_type = HE_AAC; + hInfo->sbr = SBR_UPSAMPLED; + } else { + hInfo->sbr = NO_SBR_UPSAMPLED; + } + if (hDecoder->downSampledSBR) { hInfo->sbr = SBR_DOWNSAMPLED; } + } +#endif + sample_buffer = output_to_PCM(hDecoder, hDecoder->time_out, sample_buffer, output_channels, frame_len, hDecoder->config.outputFormat); +#ifdef DRM + // conceal_output(hDecoder, frame_len, output_channels, sample_buffer); +#endif + hDecoder->postSeekResetFlag = 0; + hDecoder->frame++; +#ifdef LD_DEC + if (hDecoder->object_type != LD) { +#endif + if (hDecoder->frame <= 1) hInfo->samples = 0; +#ifdef LD_DEC + } else { + /* LD encoders will give lower delay */ + if (hDecoder->frame <= 0) hInfo->samples = 0; + } +#endif + /* cleanup */ +#ifdef ANALYSIS + fflush(stdout); +#endif +#ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->cycles += count; +#endif + return sample_buffer; +error: +#ifdef DRM + hDecoder->error_state = ERROR_STATE_INIT; +#endif + /* reset filterbank state */ + for (i = 0; i < MAX_CHANNELS; i++) { + if (hDecoder->fb_intermed[i] != NULL) { memset(hDecoder->fb_intermed[i], 0, hDecoder->frameLength * sizeof(real_t)); } + } +#ifdef SBR_DEC + for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++) { + if (hDecoder->sbr[i] != NULL) { sbrReset(hDecoder->sbr[i], i); } + } +#endif + faad_endbits(&ld); + /* cleanup */ +#ifdef ANALYSIS + fflush(stdout); +#endif + return NULL; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::faad_check_CRC(bitfile* ld, uint16_t len) { + int bytes, rem; + int32_t CRC; + int32_t r = 255; /* Initialize to all ones */ + /* CRC polynome used x^8 + x^4 + x^3 + x^2 +1 */ +#define GPOLY 0435 + faad_rewindbits(ld); + CRC = (int32_t)~faad_getbits(ld, 8) & 0xFF; /* CRC is stored inverted */ + bytes = len >> 3; + rem = len & 0x7; + for (; bytes > 0; bytes--) { r = crc_table_G8[(r ^ faad_getbits(ld, 8)) & 0xFF]; } + for (; rem > 0; rem--) { r = ((r << 1) ^ (((faad_get1bit(ld) & 1) ^ ((r >> 7) & 1)) * GPOLY)) & 0xFF; } + if (r != CRC) + // if (0) + { + return 28; + } else { + return 0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* initialize buffer, call once before first getbits or showbits */ +void NeaacDecoder::faad_initbits(bitfile* ld, const void* _buffer, const uint32_t buffer_size) { + uint32_t tmp; + if (ld == NULL) return; + // useless + // memset(ld, 0, sizeof(bitfile)); + if (buffer_size == 0 || _buffer == NULL) { + ld->error = 1; + return; + } + ld->buffer = _buffer; + ld->buffer_size = buffer_size; + ld->bytes_left = buffer_size; + if (ld->bytes_left >= 4) { + tmp = getdword((uint32_t*)ld->buffer); + ld->bytes_left -= 4; + } else { + tmp = getdword_n((uint32_t*)ld->buffer, ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufa = tmp; + if (ld->bytes_left >= 4) { + tmp = getdword((uint32_t*)ld->buffer + 1); + ld->bytes_left -= 4; + } else { + tmp = getdword_n((uint32_t*)ld->buffer + 1, ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufb = tmp; + ld->start = (uint32_t*)ld->buffer; + ld->tail = ((uint32_t*)ld->buffer + 2); + ld->bits_left = 32; + ld->error = 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_endbits(bitfile* ld) { + // void +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::faad_get_processed_bits(bitfile* ld) { + return (uint32_t)(8 * (4 * (ld->tail - ld->start) - 4) - (ld->bits_left)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::faad_byte_align(bitfile* ld) { + int remainder = (32 - ld->bits_left) & 0x7; + if (remainder) { + faad_flushbits(ld, 8 - remainder); + return (uint8_t)(8 - remainder); + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_flushbits_ex(bitfile* ld, uint32_t bits) { + uint32_t tmp; + ld->bufa = ld->bufb; + if (ld->bytes_left >= 4) { + tmp = getdword(ld->tail); + ld->bytes_left -= 4; + } else { + tmp = getdword_n(ld->tail, ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufb = tmp; + ld->tail++; + ld->bits_left += (32 - bits); + // ld->bytes_left -= 4; + // if (ld->bytes_left == 0) + // ld->no_more_reading = 1; + // if (ld->bytes_left < 0) + // ld->error = 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* rewind to beginning */ +void NeaacDecoder::faad_rewindbits(bitfile* ld) { + uint32_t tmp; + ld->bytes_left = ld->buffer_size; + if (ld->bytes_left >= 4) { + tmp = getdword((uint32_t*)&ld->start[0]); + ld->bytes_left -= 4; + } else { + tmp = getdword_n((uint32_t*)&ld->start[0], ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufa = tmp; + if (ld->bytes_left >= 4) { + tmp = getdword((uint32_t*)&ld->start[1]); + ld->bytes_left -= 4; + } else { + tmp = getdword_n((uint32_t*)&ld->start[1], ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufb = tmp; + ld->bits_left = 32; + ld->tail = &ld->start[2]; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* reset to a certain point */ +void NeaacDecoder::faad_resetbits(bitfile* ld, int bits) { + uint32_t tmp; + int words = bits >> 5; + int remainder = bits & 0x1F; + if (ld->buffer_size < words * 4) + ld->bytes_left = 0; + else + ld->bytes_left = ld->buffer_size - words * 4; + if (ld->bytes_left >= 4) { + tmp = getdword(&ld->start[words]); + ld->bytes_left -= 4; + } else { + tmp = getdword_n(&ld->start[words], ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufa = tmp; + if (ld->bytes_left >= 4) { + tmp = getdword(&ld->start[words + 1]); + ld->bytes_left -= 4; + } else { + tmp = getdword_n(&ld->start[words + 1], ld->bytes_left); + ld->bytes_left = 0; + } + ld->bufb = tmp; + ld->bits_left = 32 - remainder; + ld->tail = &ld->start[words + 2]; + /* recheck for reading too many bytes */ + ld->error = 0; + // if (ld->bytes_left == 0) + // ld->no_more_reading = 1; + // if (ld->bytes_left < 0) + // ld->error = 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t* NeaacDecoder::faad_getbitbuffer(bitfile* ld, uint32_t bits) { + int i; + int32_t temp; + int bytes = bits >> 3; + int remainder = bits & 0x7; + uint8_t* buffer = (uint8_t*)faad_malloc((bytes + 1) * sizeof(uint8_t)); + for (i = 0; i < bytes; i++) { buffer[i] = (uint8_t)faad_getbits(ld, 8); } + if (remainder) { + temp = faad_getbits(ld, remainder) << (8 - remainder); + buffer[bytes] = (uint8_t)temp; + } + return buffer; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* return the original data buffer */ +void* NeaacDecoder::faad_origbitbuffer(bitfile* ld) { + return (void*)ld->start; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* return the original data buffer size */ +uint32_t NeaacDecoder::faad_origbitbuffer_size(bitfile* ld) { + return ld->buffer_size; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* reversed bit reading routines, used for RVLC and HCR */ +void NeaacDecoder::faad_initbits_rev(bitfile* ld, void* buffer, uint32_t bits_in_buffer) { + uint32_t tmp; + int32_t index; + ld->buffer_size = bit2byte(bits_in_buffer); + index = (bits_in_buffer + 31) / 32 - 1; + ld->start = (uint32_t*)buffer + index - 2; + tmp = getdword((uint32_t*)buffer + index); + ld->bufa = tmp; + tmp = getdword((uint32_t*)buffer + index - 1); + ld->bufb = tmp; + ld->tail = (uint32_t*)buffer + index; + ld->bits_left = bits_in_buffer % 32; + if (ld->bits_left == 0) ld->bits_left = 32; + ld->bytes_left = ld->buffer_size; + ld->error = 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::faad_showbits(bitfile* ld, uint32_t bits) { + if (bits <= ld->bits_left) { + // return (ld->bufa >> (ld->bits_left - bits)) & bitmask[bits]; + return (ld->bufa << (32 - ld->bits_left)) >> (32 - bits); + } + bits -= ld->bits_left; + // return ((ld->bufa & bitmask[ld->bits_left]) << bits) | (ld->bufb >> (32 - bits)); + return ((ld->bufa & ((1 << ld->bits_left) - 1)) << bits) | (ld->bufb >> (32 - bits)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_flushbits(bitfile* ld, uint32_t bits) { + /* do nothing if error */ + if (ld->error != 0) return; + if (bits < ld->bits_left) { + ld->bits_left -= bits; + } else { + faad_flushbits_ex(ld, bits); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* reversed bitreading routines */ +uint32_t NeaacDecoder::faad_showbits_rev(bitfile* ld, uint32_t bits) { + uint8_t i; + uint32_t B = 0; + if (bits <= ld->bits_left) { + for (i = 0; i < bits; i++) { + if (ld->bufa & (1 << (i + (32 - ld->bits_left)))) B |= (1 << (bits - i - 1)); + } + return B; + } else { + for (i = 0; i < ld->bits_left; i++) { + if (ld->bufa & (1 << (i + (32 - ld->bits_left)))) B |= (1 << (bits - i - 1)); + } + for (i = 0; i < bits - ld->bits_left; i++) { + if (ld->bufb & (1 << (i + (32 - ld->bits_left)))) B |= (1 << (bits - ld->bits_left - i - 1)); + } + return B; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_flushbits_rev(bitfile* ld, uint32_t bits) { + /* do nothing if error */ + if (ld->error != 0) return; + if (bits < ld->bits_left) { + ld->bits_left -= bits; + } else { + uint32_t tmp; + ld->bufa = ld->bufb; + tmp = getdword(ld->start); + ld->bufb = tmp; + ld->start--; + ld->bits_left += (32 - bits); + if (ld->bytes_left < 4) { + ld->error = 1; + ld->bytes_left = 0; + } else { + ld->bytes_left -= 4; + } + // if (ld->bytes_left == 0) + // ld->no_more_reading = 1; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::faad_getbits_rev(bitfile* ld, uint32_t n) { + uint32_t ret; + if (n == 0) return 0; + ret = faad_showbits_rev(ld, n); + faad_flushbits_rev(ld, n); +#ifdef ANALYSIS + if (print) fprintf(stdout, "%4d %2d bits, val: %4d, variable: %d %s\n", dbg_count++, n, ret, var, dbg); +#endif + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +uint32_t NeaacDecoder::showbits_hcr(bits_t* ld, uint8_t bits) { + if (bits == 0) return 0; + if (ld->len <= 32) { + /* huffman_spectral_data_2 needs to read more than may be available, bits maybe + > ld->len, deliver 0 than */ + if (ld->len >= bits) + return ((ld->bufa >> (ld->len - bits)) & (0xFFFFFFFF >> (32 - bits))); + else + return ((ld->bufa << (bits - ld->len)) & (0xFFFFFFFF >> (32 - bits))); + } else { + if ((ld->len - bits) < 32) { + return ((ld->bufb & (0xFFFFFFFF >> (64 - ld->len))) << (bits - ld->len + 32)) | (ld->bufa >> (ld->len - bits)); + } else { + return ((ld->bufb >> (ld->len - bits - 32)) & (0xFFFFFFFF >> (32 - bits))); + } + } +} +#endif /*ERROR_RESILIENCE*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +/* return 1 if position is outside of buffer, 0 otherwise */ +int8_t NeaacDecoder::flushbits_hcr(bits_t* ld, uint8_t bits) { + ld->len -= bits; + if (ld->len < 0) { + ld->len = 0; + return 1; + } else { + return 0; + } +} +#endif /*ERROR_RESILIENCE*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +int8_t NeaacDecoder::getbits_hcr(bits_t* ld, uint8_t n, uint32_t* result) { + *result = showbits_hcr(ld, n); + return flushbits_hcr(ld, n); +} +#endif /*ERROR_RESILIENCE*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +int8_t NeaacDecoder::get1bit_hcr(bits_t* ld, uint8_t* result) { + uint32_t res; + int8_t ret; + ret = getbits_hcr(ld, 1, &res); + *result = (int8_t)(res & 1); + return ret; +} +#endif /*ERROR_RESILIENCE*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::faad_get1bit(bitfile* ld) { + uint8_t r; + if (ld->bits_left > 0) { + ld->bits_left--; + r = (uint8_t)((ld->bufa >> ld->bits_left) & 1); + return r; + } + /* bits_left == 0 */ +#if 0 + r = (uint8_t)(ld->bufb >> 31); + faad_flushbits_ex(ld, 1); +#else + r = (uint8_t)faad_getbits(ld, 1); +#endif + return r; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::faad_getbits(bitfile* ld, uint32_t n) { + uint32_t ret; + if (n == 0) return 0; + ret = faad_showbits(ld, n); + faad_flushbits(ld, n); +#ifdef ANALYSIS + if (print) fprintf(stdout, "%4d %2d bits, val: %4d, variable: %d %s\n", dbg_count++, n, ret, var, dbg); +#endif + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::getdword(void* mem) { + uint32_t tmp; +#ifndef ARCH_IS_BIG_ENDIAN + ((uint8_t*)&tmp)[0] = ((uint8_t*)mem)[3]; + ((uint8_t*)&tmp)[1] = ((uint8_t*)mem)[2]; + ((uint8_t*)&tmp)[2] = ((uint8_t*)mem)[1]; + ((uint8_t*)&tmp)[3] = ((uint8_t*)mem)[0]; +#else + ((uint8_t*)&tmp)[0] = ((uint8_t*)mem)[0]; + ((uint8_t*)&tmp)[1] = ((uint8_t*)mem)[1]; + ((uint8_t*)&tmp)[2] = ((uint8_t*)mem)[2]; + ((uint8_t*)&tmp)[3] = ((uint8_t*)mem)[3]; +#endif + return tmp; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* reads only n bytes from the stream instead of the standard 4 */ +uint32_t NeaacDecoder::getdword_n(void* mem, int n) { + uint32_t tmp = 0; +#ifndef ARCH_IS_BIG_ENDIAN + switch (n) { + case 3: ((uint8_t*)&tmp)[1] = ((uint8_t*)mem)[2]; /* fallthrough */ + case 2: ((uint8_t*)&tmp)[2] = ((uint8_t*)mem)[1]; /* fallthrough */ + case 1: ((uint8_t*)&tmp)[3] = ((uint8_t*)mem)[0]; + default: break; + } +#else + switch (n) { + case 3: ((uint8_t*)&tmp)[2] = ((uint8_t*)mem)[2]; /* fallthrough */ + case 2: ((uint8_t*)&tmp)[1] = ((uint8_t*)mem)[1]; /* fallthrough */ + case 1: ((uint8_t*)&tmp)[0] = ((uint8_t*)mem)[0]; + default: break; + } +#endif + return tmp; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/*---------------------------------------------------------------------- + passf2, passf3, passf4, passf5. Complex FFT passes fwd and bwd. + ----------------------------------------------------------------------*/ +// ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf2pos(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa) { + uint16_t i, k, ah, ac; + if (ido == 1) { + for (k = 0; k < l1; k++) { + ah = 2 * k; + ac = 4 * k; + RE(ch[ah]) = RE(cc[ac]) + RE(cc[ac + 1]); + RE(ch[ah + l1]) = RE(cc[ac]) - RE(cc[ac + 1]); + IM(ch[ah]) = IM(cc[ac]) + IM(cc[ac + 1]); + IM(ch[ah + l1]) = IM(cc[ac]) - IM(cc[ac + 1]); + } + } else { + for (k = 0; k < l1; k++) { + ah = k * ido; + ac = 2 * k * ido; + for (i = 0; i < ido; i++) { + complex_t t2; + RE(ch[ah + i]) = RE(cc[ac + i]) + RE(cc[ac + i + ido]); + RE(t2) = RE(cc[ac + i]) - RE(cc[ac + i + ido]); + IM(ch[ah + i]) = IM(cc[ac + i]) + IM(cc[ac + i + ido]); + IM(t2) = IM(cc[ac + i]) - IM(cc[ac + i + ido]); +#if 1 + ComplexMult(&IM(ch[ah + i + l1 * ido]), &RE(ch[ah + i + l1 * ido]), IM(t2), RE(t2), RE(wa[i]), IM(wa[i])); +#else + ComplexMult(&RE(ch[ah + i + l1 * ido]), &IM(ch[ah + i + l1 * ido]), RE(t2), IM(t2), RE(wa[i]), IM(wa[i])); +#endif + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf2neg(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa) { + uint16_t i, k, ah, ac; + if (ido == 1) { + for (k = 0; k < l1; k++) { + ah = 2 * k; + ac = 4 * k; + RE(ch[ah]) = RE(cc[ac]) + RE(cc[ac + 1]); + RE(ch[ah + l1]) = RE(cc[ac]) - RE(cc[ac + 1]); + IM(ch[ah]) = IM(cc[ac]) + IM(cc[ac + 1]); + IM(ch[ah + l1]) = IM(cc[ac]) - IM(cc[ac + 1]); + } + } else { + for (k = 0; k < l1; k++) { + ah = k * ido; + ac = 2 * k * ido; + for (i = 0; i < ido; i++) { + complex_t t2; + RE(ch[ah + i]) = RE(cc[ac + i]) + RE(cc[ac + i + ido]); + RE(t2) = RE(cc[ac + i]) - RE(cc[ac + i + ido]); + IM(ch[ah + i]) = IM(cc[ac + i]) + IM(cc[ac + i + ido]); + IM(t2) = IM(cc[ac + i]) - IM(cc[ac + i + ido]); +#if 1 + ComplexMult(&RE(ch[ah + i + l1 * ido]), &IM(ch[ah + i + l1 * ido]), RE(t2), IM(t2), RE(wa[i]), IM(wa[i])); +#else + ComplexMult(&IM(ch[ah + i + l1 * ido]), &RE(ch[ah + i + l1 * ido]), IM(t2), RE(t2), RE(wa[i]), IM(wa[i])); +#endif + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf3(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const int8_t isign) { + real_t taur = FRAC_CONST(-0.5); + real_t taui = FRAC_CONST(0.866025403784439); + uint16_t i, k, ac, ah; + complex_t c2, c3, d2, d3, t2; + if (ido == 1) { + if (isign == 1) { + for (k = 0; k < l1; k++) { + ac = 3 * k + 1; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 1]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 1]); + RE(c2) = RE(cc[ac - 1]) + MUL_F(RE(t2), taur); + IM(c2) = IM(cc[ac - 1]) + MUL_F(IM(t2), taur); + RE(ch[ah]) = RE(cc[ac - 1]) + RE(t2); + IM(ch[ah]) = IM(cc[ac - 1]) + IM(t2); + RE(c3) = MUL_F((RE(cc[ac]) - RE(cc[ac + 1])), taui); + IM(c3) = MUL_F((IM(cc[ac]) - IM(cc[ac + 1])), taui); + RE(ch[ah + l1]) = RE(c2) - IM(c3); + IM(ch[ah + l1]) = IM(c2) + RE(c3); + RE(ch[ah + 2 * l1]) = RE(c2) + IM(c3); + IM(ch[ah + 2 * l1]) = IM(c2) - RE(c3); + } + } else { + for (k = 0; k < l1; k++) { + ac = 3 * k + 1; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 1]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 1]); + RE(c2) = RE(cc[ac - 1]) + MUL_F(RE(t2), taur); + IM(c2) = IM(cc[ac - 1]) + MUL_F(IM(t2), taur); + RE(ch[ah]) = RE(cc[ac - 1]) + RE(t2); + IM(ch[ah]) = IM(cc[ac - 1]) + IM(t2); + RE(c3) = MUL_F((RE(cc[ac]) - RE(cc[ac + 1])), taui); + IM(c3) = MUL_F((IM(cc[ac]) - IM(cc[ac + 1])), taui); + RE(ch[ah + l1]) = RE(c2) + IM(c3); + IM(ch[ah + l1]) = IM(c2) - RE(c3); + RE(ch[ah + 2 * l1]) = RE(c2) - IM(c3); + IM(ch[ah + 2 * l1]) = IM(c2) + RE(c3); + } + } + } else { + if (isign == 1) { + for (k = 0; k < l1; k++) { + for (i = 0; i < ido; i++) { + ac = i + (3 * k + 1) * ido; + ah = i + k * ido; + RE(t2) = RE(cc[ac]) + RE(cc[ac + ido]); + RE(c2) = RE(cc[ac - ido]) + MUL_F(RE(t2), taur); + IM(t2) = IM(cc[ac]) + IM(cc[ac + ido]); + IM(c2) = IM(cc[ac - ido]) + MUL_F(IM(t2), taur); + RE(ch[ah]) = RE(cc[ac - ido]) + RE(t2); + IM(ch[ah]) = IM(cc[ac - ido]) + IM(t2); + RE(c3) = MUL_F((RE(cc[ac]) - RE(cc[ac + ido])), taui); + IM(c3) = MUL_F((IM(cc[ac]) - IM(cc[ac + ido])), taui); + RE(d2) = RE(c2) - IM(c3); + IM(d3) = IM(c2) - RE(c3); + RE(d3) = RE(c2) + IM(c3); + IM(d2) = IM(c2) + RE(c3); +#if 1 + ComplexMult(&IM(ch[ah + l1 * ido]), &RE(ch[ah + l1 * ido]), IM(d2), RE(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + 2 * l1 * ido]), &RE(ch[ah + 2 * l1 * ido]), IM(d3), RE(d3), RE(wa2[i]), IM(wa2[i])); +#else + ComplexMult(&RE(ch[ah + l1 * ido]), &IM(ch[ah + l1 * ido]), RE(d2), IM(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + 2 * l1 * ido]), &IM(ch[ah + 2 * l1 * ido]), RE(d3), IM(d3), RE(wa2[i]), IM(wa2[i])); +#endif + } + } + } else { + for (k = 0; k < l1; k++) { + for (i = 0; i < ido; i++) { + ac = i + (3 * k + 1) * ido; + ah = i + k * ido; + RE(t2) = RE(cc[ac]) + RE(cc[ac + ido]); + RE(c2) = RE(cc[ac - ido]) + MUL_F(RE(t2), taur); + IM(t2) = IM(cc[ac]) + IM(cc[ac + ido]); + IM(c2) = IM(cc[ac - ido]) + MUL_F(IM(t2), taur); + RE(ch[ah]) = RE(cc[ac - ido]) + RE(t2); + IM(ch[ah]) = IM(cc[ac - ido]) + IM(t2); + RE(c3) = MUL_F((RE(cc[ac]) - RE(cc[ac + ido])), taui); + IM(c3) = MUL_F((IM(cc[ac]) - IM(cc[ac + ido])), taui); + RE(d2) = RE(c2) + IM(c3); + IM(d3) = IM(c2) + RE(c3); + RE(d3) = RE(c2) - IM(c3); + IM(d2) = IM(c2) - RE(c3); +#if 1 + ComplexMult(&RE(ch[ah + l1 * ido]), &IM(ch[ah + l1 * ido]), RE(d2), IM(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + 2 * l1 * ido]), &IM(ch[ah + 2 * l1 * ido]), RE(d3), IM(d3), RE(wa2[i]), IM(wa2[i])); +#else + ComplexMult(&IM(ch[ah + l1 * ido]), &RE(ch[ah + l1 * ido]), IM(d2), RE(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + 2 * l1 * ido]), &RE(ch[ah + 2 * l1 * ido]), IM(d3), RE(d3), RE(wa2[i]), IM(wa2[i])); +#endif + } + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf4pos(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3) { + uint16_t i, k, ac, ah; + if (ido == 1) { + for (k = 0; k < l1; k++) { + complex_t t1, t2, t3, t4; + ac = 4 * k; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 2]); + RE(t1) = RE(cc[ac]) - RE(cc[ac + 2]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 2]); + IM(t1) = IM(cc[ac]) - IM(cc[ac + 2]); + RE(t3) = RE(cc[ac + 1]) + RE(cc[ac + 3]); + IM(t4) = RE(cc[ac + 1]) - RE(cc[ac + 3]); + IM(t3) = IM(cc[ac + 3]) + IM(cc[ac + 1]); + RE(t4) = IM(cc[ac + 3]) - IM(cc[ac + 1]); + RE(ch[ah]) = RE(t2) + RE(t3); + RE(ch[ah + 2 * l1]) = RE(t2) - RE(t3); + IM(ch[ah]) = IM(t2) + IM(t3); + IM(ch[ah + 2 * l1]) = IM(t2) - IM(t3); + RE(ch[ah + l1]) = RE(t1) + RE(t4); + RE(ch[ah + 3 * l1]) = RE(t1) - RE(t4); + IM(ch[ah + l1]) = IM(t1) + IM(t4); + IM(ch[ah + 3 * l1]) = IM(t1) - IM(t4); + } + } else { + for (k = 0; k < l1; k++) { + ac = 4 * k * ido; + ah = k * ido; + for (i = 0; i < ido; i++) { + complex_t c2, c3, c4, t1, t2, t3, t4; + RE(t2) = RE(cc[ac + i]) + RE(cc[ac + i + 2 * ido]); + RE(t1) = RE(cc[ac + i]) - RE(cc[ac + i + 2 * ido]); + IM(t2) = IM(cc[ac + i]) + IM(cc[ac + i + 2 * ido]); + IM(t1) = IM(cc[ac + i]) - IM(cc[ac + i + 2 * ido]); + RE(t3) = RE(cc[ac + i + ido]) + RE(cc[ac + i + 3 * ido]); + IM(t4) = RE(cc[ac + i + ido]) - RE(cc[ac + i + 3 * ido]); + IM(t3) = IM(cc[ac + i + 3 * ido]) + IM(cc[ac + i + ido]); + RE(t4) = IM(cc[ac + i + 3 * ido]) - IM(cc[ac + i + ido]); + RE(c2) = RE(t1) + RE(t4); + RE(c4) = RE(t1) - RE(t4); + IM(c2) = IM(t1) + IM(t4); + IM(c4) = IM(t1) - IM(t4); + RE(ch[ah + i]) = RE(t2) + RE(t3); + RE(c3) = RE(t2) - RE(t3); + IM(ch[ah + i]) = IM(t2) + IM(t3); + IM(c3) = IM(t2) - IM(t3); +#if 1 + ComplexMult(&IM(ch[ah + i + l1 * ido]), &RE(ch[ah + i + l1 * ido]), IM(c2), RE(c2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + i + 2 * l1 * ido]), &RE(ch[ah + i + 2 * l1 * ido]), IM(c3), RE(c3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&IM(ch[ah + i + 3 * l1 * ido]), &RE(ch[ah + i + 3 * l1 * ido]), IM(c4), RE(c4), RE(wa3[i]), IM(wa3[i])); +#else + ComplexMult(&RE(ch[ah + i + l1 * ido]), &IM(ch[ah + i + l1 * ido]), RE(c2), IM(c2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + i + 2 * l1 * ido]), &IM(ch[ah + i + 2 * l1 * ido]), RE(c3), IM(c3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&RE(ch[ah + i + 3 * l1 * ido]), &IM(ch[ah + i + 3 * l1 * ido]), RE(c4), IM(c4), RE(wa3[i]), IM(wa3[i])); +#endif + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf4neg(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3) { + uint16_t i, k, ac, ah; + if (ido == 1) { + for (k = 0; k < l1; k++) { + complex_t t1, t2, t3, t4; + ac = 4 * k; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 2]); + RE(t1) = RE(cc[ac]) - RE(cc[ac + 2]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 2]); + IM(t1) = IM(cc[ac]) - IM(cc[ac + 2]); + RE(t3) = RE(cc[ac + 1]) + RE(cc[ac + 3]); + IM(t4) = RE(cc[ac + 1]) - RE(cc[ac + 3]); + IM(t3) = IM(cc[ac + 3]) + IM(cc[ac + 1]); + RE(t4) = IM(cc[ac + 3]) - IM(cc[ac + 1]); + RE(ch[ah]) = RE(t2) + RE(t3); + RE(ch[ah + 2 * l1]) = RE(t2) - RE(t3); + IM(ch[ah]) = IM(t2) + IM(t3); + IM(ch[ah + 2 * l1]) = IM(t2) - IM(t3); + RE(ch[ah + l1]) = RE(t1) - RE(t4); + RE(ch[ah + 3 * l1]) = RE(t1) + RE(t4); + IM(ch[ah + l1]) = IM(t1) - IM(t4); + IM(ch[ah + 3 * l1]) = IM(t1) + IM(t4); + } + } else { + for (k = 0; k < l1; k++) { + ac = 4 * k * ido; + ah = k * ido; + for (i = 0; i < ido; i++) { + complex_t c2, c3, c4, t1, t2, t3, t4; + RE(t2) = RE(cc[ac + i]) + RE(cc[ac + i + 2 * ido]); + RE(t1) = RE(cc[ac + i]) - RE(cc[ac + i + 2 * ido]); + IM(t2) = IM(cc[ac + i]) + IM(cc[ac + i + 2 * ido]); + IM(t1) = IM(cc[ac + i]) - IM(cc[ac + i + 2 * ido]); + RE(t3) = RE(cc[ac + i + ido]) + RE(cc[ac + i + 3 * ido]); + IM(t4) = RE(cc[ac + i + ido]) - RE(cc[ac + i + 3 * ido]); + IM(t3) = IM(cc[ac + i + 3 * ido]) + IM(cc[ac + i + ido]); + RE(t4) = IM(cc[ac + i + 3 * ido]) - IM(cc[ac + i + ido]); + RE(c2) = RE(t1) - RE(t4); + RE(c4) = RE(t1) + RE(t4); + IM(c2) = IM(t1) - IM(t4); + IM(c4) = IM(t1) + IM(t4); + RE(ch[ah + i]) = RE(t2) + RE(t3); + RE(c3) = RE(t2) - RE(t3); + IM(ch[ah + i]) = IM(t2) + IM(t3); + IM(c3) = IM(t2) - IM(t3); +#if 1 + ComplexMult(&RE(ch[ah + i + l1 * ido]), &IM(ch[ah + i + l1 * ido]), RE(c2), IM(c2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + i + 2 * l1 * ido]), &IM(ch[ah + i + 2 * l1 * ido]), RE(c3), IM(c3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&RE(ch[ah + i + 3 * l1 * ido]), &IM(ch[ah + i + 3 * l1 * ido]), RE(c4), IM(c4), RE(wa3[i]), IM(wa3[i])); +#else + ComplexMult(&IM(ch[ah + i + l1 * ido]), &RE(ch[ah + i + l1 * ido]), IM(c2), RE(c2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + i + 2 * l1 * ido]), &RE(ch[ah + i + 2 * l1 * ido]), IM(c3), RE(c3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&IM(ch[ah + i + 3 * l1 * ido]), &RE(ch[ah + i + 3 * l1 * ido]), IM(c4), RE(c4), RE(wa3[i]), IM(wa3[i])); +#endif + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::passf5(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3, const complex_t* wa4, + const int8_t isign) { + real_t tr11 = FRAC_CONST(0.309016994374947); + real_t ti11 = FRAC_CONST(0.951056516295154); + real_t tr12 = FRAC_CONST(-0.809016994374947); + real_t ti12 = FRAC_CONST(0.587785252292473); + uint16_t i, k, ac, ah; + complex_t c2, c3, c4, c5, d3, d4, d5, d2, t2, t3, t4, t5; + if (ido == 1) { + if (isign == 1) { + for (k = 0; k < l1; k++) { + ac = 5 * k + 1; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 3]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 3]); + RE(t3) = RE(cc[ac + 1]) + RE(cc[ac + 2]); + IM(t3) = IM(cc[ac + 1]) + IM(cc[ac + 2]); + RE(t4) = RE(cc[ac + 1]) - RE(cc[ac + 2]); + IM(t4) = IM(cc[ac + 1]) - IM(cc[ac + 2]); + RE(t5) = RE(cc[ac]) - RE(cc[ac + 3]); + IM(t5) = IM(cc[ac]) - IM(cc[ac + 3]); + RE(ch[ah]) = RE(cc[ac - 1]) + RE(t2) + RE(t3); + IM(ch[ah]) = IM(cc[ac - 1]) + IM(t2) + IM(t3); + RE(c2) = RE(cc[ac - 1]) + MUL_F(RE(t2), tr11) + MUL_F(RE(t3), tr12); + IM(c2) = IM(cc[ac - 1]) + MUL_F(IM(t2), tr11) + MUL_F(IM(t3), tr12); + RE(c3) = RE(cc[ac - 1]) + MUL_F(RE(t2), tr12) + MUL_F(RE(t3), tr11); + IM(c3) = IM(cc[ac - 1]) + MUL_F(IM(t2), tr12) + MUL_F(IM(t3), tr11); + ComplexMult(&RE(c5), &RE(c4), ti11, ti12, RE(t5), RE(t4)); + ComplexMult(&IM(c5), &IM(c4), ti11, ti12, IM(t5), IM(t4)); + RE(ch[ah + l1]) = RE(c2) - IM(c5); + IM(ch[ah + l1]) = IM(c2) + RE(c5); + RE(ch[ah + 2 * l1]) = RE(c3) - IM(c4); + IM(ch[ah + 2 * l1]) = IM(c3) + RE(c4); + RE(ch[ah + 3 * l1]) = RE(c3) + IM(c4); + IM(ch[ah + 3 * l1]) = IM(c3) - RE(c4); + RE(ch[ah + 4 * l1]) = RE(c2) + IM(c5); + IM(ch[ah + 4 * l1]) = IM(c2) - RE(c5); + } + } else { + for (k = 0; k < l1; k++) { + ac = 5 * k + 1; + ah = k; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 3]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 3]); + RE(t3) = RE(cc[ac + 1]) + RE(cc[ac + 2]); + IM(t3) = IM(cc[ac + 1]) + IM(cc[ac + 2]); + RE(t4) = RE(cc[ac + 1]) - RE(cc[ac + 2]); + IM(t4) = IM(cc[ac + 1]) - IM(cc[ac + 2]); + RE(t5) = RE(cc[ac]) - RE(cc[ac + 3]); + IM(t5) = IM(cc[ac]) - IM(cc[ac + 3]); + RE(ch[ah]) = RE(cc[ac - 1]) + RE(t2) + RE(t3); + IM(ch[ah]) = IM(cc[ac - 1]) + IM(t2) + IM(t3); + RE(c2) = RE(cc[ac - 1]) + MUL_F(RE(t2), tr11) + MUL_F(RE(t3), tr12); + IM(c2) = IM(cc[ac - 1]) + MUL_F(IM(t2), tr11) + MUL_F(IM(t3), tr12); + RE(c3) = RE(cc[ac - 1]) + MUL_F(RE(t2), tr12) + MUL_F(RE(t3), tr11); + IM(c3) = IM(cc[ac - 1]) + MUL_F(IM(t2), tr12) + MUL_F(IM(t3), tr11); + ComplexMult(&RE(c4), &RE(c5), ti12, ti11, RE(t5), RE(t4)); + ComplexMult(&IM(c4), &IM(c5), ti12, ti11, IM(t5), IM(t4)); + RE(ch[ah + l1]) = RE(c2) + IM(c5); + IM(ch[ah + l1]) = IM(c2) - RE(c5); + RE(ch[ah + 2 * l1]) = RE(c3) + IM(c4); + IM(ch[ah + 2 * l1]) = IM(c3) - RE(c4); + RE(ch[ah + 3 * l1]) = RE(c3) - IM(c4); + IM(ch[ah + 3 * l1]) = IM(c3) + RE(c4); + RE(ch[ah + 4 * l1]) = RE(c2) - IM(c5); + IM(ch[ah + 4 * l1]) = IM(c2) + RE(c5); + } + } + } else { + if (isign == 1) { + for (k = 0; k < l1; k++) { + for (i = 0; i < ido; i++) { + ac = i + (k * 5 + 1) * ido; + ah = i + k * ido; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 3 * ido]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 3 * ido]); + RE(t3) = RE(cc[ac + ido]) + RE(cc[ac + 2 * ido]); + IM(t3) = IM(cc[ac + ido]) + IM(cc[ac + 2 * ido]); + RE(t4) = RE(cc[ac + ido]) - RE(cc[ac + 2 * ido]); + IM(t4) = IM(cc[ac + ido]) - IM(cc[ac + 2 * ido]); + RE(t5) = RE(cc[ac]) - RE(cc[ac + 3 * ido]); + IM(t5) = IM(cc[ac]) - IM(cc[ac + 3 * ido]); + RE(ch[ah]) = RE(cc[ac - ido]) + RE(t2) + RE(t3); + IM(ch[ah]) = IM(cc[ac - ido]) + IM(t2) + IM(t3); + RE(c2) = RE(cc[ac - ido]) + MUL_F(RE(t2), tr11) + MUL_F(RE(t3), tr12); + IM(c2) = IM(cc[ac - ido]) + MUL_F(IM(t2), tr11) + MUL_F(IM(t3), tr12); + RE(c3) = RE(cc[ac - ido]) + MUL_F(RE(t2), tr12) + MUL_F(RE(t3), tr11); + IM(c3) = IM(cc[ac - ido]) + MUL_F(IM(t2), tr12) + MUL_F(IM(t3), tr11); + ComplexMult(&RE(c5), &RE(c4), ti11, ti12, RE(t5), RE(t4)); + ComplexMult(&IM(c5), &IM(c4), ti11, ti12, IM(t5), IM(t4)); + IM(d2) = IM(c2) + RE(c5); + IM(d3) = IM(c3) + RE(c4); + RE(d4) = RE(c3) + IM(c4); + RE(d5) = RE(c2) + IM(c5); + RE(d2) = RE(c2) - IM(c5); + IM(d5) = IM(c2) - RE(c5); + RE(d3) = RE(c3) - IM(c4); + IM(d4) = IM(c3) - RE(c4); +#if 1 + ComplexMult(&IM(ch[ah + l1 * ido]), &RE(ch[ah + l1 * ido]), IM(d2), RE(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + 2 * l1 * ido]), &RE(ch[ah + 2 * l1 * ido]), IM(d3), RE(d3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&IM(ch[ah + 3 * l1 * ido]), &RE(ch[ah + 3 * l1 * ido]), IM(d4), RE(d4), RE(wa3[i]), IM(wa3[i])); + ComplexMult(&IM(ch[ah + 4 * l1 * ido]), &RE(ch[ah + 4 * l1 * ido]), IM(d5), RE(d5), RE(wa4[i]), IM(wa4[i])); +#else + ComplexMult(&RE(ch[ah + l1 * ido]), &IM(ch[ah + l1 * ido]), RE(d2), IM(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + 2 * l1 * ido]), &IM(ch[ah + 2 * l1 * ido]), RE(d3), IM(d3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&RE(ch[ah + 3 * l1 * ido]), &IM(ch[ah + 3 * l1 * ido]), RE(d4), IM(d4), RE(wa3[i]), IM(wa3[i])); + ComplexMult(&RE(ch[ah + 4 * l1 * ido]), &IM(ch[ah + 4 * l1 * ido]), RE(d5), IM(d5), RE(wa4[i]), IM(wa4[i])); +#endif + } + } + } else { + for (k = 0; k < l1; k++) { + for (i = 0; i < ido; i++) { + ac = i + (k * 5 + 1) * ido; + ah = i + k * ido; + RE(t2) = RE(cc[ac]) + RE(cc[ac + 3 * ido]); + IM(t2) = IM(cc[ac]) + IM(cc[ac + 3 * ido]); + RE(t3) = RE(cc[ac + ido]) + RE(cc[ac + 2 * ido]); + IM(t3) = IM(cc[ac + ido]) + IM(cc[ac + 2 * ido]); + RE(t4) = RE(cc[ac + ido]) - RE(cc[ac + 2 * ido]); + IM(t4) = IM(cc[ac + ido]) - IM(cc[ac + 2 * ido]); + RE(t5) = RE(cc[ac]) - RE(cc[ac + 3 * ido]); + IM(t5) = IM(cc[ac]) - IM(cc[ac + 3 * ido]); + RE(ch[ah]) = RE(cc[ac - ido]) + RE(t2) + RE(t3); + IM(ch[ah]) = IM(cc[ac - ido]) + IM(t2) + IM(t3); + RE(c2) = RE(cc[ac - ido]) + MUL_F(RE(t2), tr11) + MUL_F(RE(t3), tr12); + IM(c2) = IM(cc[ac - ido]) + MUL_F(IM(t2), tr11) + MUL_F(IM(t3), tr12); + RE(c3) = RE(cc[ac - ido]) + MUL_F(RE(t2), tr12) + MUL_F(RE(t3), tr11); + IM(c3) = IM(cc[ac - ido]) + MUL_F(IM(t2), tr12) + MUL_F(IM(t3), tr11); + ComplexMult(&RE(c4), &RE(c5), ti12, ti11, RE(t5), RE(t4)); + ComplexMult(&IM(c4), &IM(c5), ti12, ti11, IM(t5), IM(t4)); + IM(d2) = IM(c2) - RE(c5); + IM(d3) = IM(c3) - RE(c4); + RE(d4) = RE(c3) - IM(c4); + RE(d5) = RE(c2) - IM(c5); + RE(d2) = RE(c2) + IM(c5); + IM(d5) = IM(c2) + RE(c5); + RE(d3) = RE(c3) + IM(c4); + IM(d4) = IM(c3) + RE(c4); +#if 1 + ComplexMult(&RE(ch[ah + l1 * ido]), &IM(ch[ah + l1 * ido]), RE(d2), IM(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&RE(ch[ah + 2 * l1 * ido]), &IM(ch[ah + 2 * l1 * ido]), RE(d3), IM(d3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&RE(ch[ah + 3 * l1 * ido]), &IM(ch[ah + 3 * l1 * ido]), RE(d4), IM(d4), RE(wa3[i]), IM(wa3[i])); + ComplexMult(&RE(ch[ah + 4 * l1 * ido]), &IM(ch[ah + 4 * l1 * ido]), RE(d5), IM(d5), RE(wa4[i]), IM(wa4[i])); +#else + ComplexMult(&IM(ch[ah + l1 * ido]), &RE(ch[ah + l1 * ido]), IM(d2), RE(d2), RE(wa1[i]), IM(wa1[i])); + ComplexMult(&IM(ch[ah + 2 * l1 * ido]), &RE(ch[ah + 2 * l1 * ido]), IM(d3), RE(d3), RE(wa2[i]), IM(wa2[i])); + ComplexMult(&IM(ch[ah + 3 * l1 * ido]), &RE(ch[ah + 3 * l1 * ido]), IM(d4), RE(d4), RE(wa3[i]), IM(wa3[i])); + ComplexMult(&IM(ch[ah + 4 * l1 * ido]), &RE(ch[ah + 4 * l1 * ido]), IM(d5), RE(d5), RE(wa4[i]), IM(wa4[i])); +#endif + } + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/*---------------------------------------------------------------------- + cfftf1, cfftf, cfftb, cffti1, cffti. Complex FFTs. + ----------------------------------------------------------------------*/ +void NeaacDecoder::cfftf1pos(uint16_t n, complex_t* c, complex_t* ch, const uint16_t* ifac, const complex_t* wa, const int8_t isign) { + uint16_t i; + uint16_t k1, l1, l2; + uint16_t na, nf, ip, iw, ix2, ix3, ix4, ido, idl1; + (void)idl1; + nf = ifac[1]; + na = 0; + l1 = 1; + iw = 0; + for (k1 = 2; k1 <= nf + 1; k1++) { + ip = ifac[k1]; + l2 = ip * l1; + ido = n / l2; + idl1 = ido * l1; + switch (ip) { + case 4: + ix2 = iw + ido; + ix3 = ix2 + ido; + if (na == 0) + passf4pos(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], &wa[ix3]); + else + passf4pos(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], &wa[ix3]); + na = 1 - na; + break; + case 2: + if (na == 0) + passf2pos(ido, l1, (const complex_t*)c, ch, &wa[iw]); + else + passf2pos(ido, 1, (const complex_t*)ch, c, &wa[iw]); + na = 1 - na; + break; + case 3: + ix2 = iw + ido; + if (na == 0) + passf3(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], isign); + else + passf3(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], isign); + na = 1 - na; + break; + case 5: + ix2 = iw + ido; + ix3 = ix2 + ido; + ix4 = ix3 + ido; + if (na == 0) + passf5(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign); + else + passf5(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign); + na = 1 - na; + break; + } + l1 = l2; + iw += (ip - 1) * ido; + } + if (na == 0) return; + for (i = 0; i < n; i++) { + RE(c[i]) = RE(ch[i]); + IM(c[i]) = IM(ch[i]); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::cfftf1neg(uint16_t n, complex_t* c, complex_t* ch, const uint16_t* ifac, const complex_t* wa, const int8_t isign) { + uint16_t i; + uint16_t k1, l1, l2; + uint16_t na, nf, ip, iw, ix2, ix3, ix4, ido, idl1; + (void)idl1; + nf = ifac[1]; + na = 0; + l1 = 1; + iw = 0; + for (k1 = 2; k1 <= nf + 1; k1++) { + ip = ifac[k1]; + l2 = ip * l1; + ido = n / l2; + idl1 = ido * l1; + switch (ip) { + case 4: + ix2 = iw + ido; + ix3 = ix2 + ido; + if (na == 0) + passf4neg(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], &wa[ix3]); + else + passf4neg(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], &wa[ix3]); + na = 1 - na; + break; + case 2: + if (na == 0) + passf2neg(ido, l1, (const complex_t*)c, ch, &wa[iw]); + else + passf2neg(ido, l1, (const complex_t*)ch, c, &wa[iw]); + na = 1 - na; + break; + case 3: + ix2 = iw + ido; + if (na == 0) + passf3(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], isign); + else + passf3(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], isign); + na = 1 - na; + break; + case 5: + ix2 = iw + ido; + ix3 = ix2 + ido; + ix4 = ix3 + ido; + if (na == 0) + passf5(ido, l1, (const complex_t*)c, ch, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign); + else + passf5(ido, l1, (const complex_t*)ch, c, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign); + na = 1 - na; + break; + } + l1 = l2; + iw += (ip - 1) * ido; + } + if (na == 0) return; + for (i = 0; i < n; i++) { + RE(c[i]) = RE(ch[i]); + IM(c[i]) = IM(ch[i]); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::cfftf(uint16_t mdct_len, complex_t* c) { + cfft_info* cfft_select = nullptr; + complex_t* work_select = nullptr; + switch (mdct_len) { + case 256: + cfft_select = m_ccft256.get(); + work_select = m_work256.get(); + break; + case 1024: + cfft_select = m_ccft1024.get(); + work_select = m_work1024.get(); + break; + case 2048: + cfft_select = m_ccft2048.get(); + work_select = m_work2048.get(); + break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + cfftf1neg(cfft_select->n, c, work_select, (const uint16_t*)cfft_select->ifac, (const complex_t*)cfft_select->tab, -1); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::cfftb(uint16_t mdct_len, complex_t* c) { + cfft_info* cfft_select = nullptr; + complex_t* work_select = nullptr; + switch (mdct_len) { + case 256: + cfft_select = m_ccft256.get(); + work_select = m_work256.get(); + break; + case 1024: + cfft_select = m_ccft1024.get(); + work_select = m_work1024.get(); + break; + case 2048: + cfft_select = m_ccft2048.get(); + work_select = m_work2048.get(); + break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + cfftf1pos(cfft_select->n, c, work_select, (const uint16_t*)cfft_select->ifac, (const complex_t*)cfft_select->tab, +1); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::cffti1(uint16_t n, complex_t* wa, uint16_t* ifac) { + uint16_t ntryh[4] = {3, 4, 2, 5}; +#ifndef FIXED_POINT + real_t arg, argh, argld, fi; + uint16_t ido, ipm; + uint16_t i1, k1, l1, l2; + uint16_t ld, ii, ip; +#endif + uint16_t ntry = 0, i, j; + uint16_t ib; + uint16_t nf, nl, nq, nr; + nl = n; + nf = 0; + j = 0; +startloop: + j++; + if (j <= 4) + ntry = ntryh[j - 1]; + else + ntry += 2; + do { + nq = nl / ntry; + nr = nl - ntry * nq; + if (nr != 0) goto startloop; + nf++; + ifac[nf + 1] = ntry; + nl = nq; + if (ntry == 2 && nf != 1) { + for (i = 2; i <= nf; i++) { + ib = nf - i + 2; + ifac[ib + 1] = ifac[ib]; + } + ifac[2] = 2; + } + } while (nl != 1); + ifac[0] = n; + ifac[1] = nf; +#ifndef FIXED_POINT + argh = (real_t)2.0 * (real_t)M_PI / (real_t)n; + i = 0; + l1 = 1; + for (k1 = 1; k1 <= nf; k1++) { + ip = ifac[k1 + 1]; + ld = 0; + l2 = l1 * ip; + ido = n / l2; + ipm = ip - 1; + for (j = 0; j < ipm; j++) { + i1 = i; + RE(wa[i]) = 1.0; + IM(wa[i]) = 0.0; + ld += l1; + fi = 0; + argld = ld * argh; + for (ii = 0; ii < ido; ii++) { + i++; + fi++; + arg = fi * argld; + RE(wa[i]) = (real_t)cos(arg); + #if 1 + IM(wa[i]) = (real_t)sin(arg); + #else + IM(wa[i]) = (real_t)-sin(arg); + #endif + } + if (ip > 5) { + RE(wa[i1]) = RE(wa[i]); + IM(wa[i1]) = IM(wa[i]); + } + } + l1 = l2; + } +#endif +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::cffti(uint16_t mdct_len, uint16_t n) { + cfft_info* cfft_select = nullptr; + + switch (mdct_len) { + case 256: + m_ccft256.alloc("m_ccft256"); + cfft_select = m_ccft256.get(); + m_work256.alloc_array(n * sizeof(complex_t), "m_work256"); + break; + case 1024: + m_ccft1024.alloc("m_ccft1024"); + cfft_select = m_ccft1024.get(); + m_work1024.alloc_array(n * sizeof(complex_t), "m_work1024"); + break; + case 2048: + m_ccft2048.alloc("m_ccft2048"); + cfft_select = m_ccft2048.get(); + m_work2048.alloc_array(n * sizeof(complex_t), "m_work2048"); + break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + cfft_select->n = n; + +#ifndef FIXED_POINT + cfft_select->tab = (complex_t*)faad_malloc(n * sizeof(complex_t)); + cffti1(n, cfft_select->tab, cfft_select->ifac); +#else + cffti1(n, NULL, cfft_select->ifac); + switch (n) { + case 64: cfft_select->tab = (complex_t*)cfft_tab_64; break; + case 512: cfft_select->tab = (complex_t*)cfft_tab_512; break; + #ifdef LD_DEC + case 256: cfft_select->tab = (complex_t*)cfft_tab_256; break; + #endif + #ifdef ALLOW_SMALL_FRAMELENGTH + case 60: cfft_select->tab = (complex_t*)cfft_tab_60; break; + case 480: cfft_select->tab = (complex_t*)cfft_tab_480; break; + #ifdef LD_DEC + case 240: cfft_select->tab = (complex_t*)cfft_tab_240; break; + #endif + #endif + case 128: cfft_select->tab = (complex_t*)cfft_tab_128; break; + } +#endif + return; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +drc_info* NeaacDecoder::drc_init(real_t cut, real_t boost) { + drc_info* drc = (drc_info*)faad_malloc(sizeof(drc_info)); + memset(drc, 0, sizeof(drc_info)); + drc->ctrl1 = cut; + drc->ctrl2 = boost; + drc->num_bands = 1; + drc->band_top[0] = 1024 / 4 - 1; + drc->dyn_rng_sgn[0] = 1; + drc->dyn_rng_ctl[0] = 0; + return drc; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::drc_end(drc_info* drc) { + if (drc) faad_free(&drc); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::drc_decode(drc_info* drc, real_t* spec) { + uint16_t i, bd, top; +#ifdef FIXED_POINT + int32_t exp, frac; +#else + real_t factor, exp; +#endif + uint16_t bottom = 0; + if (drc->num_bands == 1) drc->band_top[0] = 1024 / 4 - 1; + for (bd = 0; bd < drc->num_bands; bd++) { + top = 4 * (drc->band_top[bd] + 1); +#ifndef FIXED_POINT + /* Decode DRC gain factor */ + if (drc->dyn_rng_sgn[bd]) /* compress */ + exp = ((-drc->ctrl1 * drc->dyn_rng_ctl[bd]) - (DRC_REF_LEVEL - drc->prog_ref_level)) / REAL_CONST(24.0); + else /* boost */ + exp = ((drc->ctrl2 * drc->dyn_rng_ctl[bd]) - (DRC_REF_LEVEL - drc->prog_ref_level)) / REAL_CONST(24.0); + factor = (real_t)pow(2.0, exp); + /* Apply gain factor */ + for (i = bottom; i < top; i++) spec[i] *= factor; +#else + /* Decode DRC gain factor */ + if (drc->dyn_rng_sgn[bd]) /* compress */ + { + exp = -1 * (drc->dyn_rng_ctl[bd] - (DRC_REF_LEVEL - drc->prog_ref_level)) / 24; + frac = -1 * (drc->dyn_rng_ctl[bd] - (DRC_REF_LEVEL - drc->prog_ref_level)) % 24; + } else { /* boost */ + exp = (drc->dyn_rng_ctl[bd] - (DRC_REF_LEVEL - drc->prog_ref_level)) / 24; + frac = (drc->dyn_rng_ctl[bd] - (DRC_REF_LEVEL - drc->prog_ref_level)) % 24; + } + /* Apply gain factor */ + if (exp < 0) { + for (i = bottom; i < top; i++) { + spec[i] >>= -exp; + if (frac) spec[i] = MUL_R(spec[i], drc_pow2_table[frac + 23]); + } + } else { + for (i = bottom; i < top; i++) { + spec[i] <<= exp; + if (frac) spec[i] = MUL_R(spec[i], drc_pow2_table[frac + 23]); + } + } +#endif + bottom = top; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* function declarations */ +void NeaacDecoder::drm_ps_sa_element(drm_ps_info* ps, bitfile* ld); +void NeaacDecoder::drm_ps_pan_element(drm_ps_info* ps, bitfile* ld); +int8_t NeaacDecoder::huff_dec(bitfile* ld, drm_ps_huff_tab huff); +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +uint16_t NeaacDecoder::drm_ps_data(drm_ps_info* ps, bitfile* ld) { + uint16_t bits = (uint16_t)faad_get_processed_bits(ld); + ps->drm_ps_data_available = 1; + ps->bs_enable_sa = faad_get1bit(ld); + ps->bs_enable_pan = faad_get1bit(ld); + if (ps->bs_enable_sa) { drm_ps_sa_element(ps, ld); } + if (ps->bs_enable_pan) { drm_ps_pan_element(ps, ld); } + bits = (uint16_t)faad_get_processed_bits(ld) - bits; + return bits; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_ps_sa_element(drm_ps_info* ps, bitfile* ld) { + drm_ps_huff_tab huff; + uint8_t band; + ps->bs_sa_dt_flag = faad_get1bit(ld); + if (ps->bs_sa_dt_flag) { + huff = t_huffman_sa; + } else { + huff = f_huffman_sa; + } + for (band = 0; band < DRM_NUM_SA_BANDS; band++) { ps->bs_sa_data[band] = huff_dec(ld, huff); } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_ps_pan_element(drm_ps_info* ps, bitfile* ld) { + drm_ps_huff_tab huff; + uint8_t band; + ps->bs_pan_dt_flag = faad_get1bit(ld); + if (ps->bs_pan_dt_flag) { + huff = t_huffman_pan; + } else { + huff = f_huffman_pan; + } + for (band = 0; band < DRM_NUM_PAN_BANDS; band++) { ps->bs_pan_data[band] = huff_dec(ld, huff); } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* binary search huffman decoding */ +int8_t NeaacDecoder::huff_dec(bitfile* ld, drm_ps_huff_tab huff) { + uint8_t bit; + int16_t index = 0; + while (index >= 0) { + bit = (uint8_t)faad_get1bit(ld); + index = huff[index][bit]; + } + return index + 15; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +int8_t NeaacDecoder::sa_delta_clip(drm_ps_info* ps, int8_t i) { + if (i < 0) { + /* printf(" SAminclip %d", i); */ + ps->sa_decode_error = 1; + return 0; + } else if (i > 7) { + /* printf(" SAmaxclip %d", i); */ + ps->sa_decode_error = 1; + return 7; + } else + return i; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +int8_t NeaacDecoder::pan_delta_clip(drm_ps_info* ps, int8_t i) { + if (i < -7) { + /* printf(" PANminclip %d", i); */ + ps->pan_decode_error = 1; + return -7; + } else if (i > 7) { + /* printf(" PANmaxclip %d", i); */ + ps->pan_decode_error = 1; + return 7; + } else + return i; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_ps_delta_decode(drm_ps_info* ps) { + uint8_t band; + if (ps->bs_enable_sa) { + if (ps->bs_sa_dt_flag && !ps->g_last_had_sa) { + /* wait until we get a DT frame */ + ps->bs_enable_sa = 0; + } else if (ps->bs_sa_dt_flag) { + /* DT frame, we have a last frame, so we can decode */ + ps->g_sa_index[0] = sa_delta_clip(ps, ps->g_prev_sa_index[0] + ps->bs_sa_data[0]); + } else { + /* DF always decodable */ + ps->g_sa_index[0] = sa_delta_clip(ps, ps->bs_sa_data[0]); + } + for (band = 1; band < DRM_NUM_SA_BANDS; band++) { + if (ps->bs_sa_dt_flag && ps->g_last_had_sa) { + ps->g_sa_index[band] = sa_delta_clip(ps, ps->g_prev_sa_index[band] + ps->bs_sa_data[band]); + } else if (!ps->bs_sa_dt_flag) { + ps->g_sa_index[band] = sa_delta_clip(ps, ps->g_sa_index[band - 1] + ps->bs_sa_data[band]); + } + } + } + /* An error during SA decoding implies PAN data will be undecodable, too */ + /* Also, we don't like on/off switching in PS, so we force to last settings */ + if (ps->sa_decode_error) { + ps->pan_decode_error = 1; + ps->bs_enable_pan = ps->g_last_had_pan; + ps->bs_enable_sa = ps->g_last_had_sa; + } + if (ps->bs_enable_sa) { + if (ps->sa_decode_error) { + for (band = 0; band < DRM_NUM_SA_BANDS; band++) { ps->g_sa_index[band] = ps->g_last_good_sa_index[band]; } + } else { + for (band = 0; band < DRM_NUM_SA_BANDS; band++) { ps->g_last_good_sa_index[band] = ps->g_sa_index[band]; } + } + } + if (ps->bs_enable_pan) { + if (ps->bs_pan_dt_flag && !ps->g_last_had_pan) { + ps->bs_enable_pan = 0; + } else if (ps->bs_pan_dt_flag) { + ps->g_pan_index[0] = pan_delta_clip(ps, ps->g_prev_pan_index[0] + ps->bs_pan_data[0]); + } else { + ps->g_pan_index[0] = pan_delta_clip(ps, ps->bs_pan_data[0]); + } + for (band = 1; band < DRM_NUM_PAN_BANDS; band++) { + if (ps->bs_pan_dt_flag && ps->g_last_had_pan) { + ps->g_pan_index[band] = pan_delta_clip(ps, ps->g_prev_pan_index[band] + ps->bs_pan_data[band]); + } else if (!ps->bs_pan_dt_flag) { + ps->g_pan_index[band] = pan_delta_clip(ps, ps->g_pan_index[band - 1] + ps->bs_pan_data[band]); + } + } + if (ps->pan_decode_error) { + for (band = 0; band < DRM_NUM_PAN_BANDS; band++) { ps->g_pan_index[band] = ps->g_last_good_pan_index[band]; } + } else { + for (band = 0; band < DRM_NUM_PAN_BANDS; band++) { ps->g_last_good_pan_index[band] = ps->g_pan_index[band]; } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_calc_sa_side_signal(drm_ps_info* ps, qmf_t X[38][64]) { + uint8_t s, b, k; + complex_t qfrac, tmp0, tmp, in, R0; + real_t peakdiff; + real_t nrg; + real_t power; + real_t transratio; + real_t new_delay_slopes[NUM_OF_LINKS]; + uint8_t temp_delay_ser[NUM_OF_LINKS]; + complex_t Phi_Fract; + #ifdef FIXED_POINT + uint32_t in_re, in_im; + #endif + for (b = 0; b < sa_freq_scale[DRM_NUM_SA_BANDS]; b++) { + /* set delay indices */ + for (k = 0; k < NUM_OF_LINKS; k++) temp_delay_ser[k] = ps->delay_buf_index_ser[k]; + RE(Phi_Fract) = RE(Phi_Fract_Qmf[b]); + IM(Phi_Fract) = IM(Phi_Fract_Qmf[b]); + for (s = 0; s < NUM_OF_SUBSAMPLES; s++) { + const real_t gamma = REAL_CONST(1.5); + const real_t sigma = REAL_CONST(1.5625); + RE(in) = QMF_RE(X[s][b]); + IM(in) = QMF_IM(X[s][b]); + #ifdef FIXED_POINT + /* NOTE: all input is scaled by 2^(-5) because of fixed point QMF + * meaning that P will be scaled by 2^(-10) compared to floating point version + */ + in_re = ((abs(RE(in)) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + in_im = ((abs(IM(in)) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + power = in_re * in_re + in_im * in_im; + #else + power = MUL_R(RE(in), RE(in)) + MUL_R(IM(in), IM(in)); + #endif + ps->peakdecay_fast[b] = MUL_F(ps->peakdecay_fast[b], peak_decay); + if (ps->peakdecay_fast[b] < power) ps->peakdecay_fast[b] = power; + peakdiff = ps->prev_peakdiff[b]; + peakdiff += MUL_F((ps->peakdecay_fast[b] - power - ps->prev_peakdiff[b]), smooth_coeff); + ps->prev_peakdiff[b] = peakdiff; + nrg = ps->prev_nrg[b]; + nrg += MUL_F((power - ps->prev_nrg[b]), smooth_coeff); + ps->prev_nrg[b] = nrg; + if (MUL_R(peakdiff, gamma) <= nrg) { + transratio = sigma; + } else { + transratio = MUL_R(DIV_R(nrg, MUL_R(peakdiff, gamma)), sigma); + } + for (k = 0; k < NUM_OF_LINKS; k++) { new_delay_slopes[k] = MUL_F(g_decayslope[b], filter_coeff[k]); } + RE(tmp0) = RE(ps->d_buff[0][b]); + IM(tmp0) = IM(ps->d_buff[0][b]); + RE(ps->d_buff[0][b]) = RE(ps->d_buff[1][b]); + IM(ps->d_buff[0][b]) = IM(ps->d_buff[1][b]); + RE(ps->d_buff[1][b]) = RE(in); + IM(ps->d_buff[1][b]) = IM(in); + ComplexMult(&RE(tmp), &IM(tmp), RE(tmp0), IM(tmp0), RE(Phi_Fract), IM(Phi_Fract)); + RE(R0) = RE(tmp); + IM(R0) = IM(tmp); + for (k = 0; k < NUM_OF_LINKS; k++) { + RE(qfrac) = RE(Q_Fract_allpass_Qmf[b][k]); + IM(qfrac) = IM(Q_Fract_allpass_Qmf[b][k]); + RE(tmp0) = RE(ps->d2_buff[k][temp_delay_ser[k]][b]); + IM(tmp0) = IM(ps->d2_buff[k][temp_delay_ser[k]][b]); + ComplexMult(&RE(tmp), &IM(tmp), RE(tmp0), IM(tmp0), RE(qfrac), IM(qfrac)); + RE(tmp) += -MUL_F(new_delay_slopes[k], RE(R0)); + IM(tmp) += -MUL_F(new_delay_slopes[k], IM(R0)); + RE(ps->d2_buff[k][temp_delay_ser[k]][b]) = RE(R0) + MUL_F(new_delay_slopes[k], RE(tmp)); + IM(ps->d2_buff[k][temp_delay_ser[k]][b]) = IM(R0) + MUL_F(new_delay_slopes[k], IM(tmp)); + RE(R0) = RE(tmp); + IM(R0) = IM(tmp); + } + QMF_RE(ps->SA[s][b]) = MUL_R(RE(R0), transratio); + QMF_IM(ps->SA[s][b]) = MUL_R(IM(R0), transratio); + for (k = 0; k < NUM_OF_LINKS; k++) { + if (++temp_delay_ser[k] >= delay_length[k]) temp_delay_ser[k] = 0; + } + } + } + for (k = 0; k < NUM_OF_LINKS; k++) ps->delay_buf_index_ser[k] = temp_delay_ser[k]; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_add_ambiance(drm_ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64]) { + uint8_t s, b, ifreq, qclass; + real_t sa_map[MAX_SA_BAND], sa_dir_map[MAX_SA_BAND], k_sa_map[MAX_SA_BAND], k_sa_dir_map[MAX_SA_BAND]; + real_t new_dir_map, new_sa_map; + if (ps->bs_enable_sa) { + /* Instead of dequantization and mapping, we use an inverse mapping + to look up all the values we need */ + for (b = 0; b < sa_freq_scale[DRM_NUM_SA_BANDS]; b++) { + const real_t inv_f_num_of_subsamples = FRAC_CONST(0.03333333333); + ifreq = sa_inv_freq[b]; + qclass = (b != 0); + sa_map[b] = sa_quant[ps->g_prev_sa_index[ifreq]][qclass]; + new_sa_map = sa_quant[ps->g_sa_index[ifreq]][qclass]; + k_sa_map[b] = MUL_F(inv_f_num_of_subsamples, (new_sa_map - sa_map[b])); + sa_dir_map[b] = sa_sqrt_1_minus[ps->g_prev_sa_index[ifreq]][qclass]; + new_dir_map = sa_sqrt_1_minus[ps->g_sa_index[ifreq]][qclass]; + k_sa_dir_map[b] = MUL_F(inv_f_num_of_subsamples, (new_dir_map - sa_dir_map[b])); + } + for (s = 0; s < NUM_OF_SUBSAMPLES; s++) { + for (b = 0; b < sa_freq_scale[DRM_NUM_SA_BANDS]; b++) { + QMF_RE(X_right[s][b]) = MUL_F(QMF_RE(X_left[s][b]), sa_dir_map[b]) - MUL_F(QMF_RE(ps->SA[s][b]), sa_map[b]); + QMF_IM(X_right[s][b]) = MUL_F(QMF_IM(X_left[s][b]), sa_dir_map[b]) - MUL_F(QMF_IM(ps->SA[s][b]), sa_map[b]); + QMF_RE(X_left[s][b]) = MUL_F(QMF_RE(X_left[s][b]), sa_dir_map[b]) + MUL_F(QMF_RE(ps->SA[s][b]), sa_map[b]); + QMF_IM(X_left[s][b]) = MUL_F(QMF_IM(X_left[s][b]), sa_dir_map[b]) + MUL_F(QMF_IM(ps->SA[s][b]), sa_map[b]); + sa_map[b] += k_sa_map[b]; + sa_dir_map[b] += k_sa_dir_map[b]; + } + for (b = sa_freq_scale[DRM_NUM_SA_BANDS]; b < NUM_OF_QMF_CHANNELS; b++) { + QMF_RE(X_right[s][b]) = QMF_RE(X_left[s][b]); + QMF_IM(X_right[s][b]) = QMF_IM(X_left[s][b]); + } + } + } else { + for (s = 0; s < NUM_OF_SUBSAMPLES; s++) { + for (b = 0; b < NUM_OF_QMF_CHANNELS; b++) { + QMF_RE(X_right[s][b]) = QMF_RE(X_left[s][b]); + QMF_IM(X_right[s][b]) = QMF_IM(X_left[s][b]); + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_add_pan(drm_ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64]) { + uint8_t s, b, qclass, ifreq; + real_t tmp, coeff1, coeff2; + real_t pan_base[MAX_PAN_BAND]; + real_t pan_delta[MAX_PAN_BAND]; + qmf_t temp_l, temp_r; + if (ps->bs_enable_pan) { + for (b = 0; b < NUM_OF_QMF_CHANNELS; b++) { + /* Instead of dequantization, 20->64 mapping and 2^G(x,y) we do an + inverse mapping 64->20 and look up the 2^G(x,y) values directly */ + ifreq = pan_inv_freq[b]; + qclass = pan_quant_class[ifreq]; + if (ps->g_prev_pan_index[ifreq] >= 0) { + pan_base[b] = pan_pow_2_pos[ps->g_prev_pan_index[ifreq]][qclass]; + } else { + pan_base[b] = pan_pow_2_neg[-ps->g_prev_pan_index[ifreq]][qclass]; + } + /* 2^((a-b)/30) = 2^(a/30) * 1/(2^(b/30)) */ + /* a en b can be negative so we may need to inverse parts */ + if (ps->g_pan_index[ifreq] >= 0) { + if (ps->g_prev_pan_index[ifreq] >= 0) { + pan_delta[b] = MUL_C(pan_pow_2_30_pos[ps->g_pan_index[ifreq]][qclass], pan_pow_2_30_neg[ps->g_prev_pan_index[ifreq]][qclass]); + } else { + pan_delta[b] = MUL_C(pan_pow_2_30_pos[ps->g_pan_index[ifreq]][qclass], pan_pow_2_30_pos[-ps->g_prev_pan_index[ifreq]][qclass]); + } + } else { + if (ps->g_prev_pan_index[ifreq] >= 0) { + pan_delta[b] = MUL_C(pan_pow_2_30_neg[-ps->g_pan_index[ifreq]][qclass], pan_pow_2_30_neg[ps->g_prev_pan_index[ifreq]][qclass]); + } else { + pan_delta[b] = MUL_C(pan_pow_2_30_neg[-ps->g_pan_index[ifreq]][qclass], pan_pow_2_30_pos[-ps->g_prev_pan_index[ifreq]][qclass]); + } + } + } + for (s = 0; s < NUM_OF_SUBSAMPLES; s++) { + /* PAN always uses all 64 channels */ + for (b = 0; b < NUM_OF_QMF_CHANNELS; b++) { + tmp = pan_base[b]; + coeff2 = DIV_R(REAL_CONST(2.0), (REAL_CONST(1.0) + tmp)); + coeff1 = MUL_R(coeff2, tmp); + QMF_RE(temp_l) = QMF_RE(X_left[s][b]); + QMF_IM(temp_l) = QMF_IM(X_left[s][b]); + QMF_RE(temp_r) = QMF_RE(X_right[s][b]); + QMF_IM(temp_r) = QMF_IM(X_right[s][b]); + QMF_RE(X_left[s][b]) = MUL_R(QMF_RE(temp_l), coeff1); + QMF_IM(X_left[s][b]) = MUL_R(QMF_IM(temp_l), coeff1); + QMF_RE(X_right[s][b]) = MUL_R(QMF_RE(temp_r), coeff2); + QMF_IM(X_right[s][b]) = MUL_R(QMF_IM(temp_r), coeff2); + /* 2^(a+k*b) = 2^a * 2^b * ... * 2^b */ + /* ^^^^^^^^^^^^^^^ k times */ + pan_base[b] = MUL_C(pan_base[b], pan_delta[b]); + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +drm_ps_info* NeaacDecoder::drm_ps_init(void) { + drm_ps_info* ps = (drm_ps_info*)faad_malloc(sizeof(drm_ps_info)); + memset(ps, 0, sizeof(drm_ps_info)); + return ps; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +void NeaacDecoder::drm_ps_free(drm_ps_info* ps) { + faad_free(&ps); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* main DRM PS decoding function */ +uint8_t NeaacDecoder::drm_ps_decode(drm_ps_info* ps, uint8_t guess, qmf_t X_left[38][64], qmf_t X_right[38][64]) { + if (ps == NULL) { + memcpy(X_right, X_left, sizeof(qmf_t) * 30 * 64); + return 0; + } + if (!ps->drm_ps_data_available && !guess) { + memcpy(X_right, X_left, sizeof(qmf_t) * 30 * 64); + memset(ps->g_prev_sa_index, 0, sizeof(ps->g_prev_sa_index)); + memset(ps->g_prev_pan_index, 0, sizeof(ps->g_prev_pan_index)); + return 0; + } + /* if SBR CRC doesn't match out, we can assume decode errors to start with, + and we'll guess what the parameters should be */ + if (!guess) { + ps->sa_decode_error = 0; + ps->pan_decode_error = 0; + drm_ps_delta_decode(ps); + } else { + ps->sa_decode_error = 1; + ps->pan_decode_error = 1; + /* don't even bother decoding */ + } + ps->drm_ps_data_available = 0; + drm_calc_sa_side_signal(ps, X_left); + drm_add_ambiance(ps, X_left, X_right); + if (ps->bs_enable_sa) { + ps->g_last_had_sa = 1; + memcpy(ps->g_prev_sa_index, ps->g_sa_index, sizeof(int8_t) * DRM_NUM_SA_BANDS); + } else { + ps->g_last_had_sa = 0; + } + if (ps->bs_enable_pan) { + drm_add_pan(ps, X_left, X_right); + ps->g_last_had_pan = 1; + memcpy(ps->g_prev_pan_index, ps->g_pan_index, sizeof(int8_t) * DRM_NUM_PAN_BANDS); + } else { + ps->g_last_had_pan = 0; + } + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::ms_decode(ic_stream* ics, ic_stream* icsr, real_t* l_spec, real_t* r_spec, uint16_t frame_len) { + uint8_t g, b, sfb; + uint8_t group = 0; + uint16_t nshort = frame_len / 8; + uint16_t i, k; + real_t tmp; + if (ics->ms_mask_present >= 1) { + for (g = 0; g < ics->num_window_groups; g++) { + for (b = 0; b < ics->window_group_length[g]; b++) { + for (sfb = 0; sfb < ics->max_sfb; sfb++) { + /* If intensity stereo coding or noise substitution is on + for a particular scalefactor band, no M/S stereo decoding + is carried out. + */ + if ((ics->ms_used[g][sfb] || ics->ms_mask_present == 2) && !is_intensity(icsr, g, sfb) && !is_noise(ics, g, sfb)) { + for (i = ics->swb_offset[sfb]; i < min(ics->swb_offset[sfb + 1], ics->swb_offset_max); i++) { + k = (group * nshort) + i; + tmp = l_spec[k] - r_spec[k]; + l_spec[k] = l_spec[k] + r_spec[k]; + r_spec[k] = tmp; + } + } + } + group++; + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t NeaacDecoder::is_intensity(ic_stream* ics, uint8_t group, uint8_t sfb) { + switch (ics->sfb_cb[group][sfb]) { + case INTENSITY_HCB: return 1; + case INTENSITY_HCB2: return -1; + default: return 0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t NeaacDecoder::invert_intensity(ic_stream* ics, uint8_t group, uint8_t sfb) { + if (ics->ms_mask_present == 1) return (1 - 2 * ics->ms_used[group][sfb]); + return 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::is_noise(ic_stream* ics, uint8_t group, uint8_t sfb) { + if (ics->sfb_cb[group][sfb] == NOISE_HCB) return 1; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +real_t NeaacDecoder::get_sample(real_t** input, uint8_t channel, uint16_t sample, uint8_t down_matrix, uint8_t* internal_channel) { + if (!down_matrix) return input[internal_channel[channel]][sample]; + if (channel == 0) { + return DM_MUL * (input[internal_channel[1]][sample] + input[internal_channel[0]][sample] * RSQRT2 + input[internal_channel[3]][sample] * RSQRT2); + } else { + return DM_MUL * (input[internal_channel[2]][sample] + input[internal_channel[0]][sample] * RSQRT2 + input[internal_channel[4]][sample] * RSQRT2); + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void NeaacDecoder::to_PCM_16bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int16_t** sample_buffer) { + uint8_t ch, ch1; + uint16_t i; + switch (CONV(channels, hDecoder->downMatrix)) { + case CONV(1, 0): + case CONV(1, 1): + for (i = 0; i < frame_len; i++) { + real_t inp = input[hDecoder->internal_channel[0]][i]; + CLIP(inp, 32767.0f, -32768.0f); + (*sample_buffer)[i] = (int16_t)lrintf(inp); + } + break; + case CONV(2, 0): + if (hDecoder->upMatrix) { + ch = hDecoder->internal_channel[0]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + CLIP(inp0, 32767.0f, -32768.0f); + (*sample_buffer)[(i * 2) + 0] = (int16_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int16_t)lrintf(inp0); + } + } else { + ch = hDecoder->internal_channel[0]; + ch1 = hDecoder->internal_channel[1]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + real_t inp1 = input[ch1][i]; + CLIP(inp0, 32767.0f, -32768.0f); + CLIP(inp1, 32767.0f, -32768.0f); + (*sample_buffer)[(i * 2) + 0] = (int16_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int16_t)lrintf(inp1); + } + } + break; + default: + for (ch = 0; ch < channels; ch++) { + for (i = 0; i < frame_len; i++) { + real_t inp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->internal_channel); + CLIP(inp, 32767.0f, -32768.0f); + (*sample_buffer)[(i * channels) + ch] = (int16_t)lrintf(inp); + } + } + break; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void NeaacDecoder::to_PCM_24bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int32_t** sample_buffer) { + uint8_t ch, ch1; + uint16_t i; + switch (CONV(channels, hDecoder->downMatrix)) { + case CONV(1, 0): + case CONV(1, 1): + for (i = 0; i < frame_len; i++) { + real_t inp = input[hDecoder->internal_channel[0]][i]; + inp *= 256.0f; + CLIP(inp, 8388607.0f, -8388608.0f); + (*sample_buffer)[i] = (int32_t)lrintf(inp); + } + break; + case CONV(2, 0): + if (hDecoder->upMatrix) { + ch = hDecoder->internal_channel[0]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + inp0 *= 256.0f; + CLIP(inp0, 8388607.0f, -8388608.0f); + (*sample_buffer)[(i * 2) + 0] = (int32_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int32_t)lrintf(inp0); + } + } else { + ch = hDecoder->internal_channel[0]; + ch1 = hDecoder->internal_channel[1]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + real_t inp1 = input[ch1][i]; + inp0 *= 256.0f; + inp1 *= 256.0f; + CLIP(inp0, 8388607.0f, -8388608.0f); + CLIP(inp1, 8388607.0f, -8388608.0f); + (*sample_buffer)[(i * 2) + 0] = (int32_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int32_t)lrintf(inp1); + } + } + break; + default: + for (ch = 0; ch < channels; ch++) { + for (i = 0; i < frame_len; i++) { + real_t inp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->internal_channel); + inp *= 256.0f; + CLIP(inp, 8388607.0f, -8388608.0f); + (*sample_buffer)[(i * channels) + ch] = (int32_t)lrintf(inp); + } + } + break; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void NeaacDecoder::to_PCM_32bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int32_t** sample_buffer) { + uint8_t ch, ch1; + uint16_t i; + switch (CONV(channels, hDecoder->downMatrix)) { + case CONV(1, 0): + case CONV(1, 1): + for (i = 0; i < frame_len; i++) { + real_t inp = input[hDecoder->internal_channel[0]][i]; + inp *= 65536.0f; + CLIP(inp, 2147483647.0f, -2147483648.0f); + (*sample_buffer)[i] = (int32_t)lrintf(inp); + } + break; + case CONV(2, 0): + if (hDecoder->upMatrix) { + ch = hDecoder->internal_channel[0]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + inp0 *= 65536.0f; + CLIP(inp0, 2147483647.0f, -2147483648.0f); + (*sample_buffer)[(i * 2) + 0] = (int32_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int32_t)lrintf(inp0); + } + } else { + ch = hDecoder->internal_channel[0]; + ch1 = hDecoder->internal_channel[1]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + real_t inp1 = input[ch1][i]; + inp0 *= 65536.0f; + inp1 *= 65536.0f; + CLIP(inp0, 2147483647.0f, -2147483648.0f); + CLIP(inp1, 2147483647.0f, -2147483648.0f); + (*sample_buffer)[(i * 2) + 0] = (int32_t)lrintf(inp0); + (*sample_buffer)[(i * 2) + 1] = (int32_t)lrintf(inp1); + } + } + break; + default: + for (ch = 0; ch < channels; ch++) { + for (i = 0; i < frame_len; i++) { + real_t inp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->internal_channel); + inp *= 65536.0f; + CLIP(inp, 2147483647.0f, -2147483648.0f); + (*sample_buffer)[(i * channels) + ch] = (int32_t)lrintf(inp); + } + } + break; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void NeaacDecoder::to_PCM_float(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, float** sample_buffer) { + uint8_t ch, ch1; + uint16_t i; + switch (CONV(channels, hDecoder->downMatrix)) { + case CONV(1, 0): + case CONV(1, 1): + for (i = 0; i < frame_len; i++) { + real_t inp = input[hDecoder->internal_channel[0]][i]; + (*sample_buffer)[i] = inp * FLOAT_SCALE; + } + break; + case CONV(2, 0): + if (hDecoder->upMatrix) { + ch = hDecoder->internal_channel[0]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + (*sample_buffer)[(i * 2) + 0] = inp0 * FLOAT_SCALE; + (*sample_buffer)[(i * 2) + 1] = inp0 * FLOAT_SCALE; + } + } else { + ch = hDecoder->internal_channel[0]; + ch1 = hDecoder->internal_channel[1]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + real_t inp1 = input[ch1][i]; + (*sample_buffer)[(i * 2) + 0] = inp0 * FLOAT_SCALE; + (*sample_buffer)[(i * 2) + 1] = inp1 * FLOAT_SCALE; + } + } + break; + default: + for (ch = 0; ch < channels; ch++) { + for (i = 0; i < frame_len; i++) { + real_t inp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->internal_channel); + (*sample_buffer)[(i * channels) + ch] = inp * FLOAT_SCALE; + } + } + break; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void NeaacDecoder::to_PCM_double(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, double** sample_buffer) { + uint8_t ch, ch1; + uint16_t i; + switch (CONV(channels, hDecoder->downMatrix)) { + case CONV(1, 0): + case CONV(1, 1): + for (i = 0; i < frame_len; i++) { + real_t inp = input[hDecoder->internal_channel[0]][i]; + (*sample_buffer)[i] = (double)inp * FLOAT_SCALE; + } + break; + case CONV(2, 0): + if (hDecoder->upMatrix) { + ch = hDecoder->internal_channel[0]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + (*sample_buffer)[(i * 2) + 0] = (double)inp0 * FLOAT_SCALE; + (*sample_buffer)[(i * 2) + 1] = (double)inp0 * FLOAT_SCALE; + } + } else { + ch = hDecoder->internal_channel[0]; + ch1 = hDecoder->internal_channel[1]; + for (i = 0; i < frame_len; i++) { + real_t inp0 = input[ch][i]; + real_t inp1 = input[ch1][i]; + (*sample_buffer)[(i * 2) + 0] = (double)inp0 * FLOAT_SCALE; + (*sample_buffer)[(i * 2) + 1] = (double)inp1 * FLOAT_SCALE; + } + } + break; + default: + for (ch = 0; ch < channels; ch++) { + for (i = 0; i < frame_len; i++) { + real_t inp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->internal_channel); + (*sample_buffer)[(i * channels) + ch] = (double)inp * FLOAT_SCALE; + } + } + break; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifndef FIXED_POINT +void* NeaacDecoder::output_to_PCM(NeAACDecStruct* hDecoder, real_t** input, void* sample_buffer, uint8_t channels, uint16_t frame_len, uint8_t format) { + int16_t* short_sample_buffer = (int16_t*)sample_buffer; + int32_t* int_sample_buffer = (int32_t*)sample_buffer; + float* float_sample_buffer = (float*)sample_buffer; + double* double_sample_buffer = (double*)sample_buffer; + #ifdef PROFILE + int64_t count = faad_get_ts(); + #endif + /* Copy output to a standard PCM buffer */ + switch (format) { + case FAAD_FMT_16BIT: to_PCM_16bit(hDecoder, input, channels, frame_len, &short_sample_buffer); break; + case FAAD_FMT_24BIT: to_PCM_24bit(hDecoder, input, channels, frame_len, &int_sample_buffer); break; + case FAAD_FMT_32BIT: to_PCM_32bit(hDecoder, input, channels, frame_len, &int_sample_buffer); break; + case FAAD_FMT_FLOAT: to_PCM_float(hDecoder, input, channels, frame_len, &float_sample_buffer); break; + case FAAD_FMT_DOUBLE: to_PCM_double(hDecoder, input, channels, frame_len, &double_sample_buffer); break; + } + #ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->output_cycles += count; + #endif + return sample_buffer; +} +#endif +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +real_t NeaacDecoder::get_sample(real_t** input, uint8_t channel, uint16_t sample, uint8_t down_matrix, uint8_t up_matrix, uint8_t* internal_channel) { + if (up_matrix == 1) return input[internal_channel[0]][sample]; + if (!down_matrix) return input[internal_channel[channel]][sample]; + if (channel == 0) { + real_t C = MUL_F(input[internal_channel[0]][sample], RSQRT2); + real_t L_S = MUL_F(input[internal_channel[3]][sample], RSQRT2); + real_t cum = input[internal_channel[1]][sample] + C + L_S; + return MUL_F(cum, DM_MUL); + } else { + real_t C = MUL_F(input[internal_channel[0]][sample], RSQRT2); + real_t R_S = MUL_F(input[internal_channel[4]][sample], RSQRT2); + real_t cum = input[internal_channel[2]][sample] + C + R_S; + return MUL_F(cum, DM_MUL); + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +void* NeaacDecoder::output_to_PCM(NeAACDecStruct* hDecoder, real_t** input, void* sample_buffer, uint8_t channels, uint16_t frame_len, uint8_t format) { + uint8_t ch; + uint16_t i; + int16_t* short_sample_buffer = (int16_t*)sample_buffer; + int32_t* int_sample_buffer = (int32_t*)sample_buffer; + /* Copy output to a standard PCM buffer */ + for (ch = 0; ch < channels; ch++) { + switch (format) { + case FAAD_FMT_16BIT: + for (i = 0; i < frame_len; i++) { + int32_t tmp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->upMatrix, hDecoder->internal_channel); + if (tmp >= 0) { + tmp += (1 << (REAL_BITS - 1)); + if (tmp >= REAL_CONST(32767)) { tmp = REAL_CONST(32767); } + } else { + tmp += -(1 << (REAL_BITS - 1)); + if (tmp <= REAL_CONST(-32768)) { tmp = REAL_CONST(-32768); } + } + tmp >>= REAL_BITS; + short_sample_buffer[(i * channels) + ch] = (int16_t)tmp; + } + break; + case FAAD_FMT_24BIT: + for (i = 0; i < frame_len; i++) { + int32_t tmp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->upMatrix, hDecoder->internal_channel); + if (tmp >= 0) { + tmp += (1 << (REAL_BITS - 9)); + tmp >>= (REAL_BITS - 8); + if (tmp >= 8388607) { tmp = 8388607; } + } else { + tmp += -(1 << (REAL_BITS - 9)); + tmp >>= (REAL_BITS - 8); + if (tmp <= -8388608) { tmp = -8388608; } + } + int_sample_buffer[(i * channels) + ch] = (int32_t)tmp; + } + break; + case FAAD_FMT_32BIT: + for (i = 0; i < frame_len; i++) { + int32_t tmp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->upMatrix, hDecoder->internal_channel); + if (tmp >= 0) { + tmp += (1 << (16 - REAL_BITS - 1)); + tmp <<= (16 - REAL_BITS); + } else { + tmp += -(1 << (16 - REAL_BITS - 1)); + tmp <<= (16 - REAL_BITS); + } + int_sample_buffer[(i * channels) + ch] = (int32_t)tmp; + } + break; + case FAAD_FMT_FIXED: + for (i = 0; i < frame_len; i++) { + real_t tmp = get_sample(input, ch, i, hDecoder->downMatrix, hDecoder->upMatrix, hDecoder->internal_channel); + int_sample_buffer[(i * channels) + ch] = (int32_t)tmp; + } + break; + } + } + return sample_buffer; +} +#endif // FIXED_POINT +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* The function gen_rand_vector(addr, size) generates a vector of length with signed random values of average energy MEAN_NRG per random + value. A suitable random number generator can be realized using one multiplication/accumulation per random value.*/ +void NeaacDecoder::gen_rand_vector(real_t* spec, int16_t scale_factor, uint16_t size, uint8_t sub, uint32_t* __r1, uint32_t* __r2) { +#ifndef FIXED_POINT + uint16_t i; + real_t energy = 0.0; + real_t scale = (real_t)1.0 / (real_t)size; + for (i = 0; i < size; i++) { + real_t tmp = scale * (real_t)(int32_t)ne_rng(__r1, __r2); + spec[i] = tmp; + energy += tmp * tmp; + } + scale = (real_t)1.0 / (real_t)sqrt(energy); + scale *= (real_t)pow(2.0, 0.25 * scale_factor); + for (i = 0; i < size; i++) { spec[i] *= scale; } +#else + uint16_t i; + real_t energy = 0, scale; + int32_t exp, frac; + for (i = 0; i < size; i++) { + /* this can be replaced by a 16 bit random generator!!!! */ + real_t tmp = (int32_t)ne_rng(__r1, __r2); + if (tmp < 0) + tmp = -(tmp & ((1 << (REAL_BITS - 1)) - 1)); + else + tmp = (tmp & ((1 << (REAL_BITS - 1)) - 1)); + energy += MUL_R(tmp, tmp); + spec[i] = tmp; + } + energy = fp_sqrt(energy); + if (energy > 0) { + scale = DIV(REAL_CONST(1), energy); + exp = scale_factor >> 2; + frac = scale_factor & 3; + /* IMDCT pre-scaling */ + exp -= sub; + if (exp < 0) + scale >>= -exp; + else + scale <<= exp; + if (frac) scale = MUL_C(scale, pow2_table[frac]); + for (i = 0; i < size; i++) { spec[i] = MUL_R(spec[i], scale); } + } +#endif +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::pns_decode(ic_stream* ics_left, ic_stream* ics_right, real_t* spec_left, real_t* spec_right, uint16_t frame_len, uint8_t channel_pair, uint8_t object_type, + /* RNG states */ uint32_t* __r1, uint32_t* __r2) { + uint8_t g, sfb, b; + uint16_t size, offs; + uint8_t group = 0; + uint16_t nshort = frame_len >> 3; + uint8_t sub = 0; +#ifdef FIXED_POINT + /* IMDCT scaling */ + if (object_type == LD) { + sub = 9 /*9*/; + } else { + if (ics_left->window_sequence == EIGHT_SHORT_SEQUENCE) + sub = 7 /*7*/; + else + sub = 10 /*10*/; + } +#endif + for (g = 0; g < ics_left->num_window_groups; g++) { + /* Do perceptual noise substitution decoding */ + for (b = 0; b < ics_left->window_group_length[g]; b++) { + for (sfb = 0; sfb < ics_left->max_sfb; sfb++) { + uint32_t r1_dep = 0, r2_dep = 0; + if (is_noise(ics_left, g, sfb)) { +#ifdef LTP_DEC + /* Simultaneous use of LTP and PNS is not prevented in the + syntax. If both LTP, and PNS are enabled on the same + scalefactor band, PNS takes precedence, and no prediction + is applied to this band. + */ + ics_left->ltp.long_used[sfb] = 0; + ics_left->ltp2.long_used[sfb] = 0; +#endif +#ifdef MAIN_DEC + /* For scalefactor bands coded using PNS the corresponding + predictors are switched to "off". + */ + ics_left->pred.prediction_used[sfb] = 0; +#endif + offs = ics_left->swb_offset[sfb]; + size = min(ics_left->swb_offset[sfb + 1], ics_left->swb_offset_max) - offs; + r1_dep = *__r1; + r2_dep = *__r2; + /* Generate random vector */ + gen_rand_vector(&spec_left[(group * nshort) + offs], ics_left->scale_factors[g][sfb], size, sub, __r1, __r2); + } + /* From the spec: + If the same scalefactor band and group is coded by perceptual noise + substitution in both channels of a channel pair, the correlation of + the noise signal can be controlled by means of the ms_used field: While + the default noise generation process works independently for each channel + (separate generation of random vectors), the same random vector is used + for both channels if ms_used[] is set for a particular scalefactor band + and group. In this case, no M/S stereo coding is carried out (because M/S + stereo coding and noise substitution coding are mutually exclusive). + If the same scalefactor band and group is coded by perceptual noise + substitution in only one channel of a channel pair the setting of ms_used[] + is not evaluated. + */ + if ((ics_right != NULL) && is_noise(ics_right, g, sfb)) { +#ifdef LTP_DEC + /* See comment above. */ + ics_right->ltp.long_used[sfb] = 0; + ics_right->ltp2.long_used[sfb] = 0; +#endif +#ifdef MAIN_DEC + /* See comment above. */ + ics_right->pred.prediction_used[sfb] = 0; +#endif + if (channel_pair && is_noise(ics_left, g, sfb) && (((ics_left->ms_mask_present == 1) && (ics_left->ms_used[g][sfb])) || (ics_left->ms_mask_present == 2))) { + /*uint16_t c;*/ + offs = ics_right->swb_offset[sfb]; + size = min(ics_right->swb_offset[sfb + 1], ics_right->swb_offset_max) - offs; + /* Generate random vector dependent on left channel*/ + gen_rand_vector(&spec_right[(group * nshort) + offs], ics_right->scale_factors[g][sfb], size, sub, &r1_dep, &r2_dep); + } else /*if (ics_left->ms_mask_present == 0)*/ { + offs = ics_right->swb_offset[sfb]; + size = min(ics_right->swb_offset[sfb + 1], ics_right->swb_offset_max) - offs; + /* Generate random vector */ + gen_rand_vector(&spec_right[(group * nshort) + offs], ics_right->scale_factors[g][sfb], size, sub, __r1, __r2); + } + } + } /* sfb */ + group++; + } /* b */ + } /* g */ +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t NeaacDecoder::huffman_scale_factor(bitfile* ld) { + uint16_t offset = 0; + while (hcb_sf[offset][1]) { + uint8_t b = faad_get1bit(ld); + offset += hcb_sf[offset][b]; + if (offset > 240) { + /* printf("ERROR: offset into hcb_sf = %d >240!\n", offset); */ + return -1; + } + } + return hcb_sf[offset][0]; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::huffman_sign_bits(bitfile* ld, int16_t* sp, uint8_t len) { + uint8_t i; + for (i = 0; i < len; i++) { + if (sp[i]) { + if (faad_get1bit(ld) & 1) { sp[i] = -sp[i]; } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_getescape(bitfile* ld, int16_t* sp) { + uint8_t neg, i; + int16_t j; + int16_t off; + int16_t x = *sp; + if (x < 0) { + if (x != -16) return 0; + neg = 1; + } else { + if (x != 16) return 0; + neg = 0; + } + for (i = 4; i < 16; i++) { + if (faad_get1bit(ld) == 0) { break; } + } + if (i >= 16) return 10; + off = (int16_t)faad_getbits(ld, i); + j = off | (1 << i); + if (neg) j = -j; + *sp = j; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_2step_quad(uint8_t cb, bitfile* ld, int16_t* sp) { + uint32_t cw; + uint16_t offset = 0; + uint8_t extra_bits; + cw = faad_showbits(ld, hcbN[cb]); + offset = hcb_table[cb][cw].offset; + extra_bits = hcb_table[cb][cw].extra_bits; + if (extra_bits) { + /* we know for sure it's more than hcbN[cb] bits long */ + faad_flushbits(ld, hcbN[cb]); + offset += (uint16_t)faad_showbits(ld, extra_bits); + faad_flushbits(ld, hcb_2_quad_table[cb][offset].bits - hcbN[cb]); + } else { + faad_flushbits(ld, hcb_2_quad_table[cb][offset].bits); + } + if (offset > hcb_2_quad_table_size[cb]) { + /* printf("ERROR: offset into hcb_2_quad_table = %d >%d!\n", offset, + hcb_2_quad_table_size[cb]); */ + return 10; + } + sp[0] = hcb_2_quad_table[cb][offset].x; + sp[1] = hcb_2_quad_table[cb][offset].y; + sp[2] = hcb_2_quad_table[cb][offset].v; + sp[3] = hcb_2_quad_table[cb][offset].w; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_2step_quad_sign(uint8_t cb, bitfile* ld, int16_t* sp) { + uint8_t err = huffman_2step_quad(cb, ld, sp); + huffman_sign_bits(ld, sp, QUAD_LEN); + return err; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_2step_pair(uint8_t cb, bitfile* ld, int16_t* sp) { + uint32_t cw; + uint16_t offset = 0; + uint8_t extra_bits; + cw = faad_showbits(ld, hcbN[cb]); + offset = hcb_table[cb][cw].offset; + extra_bits = hcb_table[cb][cw].extra_bits; + if (extra_bits) { + /* we know for sure it's more than hcbN[cb] bits long */ + faad_flushbits(ld, hcbN[cb]); + offset += (uint16_t)faad_showbits(ld, extra_bits); + faad_flushbits(ld, hcb_2_pair_table[cb][offset].bits - hcbN[cb]); + } else { + faad_flushbits(ld, hcb_2_pair_table[cb][offset].bits); + } + if (offset > hcb_2_pair_table_size[cb]) { + /* printf("ERROR: offset into hcb_2_pair_table = %d >%d!\n", offset, + hcb_2_pair_table_size[cb]); */ + return 10; + } + sp[0] = hcb_2_pair_table[cb][offset].x; + sp[1] = hcb_2_pair_table[cb][offset].y; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_2step_pair_sign(uint8_t cb, bitfile* ld, int16_t* sp) { + uint8_t err = huffman_2step_pair(cb, ld, sp); + huffman_sign_bits(ld, sp, PAIR_LEN); + return err; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_binary_quad(uint8_t cb, bitfile* ld, int16_t* sp) { + uint16_t offset = 0; + while (!hcb3[offset].is_leaf) { + uint8_t b = faad_get1bit(ld); + offset += hcb3[offset].data[b]; + } + if (offset > hcb_bin_table_size[cb]) { + /* printf("ERROR: offset into hcb_bin_table = %d >%d!\n", offset, + hcb_bin_table_size[cb]); */ + return 10; + } + sp[0] = hcb3[offset].data[0]; + sp[1] = hcb3[offset].data[1]; + sp[2] = hcb3[offset].data[2]; + sp[3] = hcb3[offset].data[3]; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_binary_quad_sign(uint8_t cb, bitfile* ld, int16_t* sp) { + uint8_t err = huffman_binary_quad(cb, ld, sp); + huffman_sign_bits(ld, sp, QUAD_LEN); + return err; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_binary_pair(uint8_t cb, bitfile* ld, int16_t* sp) { + uint16_t offset = 0; + while (!hcb_bin_table[cb][offset].is_leaf) { + uint8_t b = faad_get1bit(ld); + offset += hcb_bin_table[cb][offset].data[b]; + } + if (offset > hcb_bin_table_size[cb]) { + /* printf("ERROR: offset into hcb_bin_table = %d >%d!\n", offset, + hcb_bin_table_size[cb]); */ + return 10; + } + sp[0] = hcb_bin_table[cb][offset].data[0]; + sp[1] = hcb_bin_table[cb][offset].data[1]; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_binary_pair_sign(uint8_t cb, bitfile* ld, int16_t* sp) { + uint8_t err = huffman_binary_pair(cb, ld, sp); + huffman_sign_bits(ld, sp, PAIR_LEN); + return err; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int16_t NeaacDecoder::huffman_codebook(uint8_t i) { + const uint32_t data = 16428320; + if (i == 0) + return (int16_t)(data >> 16) & 0xFFFF; + else + return (int16_t)data & 0xFFFF; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::vcb11_check_LAV(uint8_t cb, int16_t* sp) { + const uint16_t vcb11_LAV_tab[] = {16, 31, 47, 63, 95, 127, 159, 191, 223, 255, 319, 383, 511, 767, 1023, 2047}; + uint16_t max = 0; + if (cb < 16 || cb > 31) return; + max = vcb11_LAV_tab[cb - 16]; + if ((abs(sp[0]) > max) || (abs(sp[1]) > max)) { + sp[0] = 0; + sp[1] = 0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::huffman_spectral_data(uint8_t cb, bitfile* ld, int16_t* sp) { + switch (cb) { + case 1: /* 2-step method for data quadruples */ + case 2: return huffman_2step_quad(cb, ld, sp); + case 3: /* binary search for data quadruples */ return huffman_binary_quad_sign(cb, ld, sp); + case 4: /* 2-step method for data quadruples */ return huffman_2step_quad_sign(cb, ld, sp); + case 5: /* binary search for data pairs */ return huffman_binary_pair(cb, ld, sp); + case 6: /* 2-step method for data pairs */ return huffman_2step_pair(cb, ld, sp); + case 7: /* binary search for data pairs */ + case 9: return huffman_binary_pair_sign(cb, ld, sp); + case 8: /* 2-step method for data pairs */ + case 10: return huffman_2step_pair_sign(cb, ld, sp); + case 12: { + uint8_t err = huffman_2step_pair(11, ld, sp); + sp[0] = huffman_codebook(0); + sp[1] = huffman_codebook(1); + return err; + } + case 11: { + uint8_t err = huffman_2step_pair_sign(11, ld, sp); + if (!err) err = huffman_getescape(ld, &sp[0]); + if (!err) err = huffman_getescape(ld, &sp[1]); + return err; + } +#ifdef ERROR_RESILIENCE + /* VCB11 uses codebook 11 */ + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: { + uint8_t err = huffman_2step_pair_sign(11, ld, sp); + if (!err) err = huffman_getescape(ld, &sp[0]); + if (!err) err = huffman_getescape(ld, &sp[1]); + /* check LAV (Largest Absolute Value) */ + /* this finds errors in the ESCAPE signal */ + vcb11_check_LAV(cb, sp); + return err; + } +#endif + default: + /* Non existent codebook number, something went wrong */ + return 11; + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +/* Special version of huffman_spectral_data +Will not read from a bitfile but a bits_t structure. +Will keep track of the bits decoded and return the number of bits remaining. +Do not read more than ld->len, return -1 if codeword would be longer */ +int8_t NeaacDecoder::huffman_spectral_data_2(uint8_t cb, bits_t* ld, int16_t* sp) { + uint32_t cw; + uint16_t offset = 0; + uint8_t extra_bits; + uint8_t i, vcb11 = 0; + switch (cb) { + case 1: /* 2-step method for data quadruples */ + case 2: + case 4: + cw = showbits_hcr(ld, hcbN[cb]); + offset = hcb_table[cb][cw].offset; + extra_bits = hcb_table[cb][cw].extra_bits; + if (extra_bits) { + /* we know for sure it's more than hcbN[cb] bits long */ + if (flushbits_hcr(ld, hcbN[cb])) return -1; + offset += (uint16_t)showbits_hcr(ld, extra_bits); + if (flushbits_hcr(ld, hcb_2_quad_table[cb][offset].bits - hcbN[cb])) return -1; + } else { + if (flushbits_hcr(ld, hcb_2_quad_table[cb][offset].bits)) return -1; + } + sp[0] = hcb_2_quad_table[cb][offset].x; + sp[1] = hcb_2_quad_table[cb][offset].y; + sp[2] = hcb_2_quad_table[cb][offset].v; + sp[3] = hcb_2_quad_table[cb][offset].w; + break; + case 6: /* 2-step method for data pairs */ + case 8: + case 10: + case 11: + /* VCB11 uses codebook 11 */ + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + if (cb >= 16) { + /* store the virtual codebook */ + vcb11 = cb; + cb = 11; + } + cw = showbits_hcr(ld, hcbN[cb]); + offset = hcb_table[cb][cw].offset; + extra_bits = hcb_table[cb][cw].extra_bits; + if (extra_bits) { + /* we know for sure it's more than hcbN[cb] bits long */ + if (flushbits_hcr(ld, hcbN[cb])) return -1; + offset += (uint16_t)showbits_hcr(ld, extra_bits); + if (flushbits_hcr(ld, hcb_2_pair_table[cb][offset].bits - hcbN[cb])) return -1; + } else { + if (flushbits_hcr(ld, hcb_2_pair_table[cb][offset].bits)) return -1; + } + sp[0] = hcb_2_pair_table[cb][offset].x; + sp[1] = hcb_2_pair_table[cb][offset].y; + break; + case 3: /* binary search for data quadruples */ + while (!hcb3[offset].is_leaf) { + uint8_t b; + if (get1bit_hcr(ld, &b)) return -1; + offset += hcb3[offset].data[b]; + } + sp[0] = hcb3[offset].data[0]; + sp[1] = hcb3[offset].data[1]; + sp[2] = hcb3[offset].data[2]; + sp[3] = hcb3[offset].data[3]; + break; + case 5: /* binary search for data pairs */ + case 7: + case 9: + while (!hcb_bin_table[cb][offset].is_leaf) { + uint8_t b; + if (get1bit_hcr(ld, &b)) return -1; + offset += hcb_bin_table[cb][offset].data[b]; + } + sp[0] = hcb_bin_table[cb][offset].data[0]; + sp[1] = hcb_bin_table[cb][offset].data[1]; + break; + } + /* decode sign bits */ + if (unsigned_cb[cb]) { + for (i = 0; i < ((cb < FIRST_PAIR_HCB) ? QUAD_LEN : PAIR_LEN); i++) { + if (sp[i]) { + uint8_t b; + if (get1bit_hcr(ld, &b)) return -1; + if (b != 0) { sp[i] = -sp[i]; } + } + } + } + /* decode huffman escape bits */ + if ((cb == ESC_HCB) || (cb >= 16)) { + uint8_t k; + for (k = 0; k < 2; k++) { + if ((sp[k] == 16) || (sp[k] == -16)) { + uint8_t neg, i; + int32_t j; + uint32_t off; + neg = (sp[k] < 0) ? 1 : 0; + for (i = 4;; i++) { + uint8_t b; + if (get1bit_hcr(ld, &b)) return -1; + if (b == 0) break; + } + if (getbits_hcr(ld, i, &off)) return -1; + j = off + (1 << i); + sp[k] = (int16_t)((neg) ? -j : j); + } + } + if (vcb11 != 0) { + /* check LAV (Largest Absolute Value) */ + /* this finds errors in the ESCAPE signal */ + vcb11_check_LAV(vcb11, sp); + } + } + return ld->len; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::is_decode(ic_stream* ics, ic_stream* icsr, real_t* l_spec, real_t* r_spec, uint16_t frame_len) { + uint8_t g, sfb, b; + uint16_t i; +#ifndef FIXED_POINT + real_t scale; +#else + int32_t exp, frac; +#endif + uint16_t nshort = frame_len / 8; + uint8_t group = 0; + for (g = 0; g < icsr->num_window_groups; g++) { + /* Do intensity stereo decoding */ + for (b = 0; b < icsr->window_group_length[g]; b++) { + for (sfb = 0; sfb < icsr->max_sfb; sfb++) { + if (is_intensity(icsr, g, sfb)) { +#ifdef MAIN_DEC + /* For scalefactor bands coded in intensity stereo the + corresponding predictors in the right channel are + switched to "off". + */ + ics->pred.prediction_used[sfb] = 0; + icsr->pred.prediction_used[sfb] = 0; +#endif +#ifndef FIXED_POINT + scale = (real_t)pow(0.5, (0.25 * icsr->scale_factors[g][sfb])); +#else + exp = icsr->scale_factors[g][sfb] >> 2; + frac = icsr->scale_factors[g][sfb] & 3; +#endif + /* Scale from left to right channel, + do not touch left channel */ + for (i = icsr->swb_offset[sfb]; i < min(icsr->swb_offset[sfb + 1], ics->swb_offset_max); i++) { +#ifndef FIXED_POINT + r_spec[(group * nshort) + i] = MUL_R(l_spec[(group * nshort) + i], scale); +#else + if (exp < 0) + r_spec[(group * nshort) + i] = l_spec[(group * nshort) + i] << -exp; + else + r_spec[(group * nshort) + i] = l_spec[(group * nshort) + i] >> exp; + r_spec[(group * nshort) + i] = MUL_C(r_spec[(group * nshort) + i], pow05_table[frac + 3]); +#endif + if (is_intensity(icsr, g, sfb) != invert_intensity(ics, g, sfb)) r_spec[(group * nshort) + i] = -r_spec[(group * nshort) + i]; + } + } + } + group++; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef FIXED_POINT +real_t NeaacDecoder::fp_sqrt(real_t value) { + real_t root = 0; + step(0); + step(2); + step(4); + step(6); + step(8); + step(10); + step(12); + step(14); + step(16); + step(18); + step(20); + step(22); + step(24); + step(26); + step(28); + step(30); + if (root < value) ++root; + root <<= (REAL_BITS / 2); + return root; +} +#endif /*FIXED_POINT*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_mdct_init(uint16_t mdct_len, uint16_t N) { + mdct_info* mdct_new = nullptr; + switch (mdct_len) { + case 256: + m_mdct256.alloc("m_mdct256"); + mdct_new = m_mdct256.get(); + break; + case 1024: + m_mdct1024.alloc("m_mdct1024"); + mdct_new = m_mdct1024.get(); + break; + case 2048: + m_mdct2048.alloc("m_mdct2048"); + mdct_new = m_mdct2048.get(); + break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + assert(N % 8 == 0); + mdct_new->N = N; + /* NOTE: For "small framelengths" in FIXED_POINT the coefficients need to be + * scaled by sqrt("(nearest power of 2) > N" / N) */ + /* RE(mdct_new->sincos[k]) = scale*(int32_t)(cos(2.0*M_PI*(k+1./8.) / (int32_t)N)); + * IM(mdct_new->sincos[k]) = scale*(int32_t)(sin(2.0*M_PI*(k+1./8.) / (int32_t)N)); */ + /* scale is 1 for fixed point, sqrt(N) for floating point */ + switch (N) { + case 2048: mdct_new->sincos = (complex_t*)mdct_tab_2048; break; + case 256: mdct_new->sincos = (complex_t*)mdct_tab_256; break; +#ifdef LD_DEC + case 1024: mdct_new->sincos = (complex_t*)mdct_tab_1024; break; +#endif +#ifdef ALLOW_SMALL_FRAMELENGTH + case 1920: mdct_new->sincos = (complex_t*)mdct_tab_1920; break; + case 240: mdct_new->sincos = (complex_t*)mdct_tab_240; break; + #ifdef LD_DEC + case 960: mdct_new->sincos = (complex_t*)mdct_tab_960; break; + #endif +#endif +#ifdef SSR_DEC + case 512: mdct_new->sincos = (complex_t*)mdct_tab_512; break; + case 64: mdct_new->sincos = (complex_t*)mdct_tab_64; break; +#endif + } + /* initialise fft */ + cffti(mdct_len, N / 4); +#ifdef PROFILE + mdct_new->cycles = 0; + mdct_new->fft_cycles = 0; +#endif + return; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_mdct_end(uint16_t mdct_len) { + switch (mdct_len) { + case 256: + m_work256.reset(); + m_ccft256.reset(); + m_mdct256.reset(); + break; + case 1024: + m_work1024.reset(); + m_ccft1024.reset(); + m_mdct1024.reset(); + break; + case 2048: + m_work2048.reset(); + m_ccft2048.reset(); + m_mdct2048.reset(); + break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::faad_imdct(uint16_t mdct_len, real_t* X_in, real_t* X_out) { + mdct_info* mdct_select = nullptr; + switch (mdct_len) { + case 256: mdct_select = m_mdct256.get(); break; + case 1024: mdct_select = m_mdct1024.get(); break; + case 2048: mdct_select = m_mdct2048.get(); break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + uint16_t k; + complex_t x; +#ifdef ALLOW_SMALL_FRAMELENGTH + #ifdef FIXED_POINT + real_t scale, b_scale = 0; + #endif +#endif + // complex_t Z1[512]; + complex_t* Z1 = (complex_t*)ps_malloc(512 * sizeof(complex_t)); + complex_t* sincos = mdct_select->sincos; + uint16_t N = mdct_select->N; + uint16_t N2 = N >> 1; + uint16_t N4 = N >> 2; + uint16_t N8 = N >> 3; +#ifdef PROFILE + int64_t count1, count2 = faad_get_ts(); +#endif +#ifdef ALLOW_SMALL_FRAMELENGTH + #ifdef FIXED_POINT + /* detect non-power of 2 */ + if (N & (N - 1)) { + /* adjust scale for non-power of 2 MDCT */ + /* 2048/1920 */ + b_scale = 1; + scale = COEF_CONST(1.0666666666666667); + } + #endif +#endif + /* pre-IFFT complex multiplication */ + for (k = 0; k < N4; k++) { ComplexMult(&IM(Z1[k]), &RE(Z1[k]), X_in[2 * k], X_in[N2 - 1 - 2 * k], RE(sincos[k]), IM(sincos[k])); } +#ifdef PROFILE + count1 = faad_get_ts(); +#endif + /* complex IFFT, any non-scaling FFT can be used here */ + cfftb(mdct_len, Z1); +#ifdef PROFILE + count1 = faad_get_ts() - count1; +#endif + /* post-IFFT complex multiplication */ + for (k = 0; k < N4; k++) { + RE(x) = RE(Z1[k]); + IM(x) = IM(Z1[k]); + ComplexMult(&IM(Z1[k]), &RE(Z1[k]), IM(x), RE(x), RE(sincos[k]), IM(sincos[k])); +#ifdef ALLOW_SMALL_FRAMELENGTH + #ifdef FIXED_POINT + /* non-power of 2 MDCT scaling */ + if (b_scale) { + RE(Z1[k]) = MUL_C(RE(Z1[k]), scale); + IM(Z1[k]) = MUL_C(IM(Z1[k]), scale); + } + #endif +#endif + } + /* reordering */ + for (k = 0; k < N8; k += 2) { + X_out[2 * k] = IM(Z1[N8 + k]); + X_out[2 + 2 * k] = IM(Z1[N8 + 1 + k]); + X_out[1 + 2 * k] = -RE(Z1[N8 - 1 - k]); + X_out[3 + 2 * k] = -RE(Z1[N8 - 2 - k]); + X_out[N4 + 2 * k] = RE(Z1[k]); + X_out[N4 + +2 + 2 * k] = RE(Z1[1 + k]); + X_out[N4 + 1 + 2 * k] = -IM(Z1[N4 - 1 - k]); + X_out[N4 + 3 + 2 * k] = -IM(Z1[N4 - 2 - k]); + X_out[N2 + 2 * k] = RE(Z1[N8 + k]); + X_out[N2 + +2 + 2 * k] = RE(Z1[N8 + 1 + k]); + X_out[N2 + 1 + 2 * k] = -IM(Z1[N8 - 1 - k]); + X_out[N2 + 3 + 2 * k] = -IM(Z1[N8 - 2 - k]); + X_out[N2 + N4 + 2 * k] = -IM(Z1[k]); + X_out[N2 + N4 + 2 + 2 * k] = -IM(Z1[1 + k]); + X_out[N2 + N4 + 1 + 2 * k] = RE(Z1[N4 - 1 - k]); + X_out[N2 + N4 + 3 + 2 * k] = RE(Z1[N4 - 2 - k]); + } +#ifdef PROFILE + count2 = faad_get_ts() - count2; + mdct_select->fft_cycles += count1; + mdct_select->cycles += (count2 - count1); +#endif + faad_free(&Z1); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +void NeaacDecoder::faad_mdct(uint16_t mdct_len, real_t* X_in, real_t* X_out) { + mdct_info* mdct_select = nullptr; + switch (mdct_len) { + case 256: mdct_select = m_mdct256.get(); break; + case 1024: mdct_select = m_mdct1024.get(); break; + case 2048: mdct_select = m_mdct2048.get(); break; + default: AAC_LOG_ERROR("wrong length {}", mdct_len); + } + uint16_t k; + complex_t x; + // complex_t Z1[512]; + complex_t* Z1 = (complex_t*)ps_malloc(512 * sizeof(complex_t)); + complex_t* sincos = mdct_select->sincos; + uint16_t N = mdct_select->N; + uint16_t N2 = N >> 1; + uint16_t N4 = N >> 2; + uint16_t N8 = N >> 3; + #ifndef FIXED_POINT + real_t scale = REAL_CONST(N); + #else + real_t scale = REAL_CONST(4.0 / N); + #endif + #ifdef ALLOW_SMALL_FRAMELENGTH + #ifdef FIXED_POINT + /* detect non-power of 2 */ + if (N & (N - 1)) { + /* adjust scale for non-power of 2 MDCT */ + /* *= sqrt(2048/1920) */ + scale = MUL_C(scale, COEF_CONST(1.0327955589886444)); + } + #endif + #endif + /* pre-FFT complex multiplication */ + for (k = 0; k < N8; k++) { + uint16_t n = k << 1; + RE(x) = X_in[N - N4 - 1 - n] + X_in[N - N4 + n]; + IM(x) = X_in[N4 + n] - X_in[N4 - 1 - n]; + ComplexMult(&RE(Z1[k]), &IM(Z1[k]), RE(x), IM(x), RE(sincos[k]), IM(sincos[k])); + RE(Z1[k]) = MUL_R(RE(Z1[k]), scale); + IM(Z1[k]) = MUL_R(IM(Z1[k]), scale); + RE(x) = X_in[N2 - 1 - n] - X_in[n]; + IM(x) = X_in[N2 + n] + X_in[N - 1 - n]; + ComplexMult(&RE(Z1[k + N8]), &IM(Z1[k + N8]), RE(x), IM(x), RE(sincos[k + N8]), IM(sincos[k + N8])); + RE(Z1[k + N8]) = MUL_R(RE(Z1[k + N8]), scale); + IM(Z1[k + N8]) = MUL_R(IM(Z1[k + N8]), scale); + } + /* complex FFT, any non-scaling FFT can be used here */ + cfftf(mdct_len, Z1); + /* post-FFT complex multiplication */ + for (k = 0; k < N4; k++) { + uint16_t n = k << 1; + ComplexMult(&RE(x), &IM(x), RE(Z1[k]), IM(Z1[k]), RE(sincos[k]), IM(sincos[k])); + X_out[n] = -RE(x); + X_out[N2 - 1 - n] = IM(x); + X_out[N2 + n] = -IM(x); + X_out[N - 1 - n] = RE(x); + } + if (Z1) free(Z1); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +fb_info* NeaacDecoder::filter_bank_init(uint16_t frame_len) { + uint16_t nshort = frame_len / 8; +#ifdef LD_DEC + uint16_t frame_len_ld = frame_len / 2; +#endif + fb_info* fb = (fb_info*)faad_malloc(sizeof(fb_info)); + memset(fb, 0, sizeof(fb_info)); + /* normal */ + faad_mdct_init(256, 2 * nshort); + faad_mdct_init(2048, 2 * frame_len); +#ifdef LD_DEC + /* LD */ + faad_mdct_init(1024, 2 * frame_len_ld); +#endif +#ifdef ALLOW_SMALL_FRAMELENGTH + if (frame_len == 1024) { +#endif + fb->long_window[0] = sine_long_1024; + fb->short_window[0] = sine_short_128; + fb->long_window[1] = kbd_long_1024; + fb->short_window[1] = kbd_short_128; +#ifdef LD_DEC + fb->ld_window[0] = sine_mid_512; + fb->ld_window[1] = ld_mid_512; +#endif +#ifdef ALLOW_SMALL_FRAMELENGTH + } else /* (frame_len == 960) */ { + fb->long_window[0] = sine_long_960; + fb->short_window[0] = sine_short_120; + fb->long_window[1] = kbd_long_960; + fb->short_window[1] = kbd_short_120; + #ifdef LD_DEC + fb->ld_window[0] = sine_mid_480; + fb->ld_window[1] = ld_mid_480; + #endif + } +#endif + return fb; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::filter_bank_end(fb_info* fb) { + if (fb != NULL) { +#ifdef PROFILE + printf("FB: %I64d cycles\n", fb->cycles); +#endif + faad_mdct_end(256); + faad_mdct_end(2048); +#ifdef LD_DEC + faad_mdct_end(1024); +#endif + faad_free(&fb); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::imdct_long(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len) { +#ifdef LD_DEC + faad_imdct(len, in_data, out_data); +#else + faad_imdct(2048, in_data, out_data); +#endif +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +void NeaacDecoder::mdct_init(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len) { + uint16_t select = 0; + switch (len) { + case 2048: + case 1920: select = 2048; break; + case 256: + case 240: select = 256; break; + #ifdef LD_DEC + case 1024: + case 960: select = 1024; break; + #endif + } + faad_mdct(select, in_data, out_data); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::ifilter_bank(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, real_t* overlap, uint8_t object_type, + uint16_t frame_len) { + int16_t i; + // real_t transf_buf[2*1024] = {0}; + real_t* transf_buf = (real_t*)faad_calloc(2 * 1024, sizeof(real_t)); + const real_t* window_long = NULL; + const real_t* window_long_prev = NULL; + const real_t* window_short = NULL; + const real_t* window_short_prev = NULL; + uint16_t nlong = frame_len; + uint16_t nshort = frame_len / 8; + uint16_t trans = nshort / 2; + uint16_t nflat_ls = (nlong - nshort) / 2; +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif + /* select windows of current frame and previous frame (Sine or KBD) */ +#ifdef LD_DEC + if (object_type == LD) { + window_long = fb->ld_window[window_shape]; + window_long_prev = fb->ld_window[window_shape_prev]; + } else { +#endif + window_long = fb->long_window[window_shape]; + window_long_prev = fb->long_window[window_shape_prev]; + window_short = fb->short_window[window_shape]; + window_short_prev = fb->short_window[window_shape_prev]; +#ifdef LD_DEC + } +#endif +#if 0 + for (i = 0; i < 1024; i++) + { + printf("%d\n", freq_in[i]); + } +#endif +#if 0 + printf("%d %d\n", window_sequence, window_shape); +#endif + switch (window_sequence) { + case ONLY_LONG_SEQUENCE: + /* perform iMDCT */ + imdct_long(fb, freq_in, transf_buf, 2 * nlong); + /* add second half output of previous frame to windowed output of current frame */ + for (i = 0; i < nlong; i += 4) { + time_out[i] = overlap[i] + MUL_F(transf_buf[i], window_long_prev[i]); + time_out[i + 1] = overlap[i + 1] + MUL_F(transf_buf[i + 1], window_long_prev[i + 1]); + time_out[i + 2] = overlap[i + 2] + MUL_F(transf_buf[i + 2], window_long_prev[i + 2]); + time_out[i + 3] = overlap[i + 3] + MUL_F(transf_buf[i + 3], window_long_prev[i + 3]); + } + /* window the second half and save as overlap for next frame */ + for (i = 0; i < nlong; i += 4) { + overlap[i] = MUL_F(transf_buf[nlong + i], window_long[nlong - 1 - i]); + overlap[i + 1] = MUL_F(transf_buf[nlong + i + 1], window_long[nlong - 2 - i]); + overlap[i + 2] = MUL_F(transf_buf[nlong + i + 2], window_long[nlong - 3 - i]); + overlap[i + 3] = MUL_F(transf_buf[nlong + i + 3], window_long[nlong - 4 - i]); + } + break; + case LONG_START_SEQUENCE: + /* perform iMDCT */ + imdct_long(fb, freq_in, transf_buf, 2 * nlong); + /* add second half output of previous frame to windowed output of current frame */ + for (i = 0; i < nlong; i += 4) { + time_out[i] = overlap[i] + MUL_F(transf_buf[i], window_long_prev[i]); + time_out[i + 1] = overlap[i + 1] + MUL_F(transf_buf[i + 1], window_long_prev[i + 1]); + time_out[i + 2] = overlap[i + 2] + MUL_F(transf_buf[i + 2], window_long_prev[i + 2]); + time_out[i + 3] = overlap[i + 3] + MUL_F(transf_buf[i + 3], window_long_prev[i + 3]); + } + /* window the second half and save as overlap for next frame */ + /* construct second half window using padding with 1's and 0's */ + for (i = 0; i < nflat_ls; i++) overlap[i] = transf_buf[nlong + i]; + for (i = 0; i < nshort; i++) overlap[nflat_ls + i] = MUL_F(transf_buf[nlong + nflat_ls + i], window_short[nshort - i - 1]); + for (i = 0; i < nflat_ls; i++) overlap[nflat_ls + nshort + i] = 0; + break; + case EIGHT_SHORT_SEQUENCE: + /* perform iMDCT for each short block */ + faad_imdct(256, freq_in + 0 * nshort, transf_buf + 2 * nshort * 0); + faad_imdct(256, freq_in + 1 * nshort, transf_buf + 2 * nshort * 1); + faad_imdct(256, freq_in + 2 * nshort, transf_buf + 2 * nshort * 2); + faad_imdct(256, freq_in + 3 * nshort, transf_buf + 2 * nshort * 3); + faad_imdct(256, freq_in + 4 * nshort, transf_buf + 2 * nshort * 4); + faad_imdct(256, freq_in + 5 * nshort, transf_buf + 2 * nshort * 5); + faad_imdct(256, freq_in + 6 * nshort, transf_buf + 2 * nshort * 6); + faad_imdct(256, freq_in + 7 * nshort, transf_buf + 2 * nshort * 7); + /* add second half output of previous frame to windowed output of current frame */ + for (i = 0; i < nflat_ls; i++) time_out[i] = overlap[i]; + for (i = 0; i < nshort; i++) { + time_out[nflat_ls + i] = overlap[nflat_ls + i] + MUL_F(transf_buf[nshort * 0 + i], window_short_prev[i]); + time_out[nflat_ls + 1 * nshort + i] = + overlap[nflat_ls + nshort * 1 + i] + MUL_F(transf_buf[nshort * 1 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 2 + i], window_short[i]); + time_out[nflat_ls + 2 * nshort + i] = + overlap[nflat_ls + nshort * 2 + i] + MUL_F(transf_buf[nshort * 3 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 4 + i], window_short[i]); + time_out[nflat_ls + 3 * nshort + i] = + overlap[nflat_ls + nshort * 3 + i] + MUL_F(transf_buf[nshort * 5 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 6 + i], window_short[i]); + if (i < trans) + time_out[nflat_ls + 4 * nshort + i] = + overlap[nflat_ls + nshort * 4 + i] + MUL_F(transf_buf[nshort * 7 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 8 + i], window_short[i]); + } + /* window the second half and save as overlap for next frame */ + for (i = 0; i < nshort; i++) { + if (i >= trans) overlap[nflat_ls + 4 * nshort + i - nlong] = MUL_F(transf_buf[nshort * 7 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 8 + i], window_short[i]); + overlap[nflat_ls + 5 * nshort + i - nlong] = MUL_F(transf_buf[nshort * 9 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 10 + i], window_short[i]); + overlap[nflat_ls + 6 * nshort + i - nlong] = MUL_F(transf_buf[nshort * 11 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 12 + i], window_short[i]); + overlap[nflat_ls + 7 * nshort + i - nlong] = MUL_F(transf_buf[nshort * 13 + i], window_short[nshort - 1 - i]) + MUL_F(transf_buf[nshort * 14 + i], window_short[i]); + overlap[nflat_ls + 8 * nshort + i - nlong] = MUL_F(transf_buf[nshort * 15 + i], window_short[nshort - 1 - i]); + } + for (i = 0; i < nflat_ls; i++) overlap[nflat_ls + nshort + i] = 0; + break; + case LONG_STOP_SEQUENCE: + /* perform iMDCT */ + imdct_long(fb, freq_in, transf_buf, 2 * nlong); + /* add second half output of previous frame to windowed output of current frame */ + /* construct first half window using padding with 1's and 0's */ + for (i = 0; i < nflat_ls; i++) time_out[i] = overlap[i]; + for (i = 0; i < nshort; i++) time_out[nflat_ls + i] = overlap[nflat_ls + i] + MUL_F(transf_buf[nflat_ls + i], window_short_prev[i]); + for (i = 0; i < nflat_ls; i++) time_out[nflat_ls + nshort + i] = overlap[nflat_ls + nshort + i] + transf_buf[nflat_ls + nshort + i]; + /* window the second half and save as overlap for next frame */ + for (i = 0; i < nlong; i++) overlap[i] = MUL_F(transf_buf[nlong + i], window_long[nlong - 1 - i]); + break; + } +#if 0 + for (i = 0; i < 1024; i++) + { + printf("%d\n", time_out[i]); + //printf("0x%.8X\n", time_out[i]); + } +#endif +#ifdef PROFILE + count = faad_get_ts() - count; + fb->cycles += count; +#endif + faad_free(&transf_buf); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +/* only works for LTP -> no overlapping, no short blocks */ +void NeaacDecoder::filter_bank_ltp(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* in_data, real_t* out_mdct, uint8_t object_type, uint16_t frame_len) { + int16_t i; + // real_t windowed_buf[2*1024] = {0}; + real_t* windowed_buf = (real_t*)faad_calloc(2 * 1024, sizeof(real_t)); + const real_t* window_long = NULL; + const real_t* window_long_prev = NULL; + const real_t* window_short = NULL; + const real_t* window_short_prev = NULL; + uint16_t nlong = frame_len; + uint16_t nshort = frame_len / 8; + uint16_t nflat_ls = (nlong - nshort) / 2; + assert(window_sequence != EIGHT_SHORT_SEQUENCE); + #ifdef LD_DEC + if (object_type == LD) { + window_long = fb->ld_window[window_shape]; + window_long_prev = fb->ld_window[window_shape_prev]; + } else { + #endif + window_long = fb->long_window[window_shape]; + window_long_prev = fb->long_window[window_shape_prev]; + window_short = fb->short_window[window_shape]; + window_short_prev = fb->short_window[window_shape_prev]; + #ifdef LD_DEC + } + #endif + switch (window_sequence) { + case ONLY_LONG_SEQUENCE: + for (i = nlong - 1; i >= 0; i--) { + windowed_buf[i] = MUL_F(in_data[i], window_long_prev[i]); + windowed_buf[i + nlong] = MUL_F(in_data[i + nlong], window_long[nlong - 1 - i]); + } + mdct_init(fb, windowed_buf, out_mdct, 2 * nlong); + break; + case LONG_START_SEQUENCE: + for (i = 0; i < nlong; i++) windowed_buf[i] = MUL_F(in_data[i], window_long_prev[i]); + for (i = 0; i < nflat_ls; i++) windowed_buf[i + nlong] = in_data[i + nlong]; + for (i = 0; i < nshort; i++) windowed_buf[i + nlong + nflat_ls] = MUL_F(in_data[i + nlong + nflat_ls], window_short[nshort - 1 - i]); + for (i = 0; i < nflat_ls; i++) windowed_buf[i + nlong + nflat_ls + nshort] = 0; + mdct_init(fb, windowed_buf, out_mdct, 2 * nlong); + break; + case LONG_STOP_SEQUENCE: + for (i = 0; i < nflat_ls; i++) windowed_buf[i] = 0; + for (i = 0; i < nshort; i++) windowed_buf[i + nflat_ls] = MUL_F(in_data[i + nflat_ls], window_short_prev[i]); + for (i = 0; i < nflat_ls; i++) windowed_buf[i + nflat_ls + nshort] = in_data[i + nflat_ls + nshort]; + for (i = 0; i < nlong; i++) windowed_buf[i + nlong] = MUL_F(in_data[i + nlong], window_long[nlong - 1 - i]); + mdct_init(fb, windowed_buf, out_mdct, 2 * nlong); + break; + } + faad_free(&windowed_buf); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* rewind and reverse */ +/* 32 bit version */ +uint32_t NeaacDecoder::rewrev_word(uint32_t v, const uint8_t len) { + /* 32 bit reverse */ + v = ((v >> S[0]) & B[0]) | ((v << S[0]) & ~B[0]); + v = ((v >> S[1]) & B[1]) | ((v << S[1]) & ~B[1]); + v = ((v >> S[2]) & B[2]) | ((v << S[2]) & ~B[2]); + v = ((v >> S[3]) & B[3]) | ((v << S[3]) & ~B[3]); + v = ((v >> S[4]) & B[4]) | ((v << S[4]) & ~B[4]); + /* shift off low bits */ + v >>= (32 - len); + return v; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 64 bit version */ +void NeaacDecoder::rewrev_lword(uint32_t* hi, uint32_t* lo, const uint8_t len) { + if (len <= 32) { + *hi = 0; + *lo = rewrev_word(*lo, len); + } else { + uint32_t t = *hi, v = *lo; + /* double 32 bit reverse */ + v = ((v >> S[0]) & B[0]) | ((v << S[0]) & ~B[0]); + t = ((t >> S[0]) & B[0]) | ((t << S[0]) & ~B[0]); + v = ((v >> S[1]) & B[1]) | ((v << S[1]) & ~B[1]); + t = ((t >> S[1]) & B[1]) | ((t << S[1]) & ~B[1]); + v = ((v >> S[2]) & B[2]) | ((v << S[2]) & ~B[2]); + t = ((t >> S[2]) & B[2]) | ((t << S[2]) & ~B[2]); + v = ((v >> S[3]) & B[3]) | ((v << S[3]) & ~B[3]); + t = ((t >> S[3]) & B[3]) | ((t << S[3]) & ~B[3]); + v = ((v >> S[4]) & B[4]) | ((v << S[4]) & ~B[4]); + t = ((t >> S[4]) & B[4]) | ((t << S[4]) & ~B[4]); + /* last 32<>32 bit swap is implicit below */ + /* shift off low bits (this is really only one 64 bit shift) */ + *lo = (t >> (64 - len)) | (v << (len - 32)); + *hi = v >> (64 - len); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* bits_t version */ +void NeaacDecoder::rewrev_bits(bits_t* bits) { + if (bits->len == 0) return; + rewrev_lword(&bits->bufb, &bits->bufa, bits->len); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* merge bits of a to b */ +void NeaacDecoder::concat_bits(bits_t* b, bits_t* a) { + uint32_t bl, bh, al, ah; + if (a->len == 0) return; + al = a->bufa; + ah = a->bufb; + if (b->len > 32) { + /* maskoff superfluous high b bits */ + bl = b->bufa; + bh = b->bufb & ((1 << (b->len - 32)) - 1); + /* left shift a b->len bits */ + ah = al << (b->len - 32); + al = 0; + } else { + bl = b->bufa & ((1 << (b->len)) - 1); + bh = 0; + ah = (ah << (b->len)) | (al >> (32 - b->len)); + al = al << b->len; + } + /* merge */ + b->bufa = bl | al; + b->bufb = bh | ah; + b->len += a->len; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::is_good_cb(uint8_t this_CB, uint8_t this_sec_CB) { + /* only want spectral data CB's */ + if ((this_sec_CB > ZERO_HCB && this_sec_CB <= ESC_HCB) || (this_sec_CB >= VCB11_FIRST && this_sec_CB <= VCB11_LAST)) { + if (this_CB < ESC_HCB) { + /* normal codebook pairs */ + return ((this_sec_CB == this_CB) || (this_sec_CB == this_CB + 1)); + } else { + /* escape codebook */ + return (this_sec_CB == this_CB); + } + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::read_segment(bits_t* segment, uint8_t segwidth, bitfile* ld) { + segment->len = segwidth; + if (segwidth > 32) { + segment->bufb = faad_getbits(ld, segwidth - 32); + segment->bufa = faad_getbits(ld, 32); + } else { + segment->bufa = faad_getbits(ld, segwidth); + segment->bufb = 0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::fill_in_codeword(codeword_t* codeword, uint16_t index, uint16_t sp, uint8_t cb) { + codeword[index].sp_offset = sp; + codeword[index].cb = cb; + codeword[index].decoded = 0; + codeword[index].bits.len = 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::reordered_spectral_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, int16_t* spectral_data) { + uint8_t ret = 0; + uint16_t PCWs_done; + uint16_t numberOfSegments, numberOfSets, numberOfCodewords; + // codeword_t codeword[512]; + // bits_t segment[512]; + codeword_t* codeword = (codeword_t*)ps_malloc(sizeof(codeword_t) * 512); + bits_t* segment = (bits_t*)ps_malloc(sizeof(bits_t) * 512); + uint16_t sp_offset[8]; + uint16_t g, i, sortloop, set, bitsread; + /*uint16_t bitsleft, codewordsleft*/; + uint8_t w_idx, sfb, this_CB, last_CB, this_sec_CB; + const uint16_t nshort = hDecoder->frameLength / 8; + const uint16_t sp_data_len = ics->length_of_reordered_spectral_data; + const uint8_t* PreSortCb; + /* no data (e.g. silence) */ + if (sp_data_len == 0) { + ret = 0; + goto exit; + } + /* since there is spectral data, at least one codeword has nonzero length */ + if (ics->length_of_longest_codeword == 0) { + ret = 10; + goto exit; + } + if (sp_data_len < ics->length_of_longest_codeword) { + ret = 10; + goto exit; + } + sp_offset[0] = 0; + for (g = 1; g < ics->num_window_groups; g++) { sp_offset[g] = sp_offset[g - 1] + nshort * ics->window_group_length[g - 1]; } + PCWs_done = 0; + numberOfSegments = 0; + numberOfCodewords = 0; + bitsread = 0; + /* VCB11 code books in use */ + if (hDecoder->aacSectionDataResilienceFlag) { + PreSortCb = PreSortCB_ER; + last_CB = NUM_CB_ER; + } else { + PreSortCb = PreSortCB_STD; + last_CB = NUM_CB; + } + /* step 1: decode PCW's (set 0), and stuff data in easier-to-use format */ + for (sortloop = 0; sortloop < last_CB; sortloop++) { + /* select codebook to process this pass */ + this_CB = PreSortCb[sortloop]; + /* loop over sfbs */ + for (sfb = 0; sfb < ics->max_sfb; sfb++) { + /* loop over all in this sfb, 4 lines per loop */ + for (w_idx = 0; 4 * w_idx < (min(ics->swb_offset[sfb + 1], ics->swb_offset_max) - ics->swb_offset[sfb]); w_idx++) { + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->num_sec[g]; i++) { + /* check whether sfb used here is the one we want to process */ + if ((ics->sect_start[g][i] <= sfb) && (ics->sect_end[g][i] > sfb)) { + /* check whether codebook used here is the one we want to process */ + this_sec_CB = ics->sect_cb[g][i]; + if (is_good_cb(this_CB, this_sec_CB)) { + /* precalculate some stuff */ + uint16_t sect_sfb_size = ics->sect_sfb_offset[g][sfb + 1] - ics->sect_sfb_offset[g][sfb]; + uint8_t inc = (this_sec_CB < FIRST_PAIR_HCB) ? QUAD_LEN : PAIR_LEN; + uint16_t group_cws_count = (4 * ics->window_group_length[g]) / inc; + uint8_t segwidth = min(maxCwLen[this_sec_CB], ics->length_of_longest_codeword); + uint16_t cws; + /* read codewords until end of sfb or end of window group (shouldn't only 1 trigger?) */ + for (cws = 0; (cws < group_cws_count) && ((cws + w_idx * group_cws_count) < sect_sfb_size); cws++) { + uint16_t sp = sp_offset[g] + ics->sect_sfb_offset[g][sfb] + inc * (cws + w_idx * group_cws_count); + /* read and decode PCW */ + if (!PCWs_done) { + /* read in normal segments */ + if (bitsread + segwidth <= sp_data_len) { + read_segment(&segment[numberOfSegments], segwidth, ld); + bitsread += segwidth; + huffman_spectral_data_2(this_sec_CB, &segment[numberOfSegments], &spectral_data[sp]); + /* keep leftover bits */ + rewrev_bits(&segment[numberOfSegments]); + numberOfSegments++; + } else { + /* remaining stuff after last segment, we unfortunately couldn't read + this in earlier because it might not fit in 64 bits. since we already + decoded (and removed) the PCW it is now guaranteed to fit */ + if (bitsread < sp_data_len) { + const uint8_t additional_bits = sp_data_len - bitsread; + read_segment(&segment[numberOfSegments], additional_bits, ld); + segment[numberOfSegments].len += segment[numberOfSegments - 1].len; + rewrev_bits(&segment[numberOfSegments]); + if (segment[numberOfSegments - 1].len > 32) { + segment[numberOfSegments - 1].bufb = + segment[numberOfSegments].bufb + showbits_hcr(&segment[numberOfSegments - 1], segment[numberOfSegments - 1].len - 32); + segment[numberOfSegments - 1].bufa = segment[numberOfSegments].bufa + showbits_hcr(&segment[numberOfSegments - 1], 32); + } else { + segment[numberOfSegments - 1].bufa = + segment[numberOfSegments].bufa + showbits_hcr(&segment[numberOfSegments - 1], segment[numberOfSegments - 1].len); + segment[numberOfSegments - 1].bufb = segment[numberOfSegments].bufb; + } + segment[numberOfSegments - 1].len += additional_bits; + } + bitsread = sp_data_len; + PCWs_done = 1; + fill_in_codeword(codeword, 0, sp, this_sec_CB); + } + } else { + fill_in_codeword(codeword, numberOfCodewords - numberOfSegments, sp, this_sec_CB); + } + numberOfCodewords++; + } + } + } + } + } + } + } + } + if (numberOfSegments == 0) { + ret = 10; + goto exit; + } + numberOfSets = numberOfCodewords / numberOfSegments; + /* step 2: decode nonPCWs */ + for (set = 1; set <= numberOfSets; set++) { + uint16_t trial; + for (trial = 0; trial < numberOfSegments; trial++) { + uint16_t codewordBase; + for (codewordBase = 0; codewordBase < numberOfSegments; codewordBase++) { + const uint16_t segment_idx = (trial + codewordBase) % numberOfSegments; + const uint16_t codeword_idx = codewordBase + set * numberOfSegments - numberOfSegments; + /* data up */ + if (codeword_idx >= numberOfCodewords - numberOfSegments) break; + if (!codeword[codeword_idx].decoded && segment[segment_idx].len > 0) { + uint8_t tmplen; + if (codeword[codeword_idx].bits.len != 0) concat_bits(&segment[segment_idx], &codeword[codeword_idx].bits); + tmplen = segment[segment_idx].len; + if (huffman_spectral_data_2(codeword[codeword_idx].cb, &segment[segment_idx], &spectral_data[codeword[codeword_idx].sp_offset]) >= 0) { + codeword[codeword_idx].decoded = 1; + } else { + codeword[codeword_idx].bits = segment[segment_idx]; + codeword[codeword_idx].bits.len = tmplen; + } + } + } + } + for (i = 0; i < numberOfSegments; i++) rewrev_bits(&segment[i]); + } +#if 0 // Seems to give false errors + bitsleft = 0; + for (i = 0; i < numberOfSegments && !bitsleft; i++) + bitsleft += segment[i].len; + if (bitsleft) {ret = 10; goto exit;} + codewordsleft = 0; + for (i = 0; (i < numberOfCodewords - numberOfSegments) && (!codewordsleft); i++) + if (!codeword[i].decoded) + codewordsleft++; + if (codewordsleft) {ret = 10; goto exit;} +#endif + ret = 0; +exit: + faad_free(&codeword); + faad_free(&segment); + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::DCT4_32(real_t* y, real_t* x) { + // printf(ANSI_ESC_YELLOW "dct4_32" ANSI_ESC_WHITE "\n"); + int32_t* f = (int32_t*)faad_malloc(397 * sizeof(int32_t)); + f[0] = x[15] - x[16]; + f[1] = x[15] + x[16]; + f[2] = MUL_F(FRAC_CONST(0.7071067811865476), f[1]); + f[3] = MUL_F(FRAC_CONST(0.7071067811865476), f[0]); + f[4] = x[8] - x[23]; + f[5] = x[8] + x[23]; + f[6] = MUL_F(FRAC_CONST(0.7071067811865476), f[5]); + f[7] = MUL_F(FRAC_CONST(0.7071067811865476), f[4]); + f[8] = x[12] - x[19]; + f[9] = x[12] + x[19]; + f[10] = MUL_F(FRAC_CONST(0.7071067811865476), f[9]); + f[11] = MUL_F(FRAC_CONST(0.7071067811865476), f[8]); + f[12] = x[11] - x[20]; + f[13] = x[11] + x[20]; + f[14] = MUL_F(FRAC_CONST(0.7071067811865476), f[13]); + f[15] = MUL_F(FRAC_CONST(0.7071067811865476), f[12]); + f[16] = x[14] - x[17]; + f[17] = x[14] + x[17]; + f[18] = MUL_F(FRAC_CONST(0.7071067811865476), f[17]); + f[19] = MUL_F(FRAC_CONST(0.7071067811865476), f[16]); + f[20] = x[9] - x[22]; + f[21] = x[9] + x[22]; + f[22] = MUL_F(FRAC_CONST(0.7071067811865476), f[21]); + f[23] = MUL_F(FRAC_CONST(0.7071067811865476), f[20]); + f[24] = x[13] - x[18]; + f[25] = x[13] + x[18]; + f[26] = MUL_F(FRAC_CONST(0.7071067811865476), f[25]); + f[27] = MUL_F(FRAC_CONST(0.7071067811865476), f[24]); + f[28] = x[10] - x[21]; + f[29] = x[10] + x[21]; + f[30] = MUL_F(FRAC_CONST(0.7071067811865476), f[29]); + f[31] = MUL_F(FRAC_CONST(0.7071067811865476), f[28]); + f[32] = x[0] - f[2]; + f[33] = x[0] + f[2]; + f[34] = x[31] - f[3]; + f[35] = x[31] + f[3]; + f[36] = x[7] - f[6]; + f[37] = x[7] + f[6]; + f[38] = x[24] - f[7]; + f[39] = x[24] + f[7]; + f[40] = x[3] - f[10]; + f[41] = x[3] + f[10]; + f[42] = x[28] - f[11]; + f[43] = x[28] + f[11]; + f[44] = x[4] - f[14]; + f[45] = x[4] + f[14]; + f[46] = x[27] - f[15]; + f[47] = x[27] + f[15]; + f[48] = x[1] - f[18]; + f[49] = x[1] + f[18]; + f[50] = x[30] - f[19]; + f[51] = x[30] + f[19]; + f[52] = x[6] - f[22]; + f[53] = x[6] + f[22]; + f[54] = x[25] - f[23]; + f[55] = x[25] + f[23]; + f[56] = x[2] - f[26]; + f[57] = x[2] + f[26]; + f[58] = x[29] - f[27]; + f[59] = x[29] + f[27]; + f[60] = x[5] - f[30]; + f[61] = x[5] + f[30]; + f[62] = x[26] - f[31]; + f[63] = x[26] + f[31]; + f[64] = f[39] + f[37]; + f[65] = MUL_F(FRAC_CONST(-0.5411961001461969), f[39]); + f[66] = MUL_F(FRAC_CONST(0.9238795325112867), f[64]); + f[67] = MUL_C(COEF_CONST(1.3065629648763766), f[37]); + f[68] = f[65] + f[66]; + f[69] = f[67] - f[66]; + f[70] = f[38] + f[36]; + f[71] = MUL_C(COEF_CONST(1.3065629648763770), f[38]); + f[72] = MUL_F(FRAC_CONST(-0.3826834323650904), f[70]); + f[73] = MUL_F(FRAC_CONST(0.5411961001461961), f[36]); + f[74] = f[71] + f[72]; + f[75] = f[73] - f[72]; + f[76] = f[47] + f[45]; + f[77] = MUL_F(FRAC_CONST(-0.5411961001461969), f[47]); + f[78] = MUL_F(FRAC_CONST(0.9238795325112867), f[76]); + f[79] = MUL_C(COEF_CONST(1.3065629648763766), f[45]); + f[80] = f[77] + f[78]; + f[81] = f[79] - f[78]; + f[82] = f[46] + f[44]; + f[83] = MUL_C(COEF_CONST(1.3065629648763770), f[46]); + f[84] = MUL_F(FRAC_CONST(-0.3826834323650904), f[82]); + f[85] = MUL_F(FRAC_CONST(0.5411961001461961), f[44]); + f[86] = f[83] + f[84]; + f[87] = f[85] - f[84]; + f[88] = f[55] + f[53]; + f[89] = MUL_F(FRAC_CONST(-0.5411961001461969), f[55]); + f[90] = MUL_F(FRAC_CONST(0.9238795325112867), f[88]); + f[91] = MUL_C(COEF_CONST(1.3065629648763766), f[53]); + f[92] = f[89] + f[90]; + f[93] = f[91] - f[90]; + f[94] = f[54] + f[52]; + f[95] = MUL_C(COEF_CONST(1.3065629648763770), f[54]); + f[96] = MUL_F(FRAC_CONST(-0.3826834323650904), f[94]); + f[97] = MUL_F(FRAC_CONST(0.5411961001461961), f[52]); + f[98] = f[95] + f[96]; + f[99] = f[97] - f[96]; + f[100] = f[63] + f[61]; + f[101] = MUL_F(FRAC_CONST(-0.5411961001461969), f[63]); + f[102] = MUL_F(FRAC_CONST(0.9238795325112867), f[100]); + f[103] = MUL_C(COEF_CONST(1.3065629648763766), f[61]); + f[104] = f[101] + f[102]; + f[105] = f[103] - f[102]; + f[106] = f[62] + f[60]; + f[107] = MUL_C(COEF_CONST(1.3065629648763770), f[62]); + f[108] = MUL_F(FRAC_CONST(-0.3826834323650904), f[106]); + f[109] = MUL_F(FRAC_CONST(0.5411961001461961), f[60]); + f[110] = f[107] + f[108]; + f[111] = f[109] - f[108]; + f[112] = f[33] - f[68]; + f[113] = f[33] + f[68]; + f[114] = f[35] - f[69]; + f[115] = f[35] + f[69]; + f[116] = f[32] - f[74]; + f[117] = f[32] + f[74]; + f[118] = f[34] - f[75]; + f[119] = f[34] + f[75]; + f[120] = f[41] - f[80]; + f[121] = f[41] + f[80]; + f[122] = f[43] - f[81]; + f[123] = f[43] + f[81]; + f[124] = f[40] - f[86]; + f[125] = f[40] + f[86]; + f[126] = f[42] - f[87]; + f[127] = f[42] + f[87]; + f[128] = f[49] - f[92]; + f[129] = f[49] + f[92]; + f[130] = f[51] - f[93]; + f[131] = f[51] + f[93]; + f[132] = f[48] - f[98]; + f[133] = f[48] + f[98]; + f[134] = f[50] - f[99]; + f[135] = f[50] + f[99]; + f[136] = f[57] - f[104]; + f[137] = f[57] + f[104]; + f[138] = f[59] - f[105]; + f[139] = f[59] + f[105]; + f[140] = f[56] - f[110]; + f[141] = f[56] + f[110]; + f[142] = f[58] - f[111]; + f[143] = f[58] + f[111]; + f[144] = f[123] + f[121]; + f[145] = MUL_F(FRAC_CONST(-0.7856949583871021), f[123]); + f[146] = MUL_F(FRAC_CONST(0.9807852804032304), f[144]); + f[147] = MUL_C(COEF_CONST(1.1758756024193588), f[121]); + f[148] = f[145] + f[146]; + f[149] = f[147] - f[146]; + f[150] = f[127] + f[125]; + f[151] = MUL_F(FRAC_CONST(0.2758993792829431), f[127]); + f[152] = MUL_F(FRAC_CONST(0.5555702330196022), f[150]); + f[153] = MUL_C(COEF_CONST(1.3870398453221475), f[125]); + f[154] = f[151] + f[152]; + f[155] = f[153] - f[152]; + f[156] = f[122] + f[120]; + f[157] = MUL_C(COEF_CONST(1.1758756024193591), f[122]); + f[158] = MUL_F(FRAC_CONST(-0.1950903220161287), f[156]); + f[159] = MUL_F(FRAC_CONST(0.7856949583871016), f[120]); + f[160] = f[157] + f[158]; + f[161] = f[159] - f[158]; + f[162] = f[126] + f[124]; + f[163] = MUL_C(COEF_CONST(1.3870398453221473), f[126]); + f[164] = MUL_F(FRAC_CONST(-0.8314696123025455), f[162]); + f[165] = MUL_F(FRAC_CONST(-0.2758993792829436), f[124]); + f[166] = f[163] + f[164]; + f[167] = f[165] - f[164]; + f[168] = f[139] + f[137]; + f[169] = MUL_F(FRAC_CONST(-0.7856949583871021), f[139]); + f[170] = MUL_F(FRAC_CONST(0.9807852804032304), f[168]); + f[171] = MUL_C(COEF_CONST(1.1758756024193588), f[137]); + f[172] = f[169] + f[170]; + f[173] = f[171] - f[170]; + f[174] = f[143] + f[141]; + f[175] = MUL_F(FRAC_CONST(0.2758993792829431), f[143]); + f[176] = MUL_F(FRAC_CONST(0.5555702330196022), f[174]); + f[177] = MUL_C(COEF_CONST(1.3870398453221475), f[141]); + f[178] = f[175] + f[176]; + f[179] = f[177] - f[176]; + f[180] = f[138] + f[136]; + f[181] = MUL_C(COEF_CONST(1.1758756024193591), f[138]); + f[182] = MUL_F(FRAC_CONST(-0.1950903220161287), f[180]); + f[183] = MUL_F(FRAC_CONST(0.7856949583871016), f[136]); + f[184] = f[181] + f[182]; + f[185] = f[183] - f[182]; + f[186] = f[142] + f[140]; + f[187] = MUL_C(COEF_CONST(1.3870398453221473), f[142]); + f[188] = MUL_F(FRAC_CONST(-0.8314696123025455), f[186]); + f[189] = MUL_F(FRAC_CONST(-0.2758993792829436), f[140]); + f[190] = f[187] + f[188]; + f[191] = f[189] - f[188]; + f[192] = f[113] - f[148]; + f[193] = f[113] + f[148]; + f[194] = f[115] - f[149]; + f[195] = f[115] + f[149]; + f[196] = f[117] - f[154]; + f[197] = f[117] + f[154]; + f[198] = f[119] - f[155]; + f[199] = f[119] + f[155]; + f[200] = f[112] - f[160]; + f[201] = f[112] + f[160]; + f[202] = f[114] - f[161]; + f[203] = f[114] + f[161]; + f[204] = f[116] - f[166]; + f[205] = f[116] + f[166]; + f[206] = f[118] - f[167]; + f[207] = f[118] + f[167]; + f[208] = f[129] - f[172]; + f[209] = f[129] + f[172]; + f[210] = f[131] - f[173]; + f[211] = f[131] + f[173]; + f[212] = f[133] - f[178]; + f[213] = f[133] + f[178]; + f[214] = f[135] - f[179]; + f[215] = f[135] + f[179]; + f[216] = f[128] - f[184]; + f[217] = f[128] + f[184]; + f[218] = f[130] - f[185]; + f[219] = f[130] + f[185]; + f[220] = f[132] - f[190]; + f[221] = f[132] + f[190]; + f[222] = f[134] - f[191]; + f[223] = f[134] + f[191]; + f[224] = f[211] + f[209]; + f[225] = MUL_F(FRAC_CONST(-0.8971675863426361), f[211]); + f[226] = MUL_F(FRAC_CONST(0.9951847266721968), f[224]); + f[227] = MUL_C(COEF_CONST(1.0932018670017576), f[209]); + f[228] = f[225] + f[226]; + f[229] = f[227] - f[226]; + f[230] = f[215] + f[213]; + f[231] = MUL_F(FRAC_CONST(-0.4105245275223571), f[215]); + f[232] = MUL_F(FRAC_CONST(0.8819212643483549), f[230]); + f[233] = MUL_C(COEF_CONST(1.3533180011743529), f[213]); + f[234] = f[231] + f[232]; + f[235] = f[233] - f[232]; + f[236] = f[219] + f[217]; + f[237] = MUL_F(FRAC_CONST(0.1386171691990915), f[219]); + f[238] = MUL_F(FRAC_CONST(0.6343932841636455), f[236]); + f[239] = MUL_C(COEF_CONST(1.4074037375263826), f[217]); + f[240] = f[237] + f[238]; + f[241] = f[239] - f[238]; + f[242] = f[223] + f[221]; + f[243] = MUL_F(FRAC_CONST(0.6666556584777466), f[223]); + f[244] = MUL_F(FRAC_CONST(0.2902846772544623), f[242]); + f[245] = MUL_C(COEF_CONST(1.2472250129866711), f[221]); + f[246] = f[243] + f[244]; + f[247] = f[245] - f[244]; + f[248] = f[210] + f[208]; + f[249] = MUL_C(COEF_CONST(1.0932018670017574), f[210]); + f[250] = MUL_F(FRAC_CONST(-0.0980171403295605), f[248]); + f[251] = MUL_F(FRAC_CONST(0.8971675863426364), f[208]); + f[252] = f[249] + f[250]; + f[253] = f[251] - f[250]; + f[254] = f[214] + f[212]; + f[255] = MUL_C(COEF_CONST(1.3533180011743529), f[214]); + f[256] = MUL_F(FRAC_CONST(-0.4713967368259979), f[254]); + f[257] = MUL_F(FRAC_CONST(0.4105245275223569), f[212]); + f[258] = f[255] + f[256]; + f[259] = f[257] - f[256]; + f[260] = f[218] + f[216]; + f[261] = MUL_C(COEF_CONST(1.4074037375263826), f[218]); + f[262] = MUL_F(FRAC_CONST(-0.7730104533627369), f[260]); + f[263] = MUL_F(FRAC_CONST(-0.1386171691990913), f[216]); + f[264] = f[261] + f[262]; + f[265] = f[263] - f[262]; + f[266] = f[222] + f[220]; + f[267] = MUL_C(COEF_CONST(1.2472250129866711), f[222]); + f[268] = MUL_F(FRAC_CONST(-0.9569403357322089), f[266]); + f[269] = MUL_F(FRAC_CONST(-0.6666556584777469), f[220]); + f[270] = f[267] + f[268]; + f[271] = f[269] - f[268]; + f[272] = f[193] - f[228]; + f[273] = f[193] + f[228]; + f[274] = f[195] - f[229]; + f[275] = f[195] + f[229]; + f[276] = f[197] - f[234]; + f[277] = f[197] + f[234]; + f[278] = f[199] - f[235]; + f[279] = f[199] + f[235]; + f[280] = f[201] - f[240]; + f[281] = f[201] + f[240]; + f[282] = f[203] - f[241]; + f[283] = f[203] + f[241]; + f[284] = f[205] - f[246]; + f[285] = f[205] + f[246]; + f[286] = f[207] - f[247]; + f[287] = f[207] + f[247]; + f[288] = f[192] - f[252]; + f[289] = f[192] + f[252]; + f[290] = f[194] - f[253]; + f[291] = f[194] + f[253]; + f[292] = f[196] - f[258]; + f[293] = f[196] + f[258]; + f[294] = f[198] - f[259]; + f[295] = f[198] + f[259]; + f[296] = f[200] - f[264]; + f[297] = f[200] + f[264]; + f[298] = f[202] - f[265]; + f[299] = f[202] + f[265]; + f[300] = f[204] - f[270]; + f[301] = f[204] + f[270]; + f[302] = f[206] - f[271]; + f[303] = f[206] + f[271]; + f[304] = f[275] + f[273]; + f[305] = MUL_F(FRAC_CONST(-0.9751575901732920), f[275]); + f[306] = MUL_F(FRAC_CONST(0.9996988186962043), f[304]); + f[307] = MUL_C(COEF_CONST(1.0242400472191164), f[273]); + y[0] = f[305] + f[306]; + y[31] = f[307] - f[306]; + f[310] = f[279] + f[277]; + f[311] = MUL_F(FRAC_CONST(-0.8700688593994936), f[279]); + f[312] = MUL_F(FRAC_CONST(0.9924795345987100), f[310]); + f[313] = MUL_C(COEF_CONST(1.1148902097979263), f[277]); + y[2] = f[311] + f[312]; + y[29] = f[313] - f[312]; + f[316] = f[283] + f[281]; + f[317] = MUL_F(FRAC_CONST(-0.7566008898816587), f[283]); + f[318] = MUL_F(FRAC_CONST(0.9757021300385286), f[316]); + f[319] = MUL_C(COEF_CONST(1.1948033701953984), f[281]); + y[4] = f[317] + f[318]; + y[27] = f[319] - f[318]; + f[322] = f[287] + f[285]; + f[323] = MUL_F(FRAC_CONST(-0.6358464401941451), f[287]); + f[324] = MUL_F(FRAC_CONST(0.9495281805930367), f[322]); + f[325] = MUL_C(COEF_CONST(1.2632099209919283), f[285]); + y[6] = f[323] + f[324]; + y[25] = f[325] - f[324]; + f[328] = f[291] + f[289]; + f[329] = MUL_F(FRAC_CONST(-0.5089684416985408), f[291]); + f[330] = MUL_F(FRAC_CONST(0.9142097557035307), f[328]); + f[331] = MUL_C(COEF_CONST(1.3194510697085207), f[289]); + y[8] = f[329] + f[330]; + y[23] = f[331] - f[330]; + f[334] = f[295] + f[293]; + f[335] = MUL_F(FRAC_CONST(-0.3771887988789273), f[295]); + f[336] = MUL_F(FRAC_CONST(0.8700869911087114), f[334]); + f[337] = MUL_C(COEF_CONST(1.3629851833384954), f[293]); + y[10] = f[335] + f[336]; + y[21] = f[337] - f[336]; + f[340] = f[299] + f[297]; + f[341] = MUL_F(FRAC_CONST(-0.2417766217337384), f[299]); + f[342] = MUL_F(FRAC_CONST(0.8175848131515837), f[340]); + f[343] = MUL_C(COEF_CONST(1.3933930045694289), f[297]); + y[12] = f[341] + f[342]; + y[19] = f[343] - f[342]; + f[346] = f[303] + f[301]; + f[347] = MUL_F(FRAC_CONST(-0.1040360035527077), f[303]); + f[348] = MUL_F(FRAC_CONST(0.7572088465064845), f[346]); + f[349] = MUL_C(COEF_CONST(1.4103816894602612), f[301]); + y[14] = f[347] + f[348]; + y[17] = f[349] - f[348]; + f[352] = f[274] + f[272]; + f[353] = MUL_F(FRAC_CONST(0.0347065382144002), f[274]); + f[354] = MUL_F(FRAC_CONST(0.6895405447370668), f[352]); + f[355] = MUL_C(COEF_CONST(1.4137876276885337), f[272]); + y[16] = f[353] + f[354]; + y[15] = f[355] - f[354]; + f[358] = f[278] + f[276]; + f[359] = MUL_F(FRAC_CONST(0.1731148370459795), f[278]); + f[360] = MUL_F(FRAC_CONST(0.6152315905806268), f[358]); + f[361] = MUL_C(COEF_CONST(1.4035780182072330), f[276]); + y[18] = f[359] + f[360]; + y[13] = f[361] - f[360]; + f[364] = f[282] + f[280]; + f[365] = MUL_F(FRAC_CONST(0.3098559453626100), f[282]); + f[366] = MUL_F(FRAC_CONST(0.5349976198870972), f[364]); + f[367] = MUL_C(COEF_CONST(1.3798511851368043), f[280]); + y[20] = f[365] + f[366]; + y[11] = f[367] - f[366]; + f[370] = f[286] + f[284]; + f[371] = MUL_F(FRAC_CONST(0.4436129715409088), f[286]); + f[372] = MUL_F(FRAC_CONST(0.4496113296546065), f[370]); + f[373] = MUL_C(COEF_CONST(1.3428356308501219), f[284]); + y[22] = f[371] + f[372]; + y[9] = f[373] - f[372]; + f[376] = f[290] + f[288]; + f[377] = MUL_F(FRAC_CONST(0.5730977622997509), f[290]); + f[378] = MUL_F(FRAC_CONST(0.3598950365349881), f[376]); + f[379] = MUL_C(COEF_CONST(1.2928878353697271), f[288]); + y[24] = f[377] + f[378]; + y[7] = f[379] - f[378]; + f[382] = f[294] + f[292]; + f[383] = MUL_F(FRAC_CONST(0.6970633083205415), f[294]); + f[384] = MUL_F(FRAC_CONST(0.2667127574748984), f[382]); + f[385] = MUL_C(COEF_CONST(1.2304888232703382), f[292]); + y[26] = f[383] + f[384]; + y[5] = f[385] - f[384]; + f[388] = f[298] + f[296]; + f[389] = MUL_F(FRAC_CONST(0.8143157536286401), f[298]); + f[390] = MUL_F(FRAC_CONST(0.1709618887603012), f[388]); + f[391] = MUL_C(COEF_CONST(1.1562395311492424), f[296]); + y[28] = f[389] + f[390]; + y[3] = f[391] - f[390]; + f[394] = f[302] + f[300]; + f[395] = MUL_F(FRAC_CONST(0.9237258930790228), f[302]); + f[396] = MUL_F(FRAC_CONST(0.0735645635996674), f[394]); + f[397] = MUL_C(COEF_CONST(1.0708550202783576), f[300]); + y[30] = f[395] + f[396]; + y[1] = f[397] - f[396]; + if (f) { faad_free(&f); } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::DST4_32(real_t* y, real_t* x) { + // printf(ANSI_ESC_YELLOW "DST4_32" ANSI_ESC_WHITE "\n"); + int32_t* f = (int32_t*)faad_malloc(336 * sizeof(int32_t)); + f[0] = x[0] - x[1]; + f[1] = x[2] - x[1]; + f[2] = x[2] - x[3]; + f[3] = x[4] - x[3]; + f[4] = x[4] - x[5]; + f[5] = x[6] - x[5]; + f[6] = x[6] - x[7]; + f[7] = x[8] - x[7]; + f[8] = x[8] - x[9]; + f[9] = x[10] - x[9]; + f[10] = x[10] - x[11]; + f[11] = x[12] - x[11]; + f[12] = x[12] - x[13]; + f[13] = x[14] - x[13]; + f[14] = x[14] - x[15]; + f[15] = x[16] - x[15]; + f[16] = x[16] - x[17]; + f[17] = x[18] - x[17]; + f[18] = x[18] - x[19]; + f[19] = x[20] - x[19]; + f[20] = x[20] - x[21]; + f[21] = x[22] - x[21]; + f[22] = x[22] - x[23]; + f[23] = x[24] - x[23]; + f[24] = x[24] - x[25]; + f[25] = x[26] - x[25]; + f[26] = x[26] - x[27]; + f[27] = x[28] - x[27]; + f[28] = x[28] - x[29]; + f[29] = x[30] - x[29]; + f[30] = x[30] - x[31]; + f[31] = MUL_F(FRAC_CONST(0.7071067811865476), f[15]); + f[32] = x[0] - f[31]; + f[33] = x[0] + f[31]; + f[34] = f[7] + f[23]; + f[35] = MUL_C(COEF_CONST(1.3065629648763766), f[7]); + f[36] = MUL_F(FRAC_CONST(-0.9238795325112866), f[34]); + f[37] = MUL_F(FRAC_CONST(-0.5411961001461967), f[23]); + f[38] = f[35] + f[36]; + f[39] = f[37] - f[36]; + f[40] = f[33] - f[39]; + f[41] = f[33] + f[39]; + f[42] = f[32] - f[38]; + f[43] = f[32] + f[38]; + f[44] = f[11] - f[19]; + f[45] = f[11] + f[19]; + f[46] = MUL_F(FRAC_CONST(0.7071067811865476), f[45]); + f[47] = f[3] - f[46]; + f[48] = f[3] + f[46]; + f[49] = MUL_F(FRAC_CONST(0.7071067811865476), f[44]); + f[50] = f[49] - f[27]; + f[51] = f[49] + f[27]; + f[52] = f[51] + f[48]; + f[53] = MUL_F(FRAC_CONST(-0.7856949583871021), f[51]); + f[54] = MUL_F(FRAC_CONST(0.9807852804032304), f[52]); + f[55] = MUL_C(COEF_CONST(1.1758756024193588), f[48]); + f[56] = f[53] + f[54]; + f[57] = f[55] - f[54]; + f[58] = f[50] + f[47]; + f[59] = MUL_F(FRAC_CONST(-0.2758993792829430), f[50]); + f[60] = MUL_F(FRAC_CONST(0.8314696123025452), f[58]); + f[61] = MUL_C(COEF_CONST(1.3870398453221475), f[47]); + f[62] = f[59] + f[60]; + f[63] = f[61] - f[60]; + f[64] = f[41] - f[56]; + f[65] = f[41] + f[56]; + f[66] = f[43] - f[62]; + f[67] = f[43] + f[62]; + f[68] = f[42] - f[63]; + f[69] = f[42] + f[63]; + f[70] = f[40] - f[57]; + f[71] = f[40] + f[57]; + f[72] = f[5] - f[9]; + f[73] = f[5] + f[9]; + f[74] = f[13] - f[17]; + f[75] = f[13] + f[17]; + f[76] = f[21] - f[25]; + f[77] = f[21] + f[25]; + f[78] = MUL_F(FRAC_CONST(0.7071067811865476), f[75]); + f[79] = f[1] - f[78]; + f[80] = f[1] + f[78]; + f[81] = f[73] + f[77]; + f[82] = MUL_C(COEF_CONST(1.3065629648763766), f[73]); + f[83] = MUL_F(FRAC_CONST(-0.9238795325112866), f[81]); + f[84] = MUL_F(FRAC_CONST(-0.5411961001461967), f[77]); + f[85] = f[82] + f[83]; + f[86] = f[84] - f[83]; + f[87] = f[80] - f[86]; + f[88] = f[80] + f[86]; + f[89] = f[79] - f[85]; + f[90] = f[79] + f[85]; + f[91] = MUL_F(FRAC_CONST(0.7071067811865476), f[74]); + f[92] = f[29] - f[91]; + f[93] = f[29] + f[91]; + f[94] = f[76] + f[72]; + f[95] = MUL_C(COEF_CONST(1.3065629648763766), f[76]); + f[96] = MUL_F(FRAC_CONST(-0.9238795325112866), f[94]); + f[97] = MUL_F(FRAC_CONST(-0.5411961001461967), f[72]); + f[98] = f[95] + f[96]; + f[99] = f[97] - f[96]; + f[100] = f[93] - f[99]; + f[101] = f[93] + f[99]; + f[102] = f[92] - f[98]; + f[103] = f[92] + f[98]; + f[104] = f[101] + f[88]; + f[105] = MUL_F(FRAC_CONST(-0.8971675863426361), f[101]); + f[106] = MUL_F(FRAC_CONST(0.9951847266721968), f[104]); + f[107] = MUL_C(COEF_CONST(1.0932018670017576), f[88]); + f[108] = f[105] + f[106]; + f[109] = f[107] - f[106]; + f[110] = f[90] - f[103]; + f[111] = MUL_F(FRAC_CONST(-0.6666556584777466), f[103]); + f[112] = MUL_F(FRAC_CONST(0.9569403357322089), f[110]); + f[113] = MUL_C(COEF_CONST(1.2472250129866713), f[90]); + f[114] = f[112] - f[111]; + f[115] = f[113] - f[112]; + f[116] = f[102] + f[89]; + f[117] = MUL_F(FRAC_CONST(-0.4105245275223571), f[102]); + f[118] = MUL_F(FRAC_CONST(0.8819212643483549), f[116]); + f[119] = MUL_C(COEF_CONST(1.3533180011743529), f[89]); + f[120] = f[117] + f[118]; + f[121] = f[119] - f[118]; + f[122] = f[87] - f[100]; + f[123] = MUL_F(FRAC_CONST(-0.1386171691990915), f[100]); + f[124] = MUL_F(FRAC_CONST(0.7730104533627370), f[122]); + f[125] = MUL_C(COEF_CONST(1.4074037375263826), f[87]); + f[126] = f[124] - f[123]; + f[127] = f[125] - f[124]; + f[128] = f[65] - f[108]; + f[129] = f[65] + f[108]; + f[130] = f[67] - f[114]; + f[131] = f[67] + f[114]; + f[132] = f[69] - f[120]; + f[133] = f[69] + f[120]; + f[134] = f[71] - f[126]; + f[135] = f[71] + f[126]; + f[136] = f[70] - f[127]; + f[137] = f[70] + f[127]; + f[138] = f[68] - f[121]; + f[139] = f[68] + f[121]; + f[140] = f[66] - f[115]; + f[141] = f[66] + f[115]; + f[142] = f[64] - f[109]; + f[143] = f[64] + f[109]; + f[144] = f[0] + f[30]; + f[145] = MUL_C(COEF_CONST(1.0478631305325901), f[0]); + f[146] = MUL_F(FRAC_CONST(-0.9987954562051724), f[144]); + f[147] = MUL_F(FRAC_CONST(-0.9497277818777548), f[30]); + f[148] = f[145] + f[146]; + f[149] = f[147] - f[146]; + f[150] = f[4] + f[26]; + f[151] = MUL_F(FRAC_CONST(1.2130114330978077), f[4]); + f[152] = MUL_F(FRAC_CONST(-0.9700312531945440), f[150]); + f[153] = MUL_F(FRAC_CONST(-0.7270510732912803), f[26]); + f[154] = f[151] + f[152]; + f[155] = f[153] - f[152]; + f[156] = f[8] + f[22]; + f[157] = MUL_C(COEF_CONST(1.3315443865537255), f[8]); + f[158] = MUL_F(FRAC_CONST(-0.9039892931234433), f[156]); + f[159] = MUL_F(FRAC_CONST(-0.4764341996931612), f[22]); + f[160] = f[157] + f[158]; + f[161] = f[159] - f[158]; + f[162] = f[12] + f[18]; + f[163] = MUL_C(COEF_CONST(1.3989068359730781), f[12]); + f[164] = MUL_F(FRAC_CONST(-0.8032075314806453), f[162]); + f[165] = MUL_F(FRAC_CONST(-0.2075082269882124), f[18]); + f[166] = f[163] + f[164]; + f[167] = f[165] - f[164]; + f[168] = f[16] + f[14]; + f[169] = MUL_C(COEF_CONST(1.4125100802019777), f[16]); + f[170] = MUL_F(FRAC_CONST(-0.6715589548470187), f[168]); + f[171] = MUL_F(FRAC_CONST(0.0693921705079402), f[14]); + f[172] = f[169] + f[170]; + f[173] = f[171] - f[170]; + f[174] = f[20] + f[10]; + f[175] = MUL_C(COEF_CONST(1.3718313541934939), f[20]); + f[176] = MUL_F(FRAC_CONST(-0.5141027441932219), f[174]); + f[177] = MUL_F(FRAC_CONST(0.3436258658070501), f[10]); + f[178] = f[175] + f[176]; + f[179] = f[177] - f[176]; + f[180] = f[24] + f[6]; + f[181] = MUL_C(COEF_CONST(1.2784339185752409), f[24]); + f[182] = MUL_F(FRAC_CONST(-0.3368898533922200), f[180]); + f[183] = MUL_F(FRAC_CONST(0.6046542117908008), f[6]); + f[184] = f[181] + f[182]; + f[185] = f[183] - f[182]; + f[186] = f[28] + f[2]; + f[187] = MUL_C(COEF_CONST(1.1359069844201433), f[28]); + f[188] = MUL_F(FRAC_CONST(-0.1467304744553624), f[186]); + f[189] = MUL_F(FRAC_CONST(0.8424460355094185), f[2]); + f[190] = f[187] + f[188]; + f[191] = f[189] - f[188]; + f[192] = f[149] - f[173]; + f[193] = f[149] + f[173]; + f[194] = f[148] - f[172]; + f[195] = f[148] + f[172]; + f[196] = f[155] - f[179]; + f[197] = f[155] + f[179]; + f[198] = f[154] - f[178]; + f[199] = f[154] + f[178]; + f[200] = f[161] - f[185]; + f[201] = f[161] + f[185]; + f[202] = f[160] - f[184]; + f[203] = f[160] + f[184]; + f[204] = f[167] - f[191]; + f[205] = f[167] + f[191]; + f[206] = f[166] - f[190]; + f[207] = f[166] + f[190]; + f[208] = f[192] + f[194]; + f[209] = MUL_C(COEF_CONST(1.1758756024193588), f[192]); + f[210] = MUL_F(FRAC_CONST(-0.9807852804032304), f[208]); + f[211] = MUL_F(FRAC_CONST(-0.7856949583871021), f[194]); + f[212] = f[209] + f[210]; + f[213] = f[211] - f[210]; + f[214] = f[196] + f[198]; + f[215] = MUL_C(COEF_CONST(1.3870398453221475), f[196]); + f[216] = MUL_F(FRAC_CONST(-0.5555702330196022), f[214]); + f[217] = MUL_F(FRAC_CONST(0.2758993792829431), f[198]); + f[218] = f[215] + f[216]; + f[219] = f[217] - f[216]; + f[220] = f[200] + f[202]; + f[221] = MUL_F(FRAC_CONST(0.7856949583871022), f[200]); + f[222] = MUL_F(FRAC_CONST(0.1950903220161283), f[220]); + f[223] = MUL_C(COEF_CONST(1.1758756024193586), f[202]); + f[224] = f[221] + f[222]; + f[225] = f[223] - f[222]; + f[226] = f[204] + f[206]; + f[227] = MUL_F(FRAC_CONST(-0.2758993792829430), f[204]); + f[228] = MUL_F(FRAC_CONST(0.8314696123025452), f[226]); + f[229] = MUL_C(COEF_CONST(1.3870398453221475), f[206]); + f[230] = f[227] + f[228]; + f[231] = f[229] - f[228]; + f[232] = f[193] - f[201]; + f[233] = f[193] + f[201]; + f[234] = f[195] - f[203]; + f[235] = f[195] + f[203]; + f[236] = f[197] - f[205]; + f[237] = f[197] + f[205]; + f[238] = f[199] - f[207]; + f[239] = f[199] + f[207]; + f[240] = f[213] - f[225]; + f[241] = f[213] + f[225]; + f[242] = f[212] - f[224]; + f[243] = f[212] + f[224]; + f[244] = f[219] - f[231]; + f[245] = f[219] + f[231]; + f[246] = f[218] - f[230]; + f[247] = f[218] + f[230]; + f[248] = f[232] + f[234]; + f[249] = MUL_C(COEF_CONST(1.3065629648763766), f[232]); + f[250] = MUL_F(FRAC_CONST(-0.9238795325112866), f[248]); + f[251] = MUL_F(FRAC_CONST(-0.5411961001461967), f[234]); + f[252] = f[249] + f[250]; + f[253] = f[251] - f[250]; + f[254] = f[236] + f[238]; + f[255] = MUL_F(FRAC_CONST(0.5411961001461969), f[236]); + f[256] = MUL_F(FRAC_CONST(0.3826834323650898), f[254]); + f[257] = MUL_C(COEF_CONST(1.3065629648763766), f[238]); + f[258] = f[255] + f[256]; + f[259] = f[257] - f[256]; + f[260] = f[240] + f[242]; + f[261] = MUL_C(COEF_CONST(1.3065629648763766), f[240]); + f[262] = MUL_F(FRAC_CONST(-0.9238795325112866), f[260]); + f[263] = MUL_F(FRAC_CONST(-0.5411961001461967), f[242]); + f[264] = f[261] + f[262]; + f[265] = f[263] - f[262]; + f[266] = f[244] + f[246]; + f[267] = MUL_F(FRAC_CONST(0.5411961001461969), f[244]); + f[268] = MUL_F(FRAC_CONST(0.3826834323650898), f[266]); + f[269] = MUL_C(COEF_CONST(1.3065629648763766), f[246]); + f[270] = f[267] + f[268]; + f[271] = f[269] - f[268]; + f[272] = f[233] - f[237]; + f[273] = f[233] + f[237]; + f[274] = f[235] - f[239]; + f[275] = f[235] + f[239]; + f[276] = f[253] - f[259]; + f[277] = f[253] + f[259]; + f[278] = f[252] - f[258]; + f[279] = f[252] + f[258]; + f[280] = f[241] - f[245]; + f[281] = f[241] + f[245]; + f[282] = f[243] - f[247]; + f[283] = f[243] + f[247]; + f[284] = f[265] - f[271]; + f[285] = f[265] + f[271]; + f[286] = f[264] - f[270]; + f[287] = f[264] + f[270]; + f[288] = f[272] - f[274]; + f[289] = f[272] + f[274]; + f[290] = MUL_F(FRAC_CONST(0.7071067811865474), f[288]); + f[291] = MUL_F(FRAC_CONST(0.7071067811865474), f[289]); + f[292] = f[276] - f[278]; + f[293] = f[276] + f[278]; + f[294] = MUL_F(FRAC_CONST(0.7071067811865474), f[292]); + f[295] = MUL_F(FRAC_CONST(0.7071067811865474), f[293]); + f[296] = f[280] - f[282]; + f[297] = f[280] + f[282]; + f[298] = MUL_F(FRAC_CONST(0.7071067811865474), f[296]); + f[299] = MUL_F(FRAC_CONST(0.7071067811865474), f[297]); + f[300] = f[284] - f[286]; + f[301] = f[284] + f[286]; + f[302] = MUL_F(FRAC_CONST(0.7071067811865474), f[300]); + f[303] = MUL_F(FRAC_CONST(0.7071067811865474), f[301]); + f[304] = f[129] - f[273]; + f[305] = f[129] + f[273]; + f[306] = f[131] - f[281]; + f[307] = f[131] + f[281]; + f[308] = f[133] - f[285]; + f[309] = f[133] + f[285]; + f[310] = f[135] - f[277]; + f[311] = f[135] + f[277]; + f[312] = f[137] - f[295]; + f[313] = f[137] + f[295]; + f[314] = f[139] - f[303]; + f[315] = f[139] + f[303]; + f[316] = f[141] - f[299]; + f[317] = f[141] + f[299]; + f[318] = f[143] - f[291]; + f[319] = f[143] + f[291]; + f[320] = f[142] - f[290]; + f[321] = f[142] + f[290]; + f[322] = f[140] - f[298]; + f[323] = f[140] + f[298]; + f[324] = f[138] - f[302]; + f[325] = f[138] + f[302]; + f[326] = f[136] - f[294]; + f[327] = f[136] + f[294]; + f[328] = f[134] - f[279]; + f[329] = f[134] + f[279]; + f[330] = f[132] - f[287]; + f[331] = f[132] + f[287]; + f[332] = f[130] - f[283]; + f[333] = f[130] + f[283]; + f[334] = f[128] - f[275]; + f[335] = f[128] + f[275]; + y[31] = MUL_F(FRAC_CONST(0.5001506360206510), f[305]); + y[30] = MUL_F(FRAC_CONST(0.5013584524464084), f[307]); + y[29] = MUL_F(FRAC_CONST(0.5037887256810443), f[309]); + y[28] = MUL_F(FRAC_CONST(0.5074711720725553), f[311]); + y[27] = MUL_F(FRAC_CONST(0.5124514794082247), f[313]); + y[26] = MUL_F(FRAC_CONST(0.5187927131053328), f[315]); + y[25] = MUL_F(FRAC_CONST(0.5265773151542700), f[317]); + y[24] = MUL_F(FRAC_CONST(0.5359098169079920), f[319]); + y[23] = MUL_F(FRAC_CONST(0.5469204379855088), f[321]); + y[22] = MUL_F(FRAC_CONST(0.5597698129470802), f[323]); + y[21] = MUL_F(FRAC_CONST(0.5746551840326600), f[325]); + y[20] = MUL_F(FRAC_CONST(0.5918185358574165), f[327]); + y[19] = MUL_F(FRAC_CONST(0.6115573478825099), f[329]); + y[18] = MUL_F(FRAC_CONST(0.6342389366884031), f[331]); + y[17] = MUL_F(FRAC_CONST(0.6603198078137061), f[333]); + y[16] = MUL_F(FRAC_CONST(0.6903721282002123), f[335]); + y[15] = MUL_F(FRAC_CONST(0.7251205223771985), f[334]); + y[14] = MUL_F(FRAC_CONST(0.7654941649730891), f[332]); + y[13] = MUL_F(FRAC_CONST(0.8127020908144905), f[330]); + y[12] = MUL_F(FRAC_CONST(0.8683447152233481), f[328]); + y[11] = MUL_F(FRAC_CONST(0.9345835970364075), f[326]); + y[10] = MUL_C(COEF_CONST(1.0144082649970547), f[324]); + y[9] = MUL_C(COEF_CONST(1.1120716205797176), f[322]); + y[8] = MUL_C(COEF_CONST(1.2338327379765710), f[320]); + y[7] = MUL_C(COEF_CONST(1.3892939586328277), f[318]); + y[6] = MUL_C(COEF_CONST(1.5939722833856311), f[316]); + y[5] = MUL_C(COEF_CONST(1.8746759800084078), f[314]); + y[4] = MUL_C(COEF_CONST(2.2820500680051619), f[312]); + y[3] = MUL_C(COEF_CONST(2.9246284281582162), f[310]); + y[2] = MUL_C(COEF_CONST(4.0846110781292477), f[308]); + y[1] = MUL_C(COEF_CONST(6.7967507116736332), f[306]); + y[0] = MUL_R(REAL_CONST(20.3738781672314530), f[304]); + if (f) { faad_free(&f); } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::DCT2_16_unscaled(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10; + real_t f11, f12, f13, f14, f15, f16, f17, f18, f19, f20; + real_t f21, f22, f23, f24, f25, f26, f27, f28, f31, f32; + real_t f33, f34, f37, f38, f39, f40, f41, f42, f43, f44; + real_t f45, f46, f47, f48, f49, f51, f53, f54, f57, f58; + real_t f59, f60, f61, f62, f63, f64, f65, f66, f67, f68; + real_t f69, f70, f71, f72, f73, f74, f75, f76, f77, f78; + real_t f79, f80, f81, f82, f83, f84, f85, f86, f87, f88; + real_t f89, f90, f91, f92, f95, f96, f97, f98, f101, f102; + real_t f103, f104, f107, f108, f109, f110; + f0 = x[0] - x[15]; + f1 = x[0] + x[15]; + f2 = x[1] - x[14]; + f3 = x[1] + x[14]; + f4 = x[2] - x[13]; + f5 = x[2] + x[13]; + f6 = x[3] - x[12]; + f7 = x[3] + x[12]; + f8 = x[4] - x[11]; + f9 = x[4] + x[11]; + f10 = x[5] - x[10]; + f11 = x[5] + x[10]; + f12 = x[6] - x[9]; + f13 = x[6] + x[9]; + f14 = x[7] - x[8]; + f15 = x[7] + x[8]; + f16 = f1 - f15; + f17 = f1 + f15; + f18 = f3 - f13; + f19 = f3 + f13; + f20 = f5 - f11; + f21 = f5 + f11; + f22 = f7 - f9; + f23 = f7 + f9; + f24 = f17 - f23; + f25 = f17 + f23; + f26 = f19 - f21; + f27 = f19 + f21; + f28 = f25 - f27; + y[0] = f25 + f27; + y[8] = MUL_F(f28, FRAC_CONST(0.7071067811865476)); + f31 = f24 + f26; + f32 = MUL_C(f24, COEF_CONST(1.3065629648763766)); + f33 = MUL_F(f31, FRAC_CONST(-0.9238795325112866)); + f34 = MUL_F(f26, FRAC_CONST(-0.5411961001461967)); + y[12] = f32 + f33; + y[4] = f34 - f33; + f37 = f16 + f22; + f38 = MUL_C(f16, COEF_CONST(1.1758756024193588)); + f39 = MUL_F(f37, FRAC_CONST(-0.9807852804032304)); + f40 = MUL_F(f22, FRAC_CONST(-0.7856949583871021)); + f41 = f38 + f39; + f42 = f40 - f39; + f43 = f18 + f20; + f44 = MUL_C(f18, COEF_CONST(1.3870398453221473)); + f45 = MUL_F(f43, FRAC_CONST(-0.8314696123025455)); + f46 = MUL_F(f20, FRAC_CONST(-0.2758993792829436)); + f47 = f44 + f45; + f48 = f46 - f45; + f49 = f42 - f48; + y[2] = f42 + f48; + f51 = MUL_F(f49, FRAC_CONST(0.7071067811865476)); + y[14] = f41 - f47; + f53 = f41 + f47; + f54 = MUL_F(f53, FRAC_CONST(0.7071067811865476)); + y[10] = f51 - f54; + y[6] = f51 + f54; + f57 = f2 - f4; + f58 = f2 + f4; + f59 = f6 - f8; + f60 = f6 + f8; + f61 = f10 - f12; + f62 = f10 + f12; + f63 = MUL_F(f60, FRAC_CONST(0.7071067811865476)); + f64 = f0 - f63; + f65 = f0 + f63; + f66 = f58 + f62; + f67 = MUL_C(f58, COEF_CONST(1.3065629648763766)); + f68 = MUL_F(f66, FRAC_CONST(-0.9238795325112866)); + f69 = MUL_F(f62, FRAC_CONST(-0.5411961001461967)); + f70 = f67 + f68; + f71 = f69 - f68; + f72 = f65 - f71; + f73 = f65 + f71; + f74 = f64 - f70; + f75 = f64 + f70; + f76 = MUL_F(f59, FRAC_CONST(0.7071067811865476)); + f77 = f14 - f76; + f78 = f14 + f76; + f79 = f61 + f57; + f80 = MUL_C(f61, COEF_CONST(1.3065629648763766)); + f81 = MUL_F(f79, FRAC_CONST(-0.9238795325112866)); + f82 = MUL_F(f57, FRAC_CONST(-0.5411961001461967)); + f83 = f80 + f81; + f84 = f82 - f81; + f85 = f78 - f84; + f86 = f78 + f84; + f87 = f77 - f83; + f88 = f77 + f83; + f89 = f86 + f73; + f90 = MUL_F(f86, FRAC_CONST(-0.8971675863426361)); + f91 = MUL_F(f89, FRAC_CONST(0.9951847266721968)); + f92 = MUL_C(f73, COEF_CONST(1.0932018670017576)); + y[1] = f90 + f91; + y[15] = f92 - f91; + f95 = f75 - f88; + f96 = MUL_F(f88, FRAC_CONST(-0.6666556584777466)); + f97 = MUL_F(f95, FRAC_CONST(0.9569403357322089)); + f98 = MUL_C(f75, COEF_CONST(1.2472250129866713)); + y[3] = f97 - f96; + y[13] = f98 - f97; + f101 = f87 + f74; + f102 = MUL_F(f87, FRAC_CONST(-0.4105245275223571)); + f103 = MUL_F(f101, FRAC_CONST(0.8819212643483549)); + f104 = MUL_C(f74, COEF_CONST(1.3533180011743529)); + y[5] = f102 + f103; + y[11] = f104 - f103; + f107 = f72 - f85; + f108 = MUL_F(f85, FRAC_CONST(-0.1386171691990915)); + f109 = MUL_F(f107, FRAC_CONST(0.7730104533627370)); + f110 = MUL_C(f72, COEF_CONST(1.4074037375263826)); + y[7] = f109 - f108; + y[9] = f110 - f109; +} + #endif +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::DCT4_16(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10; + real_t f11, f12, f13, f14, f15, f16, f17, f18, f19, f20; + real_t f21, f22, f23, f24, f25, f26, f27, f28, f29, f30; + real_t f31, f32, f33, f34, f35, f36, f37, f38, f39, f40; + real_t f41, f42, f43, f44, f45, f46, f47, f48, f49, f50; + real_t f51, f52, f53, f54, f55, f56, f57, f58, f59, f60; + real_t f61, f62, f63, f64, f65, f66, f67, f68, f69, f70; + real_t f71, f72, f73, f74, f75, f76, f77, f78, f79, f80; + real_t f81, f82, f83, f84, f85, f86, f87, f88, f89, f90; + real_t f91, f92, f93, f94, f95, f96, f97, f98, f99, f100; + real_t f101, f102, f103, f104, f105, f106, f107, f108, f109, f110; + real_t f111, f112, f113, f114, f115, f116, f117, f118, f119, f120; + real_t f121, f122, f123, f124, f125, f126, f127, f128, f130, f132; + real_t f134, f136, f138, f140, f142, f144, f145, f148, f149, f152; + real_t f153, f156, f157; + f0 = x[0] + x[15]; + f1 = MUL_C(COEF_CONST(1.0478631305325901), x[0]); + f2 = MUL_F(FRAC_CONST(-0.9987954562051724), f0); + f3 = MUL_F(FRAC_CONST(-0.9497277818777548), x[15]); + f4 = f1 + f2; + f5 = f3 - f2; + f6 = x[2] + x[13]; + f7 = MUL_C(COEF_CONST(1.2130114330978077), x[2]); + f8 = MUL_F(FRAC_CONST(-0.9700312531945440), f6); + f9 = MUL_F(FRAC_CONST(-0.7270510732912803), x[13]); + f10 = f7 + f8; + f11 = f9 - f8; + f12 = x[4] + x[11]; + f13 = MUL_C(COEF_CONST(1.3315443865537255), x[4]); + f14 = MUL_F(FRAC_CONST(-0.9039892931234433), f12); + f15 = MUL_F(FRAC_CONST(-0.4764341996931612), x[11]); + f16 = f13 + f14; + f17 = f15 - f14; + f18 = x[6] + x[9]; + f19 = MUL_C(COEF_CONST(1.3989068359730781), x[6]); + f20 = MUL_F(FRAC_CONST(-0.8032075314806453), f18); + f21 = MUL_F(FRAC_CONST(-0.2075082269882124), x[9]); + f22 = f19 + f20; + f23 = f21 - f20; + f24 = x[8] + x[7]; + f25 = MUL_C(COEF_CONST(1.4125100802019777), x[8]); + f26 = MUL_F(FRAC_CONST(-0.6715589548470187), f24); + f27 = MUL_F(FRAC_CONST(0.0693921705079402), x[7]); + f28 = f25 + f26; + f29 = f27 - f26; + f30 = x[10] + x[5]; + f31 = MUL_C(COEF_CONST(1.3718313541934939), x[10]); + f32 = MUL_F(FRAC_CONST(-0.5141027441932219), f30); + f33 = MUL_F(FRAC_CONST(0.3436258658070501), x[5]); + f34 = f31 + f32; + f35 = f33 - f32; + f36 = x[12] + x[3]; + f37 = MUL_C(COEF_CONST(1.2784339185752409), x[12]); + f38 = MUL_F(FRAC_CONST(-0.3368898533922200), f36); + f39 = MUL_F(FRAC_CONST(0.6046542117908008), x[3]); + f40 = f37 + f38; + f41 = f39 - f38; + f42 = x[14] + x[1]; + f43 = MUL_C(COEF_CONST(1.1359069844201433), x[14]); + f44 = MUL_F(FRAC_CONST(-0.1467304744553624), f42); + f45 = MUL_F(FRAC_CONST(0.8424460355094185), x[1]); + f46 = f43 + f44; + f47 = f45 - f44; + f48 = f5 - f29; + f49 = f5 + f29; + f50 = f4 - f28; + f51 = f4 + f28; + f52 = f11 - f35; + f53 = f11 + f35; + f54 = f10 - f34; + f55 = f10 + f34; + f56 = f17 - f41; + f57 = f17 + f41; + f58 = f16 - f40; + f59 = f16 + f40; + f60 = f23 - f47; + f61 = f23 + f47; + f62 = f22 - f46; + f63 = f22 + f46; + f64 = f48 + f50; + f65 = MUL_C(COEF_CONST(1.1758756024193588), f48); + f66 = MUL_F(FRAC_CONST(-0.9807852804032304), f64); + f67 = MUL_F(FRAC_CONST(-0.7856949583871021), f50); + f68 = f65 + f66; + f69 = f67 - f66; + f70 = f52 + f54; + f71 = MUL_C(COEF_CONST(1.3870398453221475), f52); + f72 = MUL_F(FRAC_CONST(-0.5555702330196022), f70); + f73 = MUL_F(FRAC_CONST(0.2758993792829431), f54); + f74 = f71 + f72; + f75 = f73 - f72; + f76 = f56 + f58; + f77 = MUL_F(FRAC_CONST(0.7856949583871022), f56); + f78 = MUL_F(FRAC_CONST(0.1950903220161283), f76); + f79 = MUL_C(COEF_CONST(1.1758756024193586), f58); + f80 = f77 + f78; + f81 = f79 - f78; + f82 = f60 + f62; + f83 = MUL_F(FRAC_CONST(-0.2758993792829430), f60); + f84 = MUL_F(FRAC_CONST(0.8314696123025452), f82); + f85 = MUL_C(COEF_CONST(1.3870398453221475), f62); + f86 = f83 + f84; + f87 = f85 - f84; + f88 = f49 - f57; + f89 = f49 + f57; + f90 = f51 - f59; + f91 = f51 + f59; + f92 = f53 - f61; + f93 = f53 + f61; + f94 = f55 - f63; + f95 = f55 + f63; + f96 = f69 - f81; + f97 = f69 + f81; + f98 = f68 - f80; + f99 = f68 + f80; + f100 = f75 - f87; + f101 = f75 + f87; + f102 = f74 - f86; + f103 = f74 + f86; + f104 = f88 + f90; + f105 = MUL_C(COEF_CONST(1.3065629648763766), f88); + f106 = MUL_F(FRAC_CONST(-0.9238795325112866), f104); + f107 = MUL_F(FRAC_CONST(-0.5411961001461967), f90); + f108 = f105 + f106; + f109 = f107 - f106; + f110 = f92 + f94; + f111 = MUL_F(FRAC_CONST(0.5411961001461969), f92); + f112 = MUL_F(FRAC_CONST(0.3826834323650898), f110); + f113 = MUL_C(COEF_CONST(1.3065629648763766), f94); + f114 = f111 + f112; + f115 = f113 - f112; + f116 = f96 + f98; + f117 = MUL_C(COEF_CONST(1.3065629648763766), f96); + f118 = MUL_F(FRAC_CONST(-0.9238795325112866), f116); + f119 = MUL_F(FRAC_CONST(-0.5411961001461967), f98); + f120 = f117 + f118; + f121 = f119 - f118; + f122 = f100 + f102; + f123 = MUL_F(FRAC_CONST(0.5411961001461969), f100); + f124 = MUL_F(FRAC_CONST(0.3826834323650898), f122); + f125 = MUL_C(COEF_CONST(1.3065629648763766), f102); + f126 = f123 + f124; + f127 = f125 - f124; + f128 = f89 - f93; + y[0] = f89 + f93; + f130 = f91 - f95; + y[15] = f91 + f95; + f132 = f109 - f115; + y[3] = f109 + f115; + f134 = f108 - f114; + y[12] = f108 + f114; + f136 = f97 - f101; + y[1] = f97 + f101; + f138 = f99 - f103; + y[14] = f99 + f103; + f140 = f121 - f127; + y[2] = f121 + f127; + f142 = f120 - f126; + y[13] = f120 + f126; + f144 = f128 - f130; + f145 = f128 + f130; + y[8] = MUL_F(FRAC_CONST(0.7071067811865474), f144); + y[7] = MUL_F(FRAC_CONST(0.7071067811865474), f145); + f148 = f132 - f134; + f149 = f132 + f134; + y[11] = MUL_F(FRAC_CONST(0.7071067811865474), f148); + y[4] = MUL_F(FRAC_CONST(0.7071067811865474), f149); + f152 = f136 - f138; + f153 = f136 + f138; + y[9] = MUL_F(FRAC_CONST(0.7071067811865474), f152); + y[6] = MUL_F(FRAC_CONST(0.7071067811865474), f153); + f156 = f140 - f142; + f157 = f140 + f142; + y[10] = MUL_F(FRAC_CONST(0.7071067811865474), f156); + y[5] = MUL_F(FRAC_CONST(0.7071067811865474), f157); +} + #endif +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::DCT3_32_unscaled(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10; + real_t f11, f12, f13, f14, f15, f16, f17, f18, f19, f20; + real_t f21, f22, f23, f24, f25, f26, f27, f28, f29, f30; + real_t f31, f32, f33, f34, f35, f36, f37, f38, f39, f40; + real_t f41, f42, f43, f44, f45, f46, f47, f48, f49, f50; + real_t f51, f52, f53, f54, f55, f56, f57, f58, f59, f60; + real_t f61, f62, f63, f64, f65, f66, f67, f68, f69, f70; + real_t f71, f72, f73, f74, f75, f76, f77, f78, f79, f80; + real_t f81, f82, f83, f84, f85, f86, f87, f88, f89, f90; + real_t f91, f92, f93, f94, f95, f96, f97, f98, f99, f100; + real_t f101, f102, f103, f104, f105, f106, f107, f108, f109, f110; + real_t f111, f112, f113, f114, f115, f116, f117, f118, f119, f120; + real_t f121, f122, f123, f124, f125, f126, f127, f128, f129, f130; + real_t f131, f132, f133, f134, f135, f136, f137, f138, f139, f140; + real_t f141, f142, f143, f144, f145, f146, f147, f148, f149, f150; + real_t f151, f152, f153, f154, f155, f156, f157, f158, f159, f160; + real_t f161, f162, f163, f164, f165, f166, f167, f168, f169, f170; + real_t f171, f172, f173, f174, f175, f176, f177, f178, f179, f180; + real_t f181, f182, f183, f184, f185, f186, f187, f188, f189, f190; + real_t f191, f192, f193, f194, f195, f196, f197, f198, f199, f200; + real_t f201, f202, f203, f204, f205, f206, f207, f208, f209, f210; + real_t f211, f212, f213, f214, f215, f216, f217, f218, f219, f220; + real_t f221, f222, f223, f224, f225, f226, f227, f228, f229, f230; + real_t f231, f232, f233, f234, f235, f236, f237, f238, f239, f240; + real_t f241, f242, f243, f244, f245, f246, f247, f248, f249, f250; + real_t f251, f252, f253, f254, f255, f256, f257, f258, f259, f260; + real_t f261, f262, f263, f264, f265, f266, f267, f268, f269, f270; + real_t f271, f272; + f0 = MUL_F(x[16], FRAC_CONST(0.7071067811865476)); + f1 = x[0] - f0; + f2 = x[0] + f0; + f3 = x[8] + x[24]; + f4 = MUL_C(x[8], COEF_CONST(1.3065629648763766)); + f5 = MUL_F(f3, FRAC_CONST((-0.9238795325112866))); + f6 = MUL_F(x[24], FRAC_CONST((-0.5411961001461967))); + f7 = f4 + f5; + f8 = f6 - f5; + f9 = f2 - f8; + f10 = f2 + f8; + f11 = f1 - f7; + f12 = f1 + f7; + f13 = x[4] + x[28]; + f14 = MUL_C(x[4], COEF_CONST(1.1758756024193588)); + f15 = MUL_F(f13, FRAC_CONST((-0.9807852804032304))); + f16 = MUL_F(x[28], FRAC_CONST((-0.7856949583871021))); + f17 = f14 + f15; + f18 = f16 - f15; + f19 = x[12] + x[20]; + f20 = MUL_C(x[12], COEF_CONST(1.3870398453221473)); + f21 = MUL_F(f19, FRAC_CONST((-0.8314696123025455))); + f22 = MUL_F(x[20], FRAC_CONST((-0.2758993792829436))); + f23 = f20 + f21; + f24 = f22 - f21; + f25 = f18 - f24; + f26 = f18 + f24; + f27 = MUL_F(f25, FRAC_CONST(0.7071067811865476)); + f28 = f17 - f23; + f29 = f17 + f23; + f30 = MUL_F(f29, FRAC_CONST(0.7071067811865476)); + f31 = f27 - f30; + f32 = f27 + f30; + f33 = f10 - f26; + f34 = f10 + f26; + f35 = f12 - f32; + f36 = f12 + f32; + f37 = f11 - f31; + f38 = f11 + f31; + f39 = f9 - f28; + f40 = f9 + f28; + f41 = x[2] + x[30]; + f42 = MUL_C(x[2], COEF_CONST(1.0932018670017569)); + f43 = MUL_F(f41, FRAC_CONST((-0.9951847266721969))); + f44 = MUL_F(x[30], FRAC_CONST((-0.8971675863426368))); + f45 = f42 + f43; + f46 = f44 - f43; + f47 = x[6] + x[26]; + f48 = MUL_C(x[6], COEF_CONST(1.2472250129866711)); + f49 = MUL_F(f47, FRAC_CONST((-0.9569403357322089))); + f50 = MUL_F(x[26], FRAC_CONST((-0.6666556584777469))); + f51 = f48 + f49; + f52 = f50 - f49; + f53 = x[10] + x[22]; + f54 = MUL_C(x[10], COEF_CONST(1.3533180011743526)); + f55 = MUL_F(f53, FRAC_CONST((-0.8819212643483551))); + f56 = MUL_F(x[22], FRAC_CONST((-0.4105245275223575))); + f57 = f54 + f55; + f58 = f56 - f55; + f59 = x[14] + x[18]; + f60 = MUL_C(x[14], COEF_CONST(1.4074037375263826)); + f61 = MUL_F(f59, FRAC_CONST((-0.7730104533627369))); + f62 = MUL_F(x[18], FRAC_CONST((-0.1386171691990913))); + f63 = f60 + f61; + f64 = f62 - f61; + f65 = f46 - f64; + f66 = f46 + f64; + f67 = f52 - f58; + f68 = f52 + f58; + f69 = f66 - f68; + f70 = f66 + f68; + f71 = MUL_F(f69, FRAC_CONST(0.7071067811865476)); + f72 = f65 + f67; + f73 = MUL_C(f65, COEF_CONST(1.3065629648763766)); + f74 = MUL_F(f72, FRAC_CONST((-0.9238795325112866))); + f75 = MUL_F(f67, FRAC_CONST((-0.5411961001461967))); + f76 = f73 + f74; + f77 = f75 - f74; + f78 = f45 - f63; + f79 = f45 + f63; + f80 = f51 - f57; + f81 = f51 + f57; + f82 = f79 + f81; + f83 = MUL_C(f79, COEF_CONST(1.3065629648763770)); + f84 = MUL_F(f82, FRAC_CONST((-0.3826834323650904))); + f85 = MUL_F(f81, FRAC_CONST(0.5411961001461961)); + f86 = f83 + f84; + f87 = f85 - f84; + f88 = f78 - f80; + f89 = f78 + f80; + f90 = MUL_F(f89, FRAC_CONST(0.7071067811865476)); + f91 = f77 - f87; + f92 = f77 + f87; + f93 = f71 - f90; + f94 = f71 + f90; + f95 = f76 - f86; + f96 = f76 + f86; + f97 = f34 - f70; + f98 = f34 + f70; + f99 = f36 - f92; + f100 = f36 + f92; + f101 = f38 - f91; + f102 = f38 + f91; + f103 = f40 - f94; + f104 = f40 + f94; + f105 = f39 - f93; + f106 = f39 + f93; + f107 = f37 - f96; + f108 = f37 + f96; + f109 = f35 - f95; + f110 = f35 + f95; + f111 = f33 - f88; + f112 = f33 + f88; + f113 = x[1] + x[31]; + f114 = MUL_C(x[1], COEF_CONST(1.0478631305325901)); + f115 = MUL_F(f113, FRAC_CONST((-0.9987954562051724))); + f116 = MUL_F(x[31], FRAC_CONST((-0.9497277818777548))); + f117 = f114 + f115; + f118 = f116 - f115; + f119 = x[5] + x[27]; + f120 = MUL_C(x[5], COEF_CONST(1.2130114330978077)); + f121 = MUL_F(f119, FRAC_CONST((-0.9700312531945440))); + f122 = MUL_F(x[27], FRAC_CONST((-0.7270510732912803))); + f123 = f120 + f121; + f124 = f122 - f121; + f125 = x[9] + x[23]; + f126 = MUL_C(x[9], COEF_CONST(1.3315443865537255)); + f127 = MUL_F(f125, FRAC_CONST((-0.9039892931234433))); + f128 = MUL_F(x[23], FRAC_CONST((-0.4764341996931612))); + f129 = f126 + f127; + f130 = f128 - f127; + f131 = x[13] + x[19]; + f132 = MUL_C(x[13], COEF_CONST(1.3989068359730781)); + f133 = MUL_F(f131, FRAC_CONST((-0.8032075314806453))); + f134 = MUL_F(x[19], FRAC_CONST((-0.2075082269882124))); + f135 = f132 + f133; + f136 = f134 - f133; + f137 = x[17] + x[15]; + f138 = MUL_C(x[17], COEF_CONST(1.4125100802019777)); + f139 = MUL_F(f137, FRAC_CONST((-0.6715589548470187))); + f140 = MUL_F(x[15], FRAC_CONST(0.0693921705079402)); + f141 = f138 + f139; + f142 = f140 - f139; + f143 = x[21] + x[11]; + f144 = MUL_C(x[21], COEF_CONST(1.3718313541934939)); + f145 = MUL_F(f143, FRAC_CONST((-0.5141027441932219))); + f146 = MUL_F(x[11], FRAC_CONST(0.3436258658070501)); + f147 = f144 + f145; + f148 = f146 - f145; + f149 = x[25] + x[7]; + f150 = MUL_C(x[25], COEF_CONST(1.2784339185752409)); + f151 = MUL_F(f149, FRAC_CONST((-0.3368898533922200))); + f152 = MUL_F(x[7], FRAC_CONST(0.6046542117908008)); + f153 = f150 + f151; + f154 = f152 - f151; + f155 = x[29] + x[3]; + f156 = MUL_C(x[29], COEF_CONST(1.1359069844201433)); + f157 = MUL_F(f155, FRAC_CONST((-0.1467304744553624))); + f158 = MUL_F(x[3], FRAC_CONST(0.8424460355094185)); + f159 = f156 + f157; + f160 = f158 - f157; + f161 = f118 - f142; + f162 = f118 + f142; + f163 = f117 - f141; + f164 = f117 + f141; + f165 = f124 - f148; + f166 = f124 + f148; + f167 = f123 - f147; + f168 = f123 + f147; + f169 = f130 - f154; + f170 = f130 + f154; + f171 = f129 - f153; + f172 = f129 + f153; + f173 = f136 - f160; + f174 = f136 + f160; + f175 = f135 - f159; + f176 = f135 + f159; + f177 = f161 + f163; + f178 = MUL_C(f161, COEF_CONST(1.1758756024193588)); + f179 = MUL_F(f177, FRAC_CONST((-0.9807852804032304))); + f180 = MUL_F(f163, FRAC_CONST((-0.7856949583871021))); + f181 = f178 + f179; + f182 = f180 - f179; + f183 = f165 + f167; + f184 = MUL_C(f165, COEF_CONST(1.3870398453221475)); + f185 = MUL_F(f183, FRAC_CONST((-0.5555702330196022))); + f186 = MUL_F(f167, FRAC_CONST(0.2758993792829431)); + f187 = f184 + f185; + f188 = f186 - f185; + f189 = f169 + f171; + f190 = MUL_F(f169, FRAC_CONST(0.7856949583871022)); + f191 = MUL_F(f189, FRAC_CONST(0.1950903220161283)); + f192 = MUL_C(f171, COEF_CONST(1.1758756024193586)); + f193 = f190 + f191; + f194 = f192 - f191; + f195 = f173 + f175; + f196 = MUL_F(f173, FRAC_CONST((-0.2758993792829430))); + f197 = MUL_F(f195, FRAC_CONST(0.8314696123025452)); + f198 = MUL_C(f175, COEF_CONST(1.3870398453221475)); + f199 = f196 + f197; + f200 = f198 - f197; + f201 = f162 - f170; + f202 = f162 + f170; + f203 = f164 - f172; + f204 = f164 + f172; + f205 = f166 - f174; + f206 = f166 + f174; + f207 = f168 - f176; + f208 = f168 + f176; + f209 = f182 - f194; + f210 = f182 + f194; + f211 = f181 - f193; + f212 = f181 + f193; + f213 = f188 - f200; + f214 = f188 + f200; + f215 = f187 - f199; + f216 = f187 + f199; + f217 = f201 + f203; + f218 = MUL_C(f201, COEF_CONST(1.3065629648763766)); + f219 = MUL_F(f217, FRAC_CONST((-0.9238795325112866))); + f220 = MUL_F(f203, FRAC_CONST((-0.5411961001461967))); + f221 = f218 + f219; + f222 = f220 - f219; + f223 = f205 + f207; + f224 = MUL_F(f205, FRAC_CONST(0.5411961001461969)); + f225 = MUL_F(f223, FRAC_CONST(0.3826834323650898)); + f226 = MUL_C(f207, COEF_CONST(1.3065629648763766)); + f227 = f224 + f225; + f228 = f226 - f225; + f229 = f209 + f211; + f230 = MUL_C(f209, COEF_CONST(1.3065629648763766)); + f231 = MUL_F(f229, FRAC_CONST((-0.9238795325112866))); + f232 = MUL_F(f211, FRAC_CONST((-0.5411961001461967))); + f233 = f230 + f231; + f234 = f232 - f231; + f235 = f213 + f215; + f236 = MUL_F(f213, FRAC_CONST(0.5411961001461969)); + f237 = MUL_F(f235, FRAC_CONST(0.3826834323650898)); + f238 = MUL_C(f215, COEF_CONST(1.3065629648763766)); + f239 = f236 + f237; + f240 = f238 - f237; + f241 = f202 - f206; + f242 = f202 + f206; + f243 = f204 - f208; + f244 = f204 + f208; + f245 = f222 - f228; + f246 = f222 + f228; + f247 = f221 - f227; + f248 = f221 + f227; + f249 = f210 - f214; + f250 = f210 + f214; + f251 = f212 - f216; + f252 = f212 + f216; + f253 = f234 - f240; + f254 = f234 + f240; + f255 = f233 - f239; + f256 = f233 + f239; + f257 = f241 - f243; + f258 = f241 + f243; + f259 = MUL_F(f257, FRAC_CONST(0.7071067811865474)); + f260 = MUL_F(f258, FRAC_CONST(0.7071067811865474)); + f261 = f245 - f247; + f262 = f245 + f247; + f263 = MUL_F(f261, FRAC_CONST(0.7071067811865474)); + f264 = MUL_F(f262, FRAC_CONST(0.7071067811865474)); + f265 = f249 - f251; + f266 = f249 + f251; + f267 = MUL_F(f265, FRAC_CONST(0.7071067811865474)); + f268 = MUL_F(f266, FRAC_CONST(0.7071067811865474)); + f269 = f253 - f255; + f270 = f253 + f255; + f271 = MUL_F(f269, FRAC_CONST(0.7071067811865474)); + f272 = MUL_F(f270, FRAC_CONST(0.7071067811865474)); + y[31] = f98 - f242; + y[0] = f98 + f242; + y[30] = f100 - f250; + y[1] = f100 + f250; + y[29] = f102 - f254; + y[2] = f102 + f254; + y[28] = f104 - f246; + y[3] = f104 + f246; + y[27] = f106 - f264; + y[4] = f106 + f264; + y[26] = f108 - f272; + y[5] = f108 + f272; + y[25] = f110 - f268; + y[6] = f110 + f268; + y[24] = f112 - f260; + y[7] = f112 + f260; + y[23] = f111 - f259; + y[8] = f111 + f259; + y[22] = f109 - f267; + y[9] = f109 + f267; + y[21] = f107 - f271; + y[10] = f107 + f271; + y[20] = f105 - f263; + y[11] = f105 + f263; + y[19] = f103 - f248; + y[12] = f103 + f248; + y[18] = f101 - f256; + y[13] = f101 + f256; + y[17] = f99 - f252; + y[14] = f99 + f252; + y[16] = f97 - f244; + y[15] = f97 + f244; +} + #endif +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::DCT2_32_unscaled(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10; + real_t f11, f12, f13, f14, f15, f16, f17, f18, f19, f20; + real_t f21, f22, f23, f24, f25, f26, f27, f28, f29, f30; + real_t f31, f32, f33, f34, f35, f36, f37, f38, f39, f40; + real_t f41, f42, f43, f44, f45, f46, f47, f48, f49, f50; + real_t f51, f52, f53, f54, f55, f56, f57, f58, f59, f60; + real_t f63, f64, f65, f66, f69, f70, f71, f72, f73, f74; + real_t f75, f76, f77, f78, f79, f80, f81, f83, f85, f86; + real_t f89, f90, f91, f92, f93, f94, f95, f96, f97, f98; + real_t f99, f100, f101, f102, f103, f104, f105, f106, f107, f108; + real_t f109, f110, f111, f112, f113, f114, f115, f116, f117, f118; + real_t f119, f120, f121, f122, f123, f124, f127, f128, f129, f130; + real_t f133, f134, f135, f136, f139, f140, f141, f142, f145, f146; + real_t f147, f148, f149, f150, f151, f152, f153, f154, f155, f156; + real_t f157, f158, f159, f160, f161, f162, f163, f164, f165, f166; + real_t f167, f168, f169, f170, f171, f172, f173, f174, f175, f176; + real_t f177, f178, f179, f180, f181, f182, f183, f184, f185, f186; + real_t f187, f188, f189, f190, f191, f192, f193, f194, f195, f196; + real_t f197, f198, f199, f200, f201, f202, f203, f204, f205, f206; + real_t f207, f208, f209, f210, f211, f212, f213, f214, f215, f216; + real_t f217, f218, f219, f220, f221, f222, f223, f224, f225, f226; + real_t f227, f228, f229, f230, f231, f232, f233, f234, f235, f236; + real_t f237, f238, f239, f240, f241, f242, f243, f244, f247, f248; + real_t f249, f250, f253, f254, f255, f256, f259, f260, f261, f262; + real_t f265, f266, f267, f268, f271, f272, f273, f274, f277, f278; + real_t f279, f280, f283, f284, f285, f286; + f0 = x[0] - x[31]; + f1 = x[0] + x[31]; + f2 = x[1] - x[30]; + f3 = x[1] + x[30]; + f4 = x[2] - x[29]; + f5 = x[2] + x[29]; + f6 = x[3] - x[28]; + f7 = x[3] + x[28]; + f8 = x[4] - x[27]; + f9 = x[4] + x[27]; + f10 = x[5] - x[26]; + f11 = x[5] + x[26]; + f12 = x[6] - x[25]; + f13 = x[6] + x[25]; + f14 = x[7] - x[24]; + f15 = x[7] + x[24]; + f16 = x[8] - x[23]; + f17 = x[8] + x[23]; + f18 = x[9] - x[22]; + f19 = x[9] + x[22]; + f20 = x[10] - x[21]; + f21 = x[10] + x[21]; + f22 = x[11] - x[20]; + f23 = x[11] + x[20]; + f24 = x[12] - x[19]; + f25 = x[12] + x[19]; + f26 = x[13] - x[18]; + f27 = x[13] + x[18]; + f28 = x[14] - x[17]; + f29 = x[14] + x[17]; + f30 = x[15] - x[16]; + f31 = x[15] + x[16]; + f32 = f1 - f31; + f33 = f1 + f31; + f34 = f3 - f29; + f35 = f3 + f29; + f36 = f5 - f27; + f37 = f5 + f27; + f38 = f7 - f25; + f39 = f7 + f25; + f40 = f9 - f23; + f41 = f9 + f23; + f42 = f11 - f21; + f43 = f11 + f21; + f44 = f13 - f19; + f45 = f13 + f19; + f46 = f15 - f17; + f47 = f15 + f17; + f48 = f33 - f47; + f49 = f33 + f47; + f50 = f35 - f45; + f51 = f35 + f45; + f52 = f37 - f43; + f53 = f37 + f43; + f54 = f39 - f41; + f55 = f39 + f41; + f56 = f49 - f55; + f57 = f49 + f55; + f58 = f51 - f53; + f59 = f51 + f53; + f60 = f57 - f59; + y[0] = f57 + f59; + y[16] = MUL_F(FRAC_CONST(0.7071067811865476), f60); + f63 = f56 + f58; + f64 = MUL_C(COEF_CONST(1.3065629648763766), f56); + f65 = MUL_F(FRAC_CONST(-0.9238795325112866), f63); + f66 = MUL_F(FRAC_CONST(-0.5411961001461967), f58); + y[24] = f64 + f65; + y[8] = f66 - f65; + f69 = f48 + f54; + f70 = MUL_C(COEF_CONST(1.1758756024193588), f48); + f71 = MUL_F(FRAC_CONST(-0.9807852804032304), f69); + f72 = MUL_F(FRAC_CONST(-0.7856949583871021), f54); + f73 = f70 + f71; + f74 = f72 - f71; + f75 = f50 + f52; + f76 = MUL_C(COEF_CONST(1.3870398453221473), f50); + f77 = MUL_F(FRAC_CONST(-0.8314696123025455), f75); + f78 = MUL_F(FRAC_CONST(-0.2758993792829436), f52); + f79 = f76 + f77; + f80 = f78 - f77; + f81 = f74 - f80; + y[4] = f74 + f80; + f83 = MUL_F(FRAC_CONST(0.7071067811865476), f81); + y[28] = f73 - f79; + f85 = f73 + f79; + f86 = MUL_F(FRAC_CONST(0.7071067811865476), f85); + y[20] = f83 - f86; + y[12] = f83 + f86; + f89 = f34 - f36; + f90 = f34 + f36; + f91 = f38 - f40; + f92 = f38 + f40; + f93 = f42 - f44; + f94 = f42 + f44; + f95 = MUL_F(FRAC_CONST(0.7071067811865476), f92); + f96 = f32 - f95; + f97 = f32 + f95; + f98 = f90 + f94; + f99 = MUL_C(COEF_CONST(1.3065629648763766), f90); + f100 = MUL_F(FRAC_CONST(-0.9238795325112866), f98); + f101 = MUL_F(FRAC_CONST(-0.5411961001461967), f94); + f102 = f99 + f100; + f103 = f101 - f100; + f104 = f97 - f103; + f105 = f97 + f103; + f106 = f96 - f102; + f107 = f96 + f102; + f108 = MUL_F(FRAC_CONST(0.7071067811865476), f91); + f109 = f46 - f108; + f110 = f46 + f108; + f111 = f93 + f89; + f112 = MUL_C(COEF_CONST(1.3065629648763766), f93); + f113 = MUL_F(FRAC_CONST(-0.9238795325112866), f111); + f114 = MUL_F(FRAC_CONST(-0.5411961001461967), f89); + f115 = f112 + f113; + f116 = f114 - f113; + f117 = f110 - f116; + f118 = f110 + f116; + f119 = f109 - f115; + f120 = f109 + f115; + f121 = f118 + f105; + f122 = MUL_F(FRAC_CONST(-0.8971675863426361), f118); + f123 = MUL_F(FRAC_CONST(0.9951847266721968), f121); + f124 = MUL_C(COEF_CONST(1.0932018670017576), f105); + y[2] = f122 + f123; + y[30] = f124 - f123; + f127 = f107 - f120; + f128 = MUL_F(FRAC_CONST(-0.6666556584777466), f120); + f129 = MUL_F(FRAC_CONST(0.9569403357322089), f127); + f130 = MUL_C(COEF_CONST(1.2472250129866713), f107); + y[6] = f129 - f128; + y[26] = f130 - f129; + f133 = f119 + f106; + f134 = MUL_F(FRAC_CONST(-0.4105245275223571), f119); + f135 = MUL_F(FRAC_CONST(0.8819212643483549), f133); + f136 = MUL_C(COEF_CONST(1.3533180011743529), f106); + y[10] = f134 + f135; + y[22] = f136 - f135; + f139 = f104 - f117; + f140 = MUL_F(FRAC_CONST(-0.1386171691990915), f117); + f141 = MUL_F(FRAC_CONST(0.7730104533627370), f139); + f142 = MUL_C(COEF_CONST(1.4074037375263826), f104); + y[14] = f141 - f140; + y[18] = f142 - f141; + f145 = f2 - f4; + f146 = f2 + f4; + f147 = f6 - f8; + f148 = f6 + f8; + f149 = f10 - f12; + f150 = f10 + f12; + f151 = f14 - f16; + f152 = f14 + f16; + f153 = f18 - f20; + f154 = f18 + f20; + f155 = f22 - f24; + f156 = f22 + f24; + f157 = f26 - f28; + f158 = f26 + f28; + f159 = MUL_F(FRAC_CONST(0.7071067811865476), f152); + f160 = f0 - f159; + f161 = f0 + f159; + f162 = f148 + f156; + f163 = MUL_C(COEF_CONST(1.3065629648763766), f148); + f164 = MUL_F(FRAC_CONST(-0.9238795325112866), f162); + f165 = MUL_F(FRAC_CONST(-0.5411961001461967), f156); + f166 = f163 + f164; + f167 = f165 - f164; + f168 = f161 - f167; + f169 = f161 + f167; + f170 = f160 - f166; + f171 = f160 + f166; + f172 = f146 + f158; + f173 = MUL_C(COEF_CONST(1.1758756024193588), f146); + f174 = MUL_F(FRAC_CONST(-0.9807852804032304), f172); + f175 = MUL_F(FRAC_CONST(-0.7856949583871021), f158); + f176 = f173 + f174; + f177 = f175 - f174; + f178 = f150 + f154; + f179 = MUL_C(COEF_CONST(1.3870398453221473), f150); + f180 = MUL_F(FRAC_CONST(-0.8314696123025455), f178); + f181 = MUL_F(FRAC_CONST(-0.2758993792829436), f154); + f182 = f179 + f180; + f183 = f181 - f180; + f184 = f177 - f183; + f185 = f177 + f183; + f186 = MUL_F(FRAC_CONST(0.7071067811865476), f184); + f187 = f176 - f182; + f188 = f176 + f182; + f189 = MUL_F(FRAC_CONST(0.7071067811865476), f188); + f190 = f186 - f189; + f191 = f186 + f189; + f192 = f169 - f185; + f193 = f169 + f185; + f194 = f171 - f191; + f195 = f171 + f191; + f196 = f170 - f190; + f197 = f170 + f190; + f198 = f168 - f187; + f199 = f168 + f187; + f200 = MUL_F(FRAC_CONST(0.7071067811865476), f151); + f201 = f30 - f200; + f202 = f30 + f200; + f203 = f155 + f147; + f204 = MUL_C(COEF_CONST(1.3065629648763766), f155); + f205 = MUL_F(FRAC_CONST(-0.9238795325112866), f203); + f206 = MUL_F(FRAC_CONST(-0.5411961001461967), f147); + f207 = f204 + f205; + f208 = f206 - f205; + f209 = f202 - f208; + f210 = f202 + f208; + f211 = f201 - f207; + f212 = f201 + f207; + f213 = f157 + f145; + f214 = MUL_C(COEF_CONST(1.1758756024193588), f157); + f215 = MUL_F(FRAC_CONST(-0.9807852804032304), f213); + f216 = MUL_F(FRAC_CONST(-0.7856949583871021), f145); + f217 = f214 + f215; + f218 = f216 - f215; + f219 = f153 + f149; + f220 = MUL_C(COEF_CONST(1.3870398453221473), f153); + f221 = MUL_F(FRAC_CONST(-0.8314696123025455), f219); + f222 = MUL_F(FRAC_CONST(-0.2758993792829436), f149); + f223 = f220 + f221; + f224 = f222 - f221; + f225 = f218 - f224; + f226 = f218 + f224; + f227 = MUL_F(FRAC_CONST(0.7071067811865476), f225); + f228 = f217 - f223; + f229 = f217 + f223; + f230 = MUL_F(FRAC_CONST(0.7071067811865476), f229); + f231 = f227 - f230; + f232 = f227 + f230; + f233 = f210 - f226; + f234 = f210 + f226; + f235 = f212 - f232; + f236 = f212 + f232; + f237 = f211 - f231; + f238 = f211 + f231; + f239 = f209 - f228; + f240 = f209 + f228; + f241 = f234 + f193; + f242 = MUL_F(FRAC_CONST(-0.9497277818777543), f234); + f243 = MUL_F(FRAC_CONST(0.9987954562051724), f241); + f244 = MUL_C(COEF_CONST(1.0478631305325905), f193); + y[1] = f242 + f243; + y[31] = f244 - f243; + f247 = f195 - f236; + f248 = MUL_F(FRAC_CONST(-0.8424460355094192), f236); + f249 = MUL_F(FRAC_CONST(0.9891765099647810), f247); + f250 = MUL_C(COEF_CONST(1.1359069844201428), f195); + y[3] = f249 - f248; + y[29] = f250 - f249; + f253 = f238 + f197; + f254 = MUL_F(FRAC_CONST(-0.7270510732912801), f238); + f255 = MUL_F(FRAC_CONST(0.9700312531945440), f253); + f256 = MUL_C(COEF_CONST(1.2130114330978079), f197); + y[5] = f254 + f255; + y[27] = f256 - f255; + f259 = f199 - f240; + f260 = MUL_F(FRAC_CONST(-0.6046542117908007), f240); + f261 = MUL_F(FRAC_CONST(0.9415440651830208), f259); + f262 = MUL_C(COEF_CONST(1.2784339185752409), f199); + y[7] = f261 - f260; + y[25] = f262 - f261; + f265 = f239 + f198; + f266 = MUL_F(FRAC_CONST(-0.4764341996931611), f239); + f267 = MUL_F(FRAC_CONST(0.9039892931234433), f265); + f268 = MUL_C(COEF_CONST(1.3315443865537255), f198); + y[9] = f266 + f267; + y[23] = f268 - f267; + f271 = f196 - f237; + f272 = MUL_F(FRAC_CONST(-0.3436258658070505), f237); + f273 = MUL_F(FRAC_CONST(0.8577286100002721), f271); + f274 = MUL_C(COEF_CONST(1.3718313541934939), f196); + y[11] = f273 - f272; + y[21] = f274 - f273; + f277 = f235 + f194; + f278 = MUL_F(FRAC_CONST(-0.2075082269882114), f235); + f279 = MUL_F(FRAC_CONST(0.8032075314806448), f277); + f280 = MUL_C(COEF_CONST(1.3989068359730783), f194); + y[13] = f278 + f279; + y[19] = f280 - f279; + f283 = f192 - f233; + f284 = MUL_F(FRAC_CONST(-0.0693921705079408), f233); + f285 = MUL_F(FRAC_CONST(0.7409511253549591), f283); + f286 = MUL_C(COEF_CONST(1.4125100802019774), f192); + y[15] = f285 - f284; + y[17] = f286 - f285; +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +void NeaacDecoder::fft_dif(real_t* Real, real_t* Imag) { + const uint8_t _n = 32; + real_t w_real, w_imag; // For faster access + real_t point1_real, point1_imag, point2_real, point2_imag; // For faster access + uint32_t j, i, i2, w_index; // Counters + // First 2 stages of 32 point FFT decimation in frequency + // 4*16*2=64*2=128 multiplications + // 6*16*2=96*2=192 additions + // Stage 1 of 32 point FFT decimation in frequency + for (i = 0; i < 16; i++) { + point1_real = Real[i]; + point1_imag = Imag[i]; + i2 = i + 16; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + w_real = w_array_real[i]; + w_imag = w_array_imag[i]; + // temp1 = x[i] - x[i2] + point1_real -= point2_real; + point1_imag -= point2_imag; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * w + Real[i2] = (MUL_F(point1_real, w_real) - MUL_F(point1_imag, w_imag)); + Imag[i2] = (MUL_F(point1_real, w_imag) + MUL_F(point1_imag, w_real)); + } + // Stage 2 of 32 point FFT decimation in frequency + for (j = 0, w_index = 0; j < 8; j++, w_index += 2) { + w_real = w_array_real[w_index]; + w_imag = w_array_imag[w_index]; + i = j; + point1_real = Real[i]; + point1_imag = Imag[i]; + i2 = i + 8; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // temp1 = x[i] - x[i2] + point1_real -= point2_real; + point1_imag -= point2_imag; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * w + Real[i2] = (MUL_F(point1_real, w_real) - MUL_F(point1_imag, w_imag)); + Imag[i2] = (MUL_F(point1_real, w_imag) + MUL_F(point1_imag, w_real)); + i = j + 16; + point1_real = Real[i]; + point1_imag = Imag[i]; + i2 = i + 8; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // temp1 = x[i] - x[i2] + point1_real -= point2_real; + point1_imag -= point2_imag; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * w + Real[i2] = (MUL_F(point1_real, w_real) - MUL_F(point1_imag, w_imag)); + Imag[i2] = (MUL_F(point1_real, w_imag) + MUL_F(point1_imag, w_real)); + } + // Stage 3 of 32 point FFT decimation in frequency + // 2*4*2=16 multiplications + // 4*4*2+6*4*2=10*8=80 additions + for (i = 0; i < _n; i += 8) { + i2 = i + 4; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // out[i1] = point1 + point2 + Real[i] += point2_real; + Imag[i] += point2_imag; + // out[i2] = point1 - point2 + Real[i2] = point1_real - point2_real; + Imag[i2] = point1_imag - point2_imag; + } + w_real = w_array_real[4]; // = sqrt(2)/2 + // w_imag = -w_real; // = w_array_imag[4]; // = -sqrt(2)/2 + for (i = 1; i < _n; i += 8) { + i2 = i + 4; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // temp1 = x[i] - x[i2] + point1_real -= point2_real; + point1_imag -= point2_imag; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * w + Real[i2] = MUL_F(point1_real + point1_imag, w_real); + Imag[i2] = MUL_F(point1_imag - point1_real, w_real); + } + for (i = 2; i < _n; i += 8) { + i2 = i + 4; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // x[i] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * (-i) + Real[i2] = point1_imag - point2_imag; + Imag[i2] = point2_real - point1_real; + } + w_real = w_array_real[12]; // = -sqrt(2)/2 + // w_imag = w_real; // = w_array_imag[12]; // = -sqrt(2)/2 + for (i = 3; i < _n; i += 8) { + i2 = i + 4; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // temp1 = x[i] - x[i2] + point1_real -= point2_real; + point1_imag -= point2_imag; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * w + Real[i2] = MUL_F(point1_real - point1_imag, w_real); + Imag[i2] = MUL_F(point1_real + point1_imag, w_real); + } + // Stage 4 of 32 point FFT decimation in frequency (no multiplications) + // 16*4=64 additions + for (i = 0; i < _n; i += 4) { + i2 = i + 2; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // x[i1] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = x[i] - x[i2] + Real[i2] = point1_real - point2_real; + Imag[i2] = point1_imag - point2_imag; + } + for (i = 1; i < _n; i += 4) { + i2 = i + 2; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // x[i] = x[i] + x[i2] + Real[i] += point2_real; + Imag[i] += point2_imag; + // x[i2] = (x[i] - x[i2]) * (-i) + Real[i2] = point1_imag - point2_imag; + Imag[i2] = point2_real - point1_real; + } + // Stage 5 of 32 point FFT decimation in frequency (no multiplications) + // 16*4=64 additions + for (i = 0; i < _n; i += 2) { + i2 = i + 1; + point1_real = Real[i]; + point1_imag = Imag[i]; + point2_real = Real[i2]; + point2_imag = Imag[i2]; + // out[i1] = point1 + point2 + Real[i] += point2_real; + Imag[i] += point2_imag; + // out[i2] = point1 - point2 + Real[i2] = point1_real - point2_real; + Imag[i2] = point1_imag - point2_imag; + } + #ifdef REORDER_IN_FFT + FFTReorder(Real, Imag); + #endif // #ifdef REORDER_IN_FFT +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +void NeaacDecoder::flt_round(float* pf) { + int32_t flg; + uint32_t tmp, tmp1, tmp2; + tmp = *(uint32_t*)pf; + flg = tmp & (uint32_t)0x00008000; + tmp &= (uint32_t)0xffff0000; + tmp1 = tmp; + /* round 1/2 lsb toward infinity */ + if (flg) { + tmp &= (uint32_t)0xff800000; /* extract exponent and sign */ + tmp |= (uint32_t)0x00010000; /* insert 1 lsb */ + tmp2 = tmp; /* add 1 lsb and elided one */ + tmp &= (uint32_t)0xff800000; /* extract exponent and sign */ + // *pf = *(float*)&tmp1 + *(float*)&tmp2 - *(float*)&tmp; // [-Wstrict-aliasing] + float f1, f2, f3; + memcpy(&f1, &tmp1, sizeof(float)); + memcpy(&f2, &tmp2, sizeof(float)); + memcpy(&f3, &tmp, sizeof(float)); + *pf = f1 + f2 - f3; + } else { + // *pf = *(float*)&tmp; // [-Wstrict-aliasing] + memcpy(pf, &tmp, sizeof(float)); + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +int16_t NeaacDecoder::quant_pred(float x) { + int16_t q; + uint32_t* tmp = (uint32_t*)&x; + q = (int16_t)(*tmp >> 16); + return q; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +float NeaacDecoder::inv_quant_pred(int16_t q) { + float x = 0.0f; + uint32_t* tmp = (uint32_t*)&x; + *tmp = ((uint32_t)q) << 16; + return x; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +void NeaacDecoder::ic_predict(pred_state* state, real_t input, real_t* output, uint8_t pred) { + uint16_t tmp; + int16_t i, j; + real_t dr1; + float predictedvalue; + real_t e0, e1; + real_t k1, k2; + real_t r[2]; + real_t COR[2]; + real_t VAR[2]; + r[0] = inv_quant_pred(state->r[0]); + r[1] = inv_quant_pred(state->r[1]); + COR[0] = inv_quant_pred(state->COR[0]); + COR[1] = inv_quant_pred(state->COR[1]); + VAR[0] = inv_quant_pred(state->VAR[0]); + VAR[1] = inv_quant_pred(state->VAR[1]); + #if 1 + tmp = state->VAR[0]; + j = (tmp >> 7); + i = tmp & 0x7f; + if (j >= 128) { + j -= 128; + k1 = COR[0] * exp_table[j] * mnt_table[i]; + } else { + k1 = REAL_CONST(0); + } + #else + { + #define B 0.953125 + real_t c = COR[0]; + real_t v = VAR[0]; + float tmp; + if (c == 0 || v <= 1) { + k1 = 0; + } else { + tmp = B / v; + flt_round(&tmp); + k1 = c * tmp; + } + } + #endif + if (pred) { + #if 1 + tmp = state->VAR[1]; + j = (tmp >> 7); + i = tmp & 0x7f; + if (j >= 128) { + j -= 128; + k2 = COR[1] * exp_table[j] * mnt_table[i]; + } else { + k2 = REAL_CONST(0); + } + #else + #define B 0.953125 + real_t c = COR[1]; + real_t v = VAR[1]; + float tmp; + if (c == 0 || v <= 1) { + k2 = 0; + } else { + tmp = B / v; + flt_round(&tmp); + k2 = c * tmp; + } + #endif + predictedvalue = k1 * r[0] + k2 * r[1]; + flt_round(&predictedvalue); + *output = input + predictedvalue; + } + /* calculate new state data */ + e0 = *output; + e1 = e0 - k1 * r[0]; + dr1 = k1 * e0; + VAR[0] = ALPHA * VAR[0] + 0.5f * (r[0] * r[0] + e0 * e0); + COR[0] = ALPHA * COR[0] + r[0] * e0; + VAR[1] = ALPHA * VAR[1] + 0.5f * (r[1] * r[1] + e1 * e1); + COR[1] = ALPHA * COR[1] + r[1] * e1; + r[1] = A * (r[0] - dr1); + r[0] = A * e0; + state->r[0] = quant_pred(r[0]); + state->r[1] = quant_pred(r[1]); + state->COR[0] = quant_pred(COR[0]); + state->COR[1] = quant_pred(COR[1]); + state->VAR[0] = quant_pred(VAR[0]); + state->VAR[1] = quant_pred(VAR[1]); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +void NeaacDecoder::reset_pred_state(pred_state* state) { + state->r[0] = 0; + state->r[1] = 0; + state->COR[0] = 0; + state->COR[1] = 0; + state->VAR[0] = 0x3F80; + state->VAR[1] = 0x3F80; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +void NeaacDecoder::pns_reset_pred_state(ic_stream* ics, pred_state* state) { + uint8_t sfb, g, b; + uint16_t i, offs, offs2; + /* prediction only for long blocks */ + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) return; + for (g = 0; g < ics->num_window_groups; g++) { + for (b = 0; b < ics->window_group_length[g]; b++) { + for (sfb = 0; sfb < ics->max_sfb; sfb++) { + if (is_noise(ics, g, sfb)) { + offs = ics->swb_offset[sfb]; + offs2 = min(ics->swb_offset[sfb + 1], ics->swb_offset_max); + for (i = offs; i < offs2; i++) reset_pred_state(&state[i]); + } + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +void NeaacDecoder::reset_all_predictors(pred_state* state, uint16_t frame_len) { + uint16_t i; + for (i = 0; i < frame_len; i++) reset_pred_state(&state[i]); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef MAIN_DEC +/* intra channel prediction */ +void NeaacDecoder::ic_prediction(ic_stream* ics, real_t* spec, pred_state* state, uint16_t frame_len, uint8_t sf_index) { + uint8_t sfb; + uint16_t bin; + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + reset_all_predictors(state, frame_len); + } else { + for (sfb = 0; sfb < max_pred_sfb(sf_index); sfb++) { + uint16_t low = ics->swb_offset[sfb]; + uint16_t high = min(ics->swb_offset[sfb + 1], ics->swb_offset_max); + for (bin = low; bin < high; bin++) { ic_predict(&state[bin], spec[bin], &spec[bin], (ics->predictor_data_present && ics->pred.prediction_used[sfb])); } + } + if (ics->predictor_data_present) { + if (ics->pred.predictor_reset) { + for (bin = ics->pred.predictor_reset_group_number - 1; bin < frame_len; bin += 30) { reset_pred_state(&state[bin]); } + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 4.5.2.3.4 */ +/* + - determine the number of windows in a window_sequence named num_windows + - determine the number of window_groups named num_window_groups + - determine the number of windows in each group named window_group_length[g] + - determine the total number of scalefactor window bands named num_swb for + the actual window type + - determine swb_offset[swb], the offset of the first coefficient in + scalefactor window band named swb of the window actually used + - determine sect_sfb_offset[g][section],the offset of the first coefficient + in section named section. This offset depends on window_sequence and + scale_factor_grouping and is needed to decode the spectral_data(). +*/ +uint8_t NeaacDecoder::window_grouping_info(NeAACDecStruct* hDecoder, ic_stream* ics) { + uint8_t i, g; + uint8_t sf_index = hDecoder->sf_index; + switch (ics->window_sequence) { + case ONLY_LONG_SEQUENCE: + case LONG_START_SEQUENCE: + case LONG_STOP_SEQUENCE: + ics->num_windows = 1; + ics->num_window_groups = 1; + ics->window_group_length[ics->num_window_groups - 1] = 1; +#ifdef LD_DEC + if (hDecoder->object_type == LD) { + if (hDecoder->frameLength == 512) + ics->num_swb = num_swb_512_window[sf_index]; + else /* if (hDecoder->frameLength == 480) */ + ics->num_swb = num_swb_480_window[sf_index]; + } else { +#endif + if (hDecoder->frameLength == 1024) + ics->num_swb = num_swb_1024_window[sf_index]; + else /* if (hDecoder->frameLength == 960) */ + ics->num_swb = num_swb_960_window[sf_index]; +#ifdef LD_DEC + } +#endif + if (ics->max_sfb > ics->num_swb) { return 32; } + /* preparation of sect_sfb_offset for long blocks */ + /* also copy the last value! */ +#ifdef LD_DEC + if (hDecoder->object_type == LD) { + if (hDecoder->frameLength == 512) { + for (i = 0; i < ics->num_swb; i++) { + ics->sect_sfb_offset[0][i] = swb_offset_512_window[sf_index][i]; + ics->swb_offset[i] = swb_offset_512_window[sf_index][i]; + } + } else /* if (hDecoder->frameLength == 480) */ { + for (i = 0; i < ics->num_swb; i++) { + ics->sect_sfb_offset[0][i] = swb_offset_480_window[sf_index][i]; + ics->swb_offset[i] = swb_offset_480_window[sf_index][i]; + } + } + ics->sect_sfb_offset[0][ics->num_swb] = hDecoder->frameLength; + ics->swb_offset[ics->num_swb] = hDecoder->frameLength; + ics->swb_offset_max = hDecoder->frameLength; + } else { +#endif + for (i = 0; i < ics->num_swb; i++) { + ics->sect_sfb_offset[0][i] = swb_offset_1024_window[sf_index][i]; + ics->swb_offset[i] = swb_offset_1024_window[sf_index][i]; + } + ics->sect_sfb_offset[0][ics->num_swb] = hDecoder->frameLength; + ics->swb_offset[ics->num_swb] = hDecoder->frameLength; + ics->swb_offset_max = hDecoder->frameLength; +#ifdef LD_DEC + } +#endif + return 0; + case EIGHT_SHORT_SEQUENCE: + ics->num_windows = 8; + ics->num_window_groups = 1; + ics->window_group_length[ics->num_window_groups - 1] = 1; + ics->num_swb = num_swb_128_window[sf_index]; + if (ics->max_sfb > ics->num_swb) { return 32; } + for (i = 0; i < ics->num_swb; i++) ics->swb_offset[i] = swb_offset_128_window[sf_index][i]; + ics->swb_offset[ics->num_swb] = hDecoder->frameLength / 8; + ics->swb_offset_max = hDecoder->frameLength / 8; + for (i = 0; i < ics->num_windows - 1; i++) { + if (!(ics->scale_factor_grouping & (1u << (6 - i)))) { + ics->num_window_groups += 1; + ics->window_group_length[ics->num_window_groups - 1] = 1; + } else { + ics->window_group_length[ics->num_window_groups - 1] += 1; + } + } + /* preparation of sect_sfb_offset for short blocks */ + for (g = 0; g < ics->num_window_groups; g++) { + uint16_t width; + uint8_t sect_sfb = 0; + uint16_t offset = 0; + for (i = 0; i < ics->num_swb; i++) { + if (i + 1 == ics->num_swb) { + width = (hDecoder->frameLength / 8) - swb_offset_128_window[sf_index][i]; + } else { + width = swb_offset_128_window[sf_index][i + 1] - swb_offset_128_window[sf_index][i]; + } + width *= ics->window_group_length[g]; + ics->sect_sfb_offset[g][sect_sfb++] = offset; + offset += width; + } + ics->sect_sfb_offset[g][sect_sfb] = offset; + } + return 0; + default: return 32; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* iquant() */ +/* output = sign(input)*abs(input)^(4/3) */ +real_t NeaacDecoder::iquant(int16_t q, const real_t* tab, uint8_t* error) { +#ifdef FIXED_POINT + /* For FIXED_POINT the iq_table is prescaled by 3 bits (iq_table[]/8) */ + /* BIG_IQ_TABLE allows you to use the full 8192 value table, if this is not + * defined a 1026 value table and interpolation will be used + */ + #ifndef BIG_IQ_TABLE + const real_t errcorr[] = {REAL_CONST(0), REAL_CONST(1.0 / 8.0), REAL_CONST(2.0 / 8.0), REAL_CONST(3.0 / 8.0), REAL_CONST(4.0 / 8.0), + REAL_CONST(5.0 / 8.0), REAL_CONST(6.0 / 8.0), REAL_CONST(7.0 / 8.0), REAL_CONST(0)}; + real_t x1, x2; + #endif + int16_t sgn = 1; + /* compute the magnitude in int: -q is evaluated as int and so does not wrap for q == -32768 the way an int16_t negation would, which keeps the + comparison against IQ_TABLE_SIZE in range like the floating-point path */ + int32_t aq = q; + + if (aq < 0) { + aq = -aq; + sgn = -1; + } + if (aq < IQ_TABLE_SIZE) { + // #define IQUANT_PRINT + #ifdef IQUANT_PRINT + // printf("0x%.8X\n", sgn * tab[aq]); + printf("%d\n", sgn * tab[aq]); + #endif + return sgn * tab[aq]; + } + #ifndef BIG_IQ_TABLE + if (aq >= 8192) { + *error = 17; + return 0; + } + /* linear interpolation */ + x1 = tab[aq >> 3]; + x2 = tab[(aq >> 3) + 1]; + return sgn * 16 * (MUL_R(errcorr[aq & 7], (x2 - x1)) + x1); + #else + *error = 17; + return 0; + #endif +#else + if (q < 0) { + /* tab contains a value for all possible q [0,8192] */ + if (-q < IQ_TABLE_SIZE) return -tab[-q]; + *error = 17; + return 0; + } else { + /* tab contains a value for all possible q [0,8192] */ + if (q < IQ_TABLE_SIZE) return tab[q]; + *error = 17; + return 0; + } +#endif +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* quant_to_spec: perform dequantisation and scaling and in case of short block it also does the deinterleaving */ +/* + For ONLY_LONG_SEQUENCE windows (num_window_groups = 1, window_group_length[0] = 1) the spectral data is in ascending spectral order. + For the EIGHT_SHORT_SEQUENCE window, the spectral order depends on the grouping in the following manner: + - Groups are ordered sequentially + - Within a group, a scalefactor band consists of the spectral data of all grouped SHORT_WINDOWs for the associated scalefactor window band. To + clarify via example, the length of a group is in the range of one to eight SHORT_WINDOWs. + - If there are eight groups each with length one (num_window_groups = 8, window_group_length[0..7] = 1), the result is a sequence of eight spectra, + each in ascending spectral order. + - If there is only one group with length eight (num_window_groups = 1, window_group_length[0] = 8), the result is that spectral data of all eight + SHORT_WINDOWs is interleaved by scalefactor window bands. + - Within a scalefactor window band, the coefficients are in ascending spectral order. +*/ +uint8_t NeaacDecoder::quant_to_spec(NeAACDecStruct* hDecoder, ic_stream* ics, int16_t* quant_data, real_t* spec_data, uint16_t frame_len) { + const real_t pow2_table[] = { + COEF_CONST(1.0), COEF_CONST(1.1892071150027210667174999705605), /* 2^0.25 */ + COEF_CONST(1.4142135623730950488016887242097), /* 2^0.5 */ + COEF_CONST(1.6817928305074290860622509524664) /* 2^0.75 */ + }; + const real_t* tab = iq_table; + uint8_t g, sfb, win; + uint16_t width, bin, k, gindex, wa, wb; + uint8_t error = 0; /* Init error flag */ +#ifndef FIXED_POINT + real_t scf; +#endif + k = 0; + gindex = 0; + for (g = 0; g < ics->num_window_groups; g++) { + uint16_t j = 0; + uint16_t gincrease = 0; + uint16_t win_inc = ics->swb_offset[ics->num_swb]; + for (sfb = 0; sfb < ics->num_swb; sfb++) { + int32_t exp, frac; + width = ics->swb_offset[sfb + 1] - ics->swb_offset[sfb]; + /* this could be scalefactor for IS or PNS, those can be negative or bigger then 255 */ + /* just ignore them */ + if (ics->scale_factors[g][sfb] < 0 || ics->scale_factors[g][sfb] > 255) { + exp = 0; + frac = 0; + } else { + /* ics->scale_factors[g][sfb] must be between 0 and 255 */ + exp = (ics->scale_factors[g][sfb] /* - 100 */) >> 2; + /* frac must always be > 0 */ + frac = (ics->scale_factors[g][sfb] /* - 100 */) & 3; + } +#ifdef FIXED_POINT + exp -= 25; + /* IMDCT pre-scaling */ + if (hDecoder->object_type == LD) { + exp -= 6 /*9*/; + } else { + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) + exp -= 4 /*7*/; + else + exp -= 7 /*10*/; + } +#endif + wa = gindex + j; +#ifndef FIXED_POINT + scf = pow2sf_tab[exp /*+25*/] * pow2_table[frac]; +#endif + for (win = 0; win < ics->window_group_length[g]; win++) { + for (bin = 0; bin < width; bin += 4) { +#ifndef FIXED_POINT + wb = wa + bin; + spec_data[wb + 0] = iquant(quant_data[k + 0], tab, &error) * scf; + spec_data[wb + 1] = iquant(quant_data[k + 1], tab, &error) * scf; + spec_data[wb + 2] = iquant(quant_data[k + 2], tab, &error) * scf; + spec_data[wb + 3] = iquant(quant_data[k + 3], tab, &error) * scf; +#else + real_t iq0 = iquant(quant_data[k + 0], tab, &error); + real_t iq1 = iquant(quant_data[k + 1], tab, &error); + real_t iq2 = iquant(quant_data[k + 2], tab, &error); + real_t iq3 = iquant(quant_data[k + 3], tab, &error); + wb = wa + bin; + if (exp < 0) { + spec_data[wb + 0] = iq0 >>= -exp; + spec_data[wb + 1] = iq1 >>= -exp; + spec_data[wb + 2] = iq2 >>= -exp; + spec_data[wb + 3] = iq3 >>= -exp; + } else { + spec_data[wb + 0] = iq0 <<= exp; + spec_data[wb + 1] = iq1 <<= exp; + spec_data[wb + 2] = iq2 <<= exp; + spec_data[wb + 3] = iq3 <<= exp; + } + if (frac != 0) { + spec_data[wb + 0] = MUL_C(spec_data[wb + 0], pow2_table[frac]); + spec_data[wb + 1] = MUL_C(spec_data[wb + 1], pow2_table[frac]); + spec_data[wb + 2] = MUL_C(spec_data[wb + 2], pow2_table[frac]); + spec_data[wb + 3] = MUL_C(spec_data[wb + 3], pow2_table[frac]); + } + // #define SCFS_PRINT + #ifdef SCFS_PRINT + printf("%d\n", spec_data[gindex + (win * win_inc) + j + bin + 0]); + printf("%d\n", spec_data[gindex + (win * win_inc) + j + bin + 1]); + printf("%d\n", spec_data[gindex + (win * win_inc) + j + bin + 2]); + printf("%d\n", spec_data[gindex + (win * win_inc) + j + bin + 3]); + // printf("0x%.8X\n", spec_data[gindex+(win*win_inc)+j+bin+0]); + // printf("0x%.8X\n", spec_data[gindex+(win*win_inc)+j+bin+1]); + // printf("0x%.8X\n", spec_data[gindex+(win*win_inc)+j+bin+2]); + // printf("0x%.8X\n", spec_data[gindex+(win*win_inc)+j+bin+3]); + #endif +#endif + gincrease += 4; + k += 4; + } + wa += win_inc; + } + j += width; + } + gindex += gincrease; + } + return error; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::allocate_single_channel(NeAACDecStruct* hDecoder, uint8_t channel, uint8_t output_channels) { + int mul = 1; +#ifdef MAIN_DEC + /* MAIN object type prediction */ + if (hDecoder->object_type == MAIN) { + /* allocate the state only when needed */ + if (hDecoder->pred_stat[channel] != NULL) { + faad_free(&hDecoder->pred_stat[channel]); + hDecoder->pred_stat[channel] = NULL; + } + hDecoder->pred_stat[channel] = (pred_state*)faad_malloc(hDecoder->frameLength * sizeof(pred_state)); + reset_all_predictors(hDecoder->pred_stat[channel], hDecoder->frameLength); + } +#endif +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + /* allocate the state only when needed */ + if (hDecoder->lt_pred_stat[channel] != NULL) { + faad_free(&hDecoder->lt_pred_stat[channel]); + hDecoder->lt_pred_stat[channel] = NULL; + } + hDecoder->lt_pred_stat[channel] = (int16_t*)faad_malloc(hDecoder->frameLength * 4 * sizeof(int16_t)); + memset(hDecoder->lt_pred_stat[channel], 0, hDecoder->frameLength * 4 * sizeof(int16_t)); + } +#endif + if (hDecoder->time_out[channel] != NULL) { + faad_free(&hDecoder->time_out[channel]); + hDecoder->time_out[channel] = NULL; + } + { + mul = 1; +#ifdef SBR_DEC + hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 0; + if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) { + /* SBR requires 2 times as much output data */ + mul = 2; + hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 1; + } +#endif + hDecoder->time_out[channel] = (real_t*)faad_malloc(mul * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->time_out[channel], 0, mul * hDecoder->frameLength * sizeof(real_t)); + } +#if (defined(PS_DEC) || defined(DRM_PS)) + if (output_channels == 2) { + if (hDecoder->time_out[channel + 1] != NULL) { + faad_free(&hDecoder->time_out[channel + 1]); + hDecoder->time_out[channel + 1] = NULL; + } + hDecoder->time_out[channel + 1] = (real_t*)faad_malloc(mul * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->time_out[channel + 1], 0, mul * hDecoder->frameLength * sizeof(real_t)); + } +#endif + if (hDecoder->fb_intermed[channel] != NULL) { + faad_free(&hDecoder->fb_intermed[channel]); + hDecoder->fb_intermed[channel] = NULL; + } + hDecoder->fb_intermed[channel] = (real_t*)faad_malloc(hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->fb_intermed[channel], 0, hDecoder->frameLength * sizeof(real_t)); +#ifdef SSR_DEC + if (hDecoder->object_type == SSR) { + if (hDecoder->ssr_overlap[channel] == NULL) { + hDecoder->ssr_overlap[channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->ssr_overlap[channel], 0, 2 * hDecoder->frameLength * sizeof(real_t)); + } + if (hDecoder->prev_fmd[channel] == NULL) { + uint16_t k; + hDecoder->prev_fmd[channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + for (k = 0; k < 2 * hDecoder->frameLength; k++) hDecoder->prev_fmd[channel][k] = REAL_CONST(-1); + } + } +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::allocate_channel_pair(NeAACDecStruct* hDecoder, uint8_t channel, uint8_t paired_channel) { + int mul = 1; +#ifdef MAIN_DEC + /* MAIN object type prediction */ + if (hDecoder->object_type == MAIN) { + /* allocate the state only when needed */ + if (hDecoder->pred_stat[channel] == NULL) { + hDecoder->pred_stat[channel] = (pred_state*)faad_malloc(hDecoder->frameLength * sizeof(pred_state)); + reset_all_predictors(hDecoder->pred_stat[channel], hDecoder->frameLength); + } + if (hDecoder->pred_stat[paired_channel] == NULL) { + hDecoder->pred_stat[paired_channel] = (pred_state*)faad_malloc(hDecoder->frameLength * sizeof(pred_state)); + reset_all_predictors(hDecoder->pred_stat[paired_channel], hDecoder->frameLength); + } + } +#endif +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + /* allocate the state only when needed */ + if (hDecoder->lt_pred_stat[channel] == NULL) { + hDecoder->lt_pred_stat[channel] = (int16_t*)faad_malloc(hDecoder->frameLength * 4 * sizeof(int16_t)); + memset(hDecoder->lt_pred_stat[channel], 0, hDecoder->frameLength * 4 * sizeof(int16_t)); + } + if (hDecoder->lt_pred_stat[paired_channel] == NULL) { + hDecoder->lt_pred_stat[paired_channel] = (int16_t*)faad_malloc(hDecoder->frameLength * 4 * sizeof(int16_t)); + memset(hDecoder->lt_pred_stat[paired_channel], 0, hDecoder->frameLength * 4 * sizeof(int16_t)); + } + } +#endif + { + mul = 1; +#ifdef SBR_DEC + hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 0; + if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) { + /* SBR requires 2 times as much output data */ + mul = 2; + hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 1; + } +#endif + } + + if (hDecoder->time_out[channel] != NULL) { + faad_free(&hDecoder->time_out[channel]); + hDecoder->time_out[channel] = NULL; + } + hDecoder->time_out[channel] = (real_t*)faad_malloc(mul * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->time_out[channel], 0, mul * hDecoder->frameLength * sizeof(real_t)); + + if (hDecoder->time_out[paired_channel] != NULL) { + faad_free(&hDecoder->time_out[paired_channel]); + hDecoder->time_out[paired_channel] = NULL; + } + hDecoder->time_out[paired_channel] = (real_t*)faad_malloc(mul * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->time_out[paired_channel], 0, mul * hDecoder->frameLength * sizeof(real_t)); + + if (hDecoder->fb_intermed[channel] != NULL) { + faad_free(&hDecoder->fb_intermed[channel]); + hDecoder->fb_intermed[channel] = NULL; + } + hDecoder->fb_intermed[channel] = (real_t*)faad_malloc(hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->fb_intermed[channel], 0, hDecoder->frameLength * sizeof(real_t)); + + if (hDecoder->fb_intermed[paired_channel] != NULL) { + faad_free(&hDecoder->fb_intermed[paired_channel]); + hDecoder->fb_intermed[paired_channel] = NULL; + } + hDecoder->fb_intermed[paired_channel] = (real_t*)faad_malloc(hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->fb_intermed[paired_channel], 0, hDecoder->frameLength * sizeof(real_t)); +#ifdef SSR_DEC + if (hDecoder->object_type == SSR) { + if (hDecoder->ssr_overlap[channel] == NULL) { + hDecoder->ssr_overlap[channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->ssr_overlap[channel], 0, 2 * hDecoder->frameLength * sizeof(real_t)); + } + if (hDecoder->ssr_overlap[paired_channel] == NULL) { + hDecoder->ssr_overlap[paired_channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + memset(hDecoder->ssr_overlap[paired_channel], 0, 2 * hDecoder->frameLength * sizeof(real_t)); + } + if (hDecoder->prev_fmd[channel] == NULL) { + uint16_t k; + hDecoder->prev_fmd[channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + for (k = 0; k < 2 * hDecoder->frameLength; k++) hDecoder->prev_fmd[channel][k] = REAL_CONST(-1); + } + if (hDecoder->prev_fmd[paired_channel] == NULL) { + uint16_t k; + hDecoder->prev_fmd[paired_channel] = (real_t*)faad_malloc(2 * hDecoder->frameLength * sizeof(real_t)); + for (k = 0; k < 2 * hDecoder->frameLength; k++) hDecoder->prev_fmd[paired_channel][k] = REAL_CONST(-1); + } + } +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::reconstruct_single_channel(NeAACDecStruct* hDecoder, ic_stream* ics, element* sce, int16_t* spec_data) { + uint8_t retval = 0; + int output_channels; + real_t* spec_coef = (real_t*)faad_malloc(1024 * sizeof(real_t)); +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif + /* always allocate 2 channels, PS can always "suddenly" turn up */ +#if ((defined(DRM) && defined(DRM_PS))) + output_channels = 2; +#elif defined(PS_DEC) + if (hDecoder->ps_used[hDecoder->fr_ch_ele]) + output_channels = 2; + else + output_channels = 1; +#else + output_channels = 1; +#endif + if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 0) { + /* element_output_channels not set yet */ + hDecoder->element_output_channels[hDecoder->fr_ch_ele] = output_channels; + } else if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] != output_channels) { + /* element inconsistency */ + /* this only happens if PS is actually found but not in the first frame + * this means that there is only 1 bitstream element! + */ + /* reset the allocation */ + hDecoder->element_alloced[hDecoder->fr_ch_ele] = 0; + memset(&hDecoder->element_alloced[hDecoder->fr_ch_ele], 0, sizeof(uint8_t) * (MAX_SYNTAX_ELEMENTS - hDecoder->fr_ch_ele)); + + hDecoder->element_output_channels[hDecoder->fr_ch_ele] = output_channels; + retval = 21; + goto exit; + } + if (hDecoder->element_alloced[hDecoder->fr_ch_ele] == 0) { + retval = allocate_single_channel(hDecoder, sce->channel, output_channels); + if (retval > 0) goto exit; + hDecoder->element_alloced[hDecoder->fr_ch_ele] = 1; + } + /* sanity check, CVE-2018-20199, CVE-2018-20360 */ + if (!hDecoder->time_out[sce->channel]) { + retval = 15; + goto exit; + } + if (output_channels > 1 && !hDecoder->time_out[sce->channel + 1]) { + retval = 15; + goto exit; + } + if (!hDecoder->fb_intermed[sce->channel]) { + retval = 15; + goto exit; + } + /* dequantisation and scaling */ + retval = quant_to_spec(hDecoder, ics, spec_data, spec_coef, hDecoder->frameLength); + if (retval > 0) goto exit; +#ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->requant_cycles += count; +#endif + /* pns decoding */ + pns_decode(ics, NULL, spec_coef, NULL, hDecoder->frameLength, 0, hDecoder->object_type, &(hDecoder->__r1), &(hDecoder->__r2)); +#ifdef MAIN_DEC + /* MAIN object type prediction */ + if (hDecoder->object_type == MAIN) { + if (!hDecoder->pred_stat[sce->channel]) { + retval = 33; + goto exit; + } // return 33; + /* intra channel prediction */ + ic_prediction(ics, spec_coef, hDecoder->pred_stat[sce->channel], hDecoder->frameLength, hDecoder->sf_index); + /* In addition, for scalefactor bands coded by perceptual + noise substitution the predictors belonging to the + corresponding spectral coefficients are reset. + */ + pns_reset_pred_state(ics, hDecoder->pred_stat[sce->channel]); + } +#endif +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + #ifdef LD_DEC + if (hDecoder->object_type == LD) { + if (ics->ltp.data_present) { + if (ics->ltp.lag_update) hDecoder->ltp_lag[sce->channel] = ics->ltp.lag; + } + ics->ltp.lag = hDecoder->ltp_lag[sce->channel]; + } + #endif + /* long term prediction */ + lt_prediction(ics, &(ics->ltp), spec_coef, hDecoder->lt_pred_stat[sce->channel], hDecoder->fb, ics->window_shape, hDecoder->window_shape_prev[sce->channel], hDecoder->sf_index, + hDecoder->object_type, hDecoder->frameLength); + } +#endif + /* tns decoding */ + tns_decode_frame(ics, &(ics->tns), hDecoder->sf_index, hDecoder->object_type, spec_coef, hDecoder->frameLength); + /* drc decoding */ +#ifdef APPLY_DRC + if (hDecoder->drc->present) { + if (!hDecoder->drc->exclude_mask[sce->channel] || !hDecoder->drc->excluded_chns_present) drc_decode(hDecoder->drc, spec_coef); + } +#endif + /* filter bank */ +#ifdef SSR_DEC + if (hDecoder->object_type != SSR) { +#endif + ifilter_bank(hDecoder->fb, ics->window_sequence, ics->window_shape, hDecoder->window_shape_prev[sce->channel], spec_coef, hDecoder->time_out[sce->channel], hDecoder->fb_intermed[sce->channel], + hDecoder->object_type, hDecoder->frameLength); +#ifdef SSR_DEC + } else { + ssr_decode(&(ics->ssr), hDecoder->fb, ics->window_sequence, ics->window_shape, hDecoder->window_shape_prev[sce->channel], spec_coef, hDecoder->time_out[sce->channel], + hDecoder->ssr_overlap[sce->channel], hDecoder->ipqf_buffer[sce->channel], hDecoder->prev_fmd[sce->channel], hDecoder->frameLength); + } +#endif + /* save window shape for next frame */ + hDecoder->window_shape_prev[sce->channel] = ics->window_shape; +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + lt_update_state(hDecoder->lt_pred_stat[sce->channel], hDecoder->time_out[sce->channel], hDecoder->fb_intermed[sce->channel], hDecoder->frameLength, hDecoder->object_type); + } +#endif +#ifdef SBR_DEC + if (((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) && hDecoder->sbr_alloced[hDecoder->fr_ch_ele]) { + int ele = hDecoder->fr_ch_ele; + int ch = sce->channel; + /* following case can happen when forceUpSampling == 1 */ + if (hDecoder->sbr[ele] == NULL) { hDecoder->sbr[ele] = sbrDecodeInit(hDecoder->frameLength, hDecoder->element_id[ele], 2 * get_sample_rate(hDecoder->sf_index), hDecoder->downSampledSBR, 0); } + if (!hDecoder->sbr[ele]) { + retval = 19; + goto exit; + } + if (sce->ics1.window_sequence == EIGHT_SHORT_SEQUENCE) + hDecoder->sbr[ele]->maxAACLine = 8 * min(sce->ics1.swb_offset[max(sce->ics1.max_sfb - 1, 0)], sce->ics1.swb_offset_max); + else + hDecoder->sbr[ele]->maxAACLine = min(sce->ics1.swb_offset[max(sce->ics1.max_sfb - 1, 0)], sce->ics1.swb_offset_max); + /* check if any of the PS tools is used */ + #if (defined(PS_DEC) || defined(DRM_PS)) + if (hDecoder->ps_used[ele] == 0) { + #endif + retval = sbrDecodeSingleFrame(hDecoder->sbr[ele], hDecoder->time_out[ch], hDecoder->postSeekResetFlag, hDecoder->downSampledSBR); + hDecoder->isPS = 0; + #if (defined(PS_DEC) || defined(DRM_PS)) + } else { + retval = sbrDecodeSingleFramePS(hDecoder->sbr[ele], hDecoder->time_out[ch], hDecoder->time_out[ch + 1], hDecoder->postSeekResetFlag, hDecoder->downSampledSBR); + hDecoder->isPS = 1; + } + #endif + if (retval > 0) goto exit; + } else if (((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) && !hDecoder->sbr_alloced[hDecoder->fr_ch_ele]) { + { + retval = 23; + goto exit; + } + } +#endif + /* copy L to R when no PS is used */ +#if (defined(PS_DEC) || defined(DRM_PS)) + if ((hDecoder->ps_used[hDecoder->fr_ch_ele] == 0) && (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 2)) { + int ele = hDecoder->fr_ch_ele; + int ch = sce->channel; + int frame_size = (hDecoder->sbr_alloced[ele]) ? 2 : 1; + frame_size *= hDecoder->frameLength * sizeof(real_t); + memcpy(hDecoder->time_out[ch + 1], hDecoder->time_out[ch], frame_size); + } +#endif + retval = 0; +exit: + faad_free(&spec_coef); + return retval; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::reconstruct_channel_pair(NeAACDecStruct* hDecoder, ic_stream* ics1, ic_stream* ics2, element* cpe, int16_t* spec_data1, int16_t* spec_data2) { + uint8_t retval; + // real_t spec_coef1[1024]; + // real_t spec_coef2[1024]; + real_t* spec_coef1 = (real_t*)faad_malloc(1024 * sizeof(real_t)); + real_t* spec_coef2 = (real_t*)faad_malloc(1024 * sizeof(real_t)); +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif + if (hDecoder->element_alloced[hDecoder->fr_ch_ele] != 2) { + retval = allocate_channel_pair(hDecoder, cpe->channel, (uint8_t)cpe->paired_channel); + if (retval > 0) goto exit; + hDecoder->element_alloced[hDecoder->fr_ch_ele] = 2; + } + /* sanity check, CVE-2018-20199, CVE-2018-20360 */ + if (!hDecoder->time_out[cpe->channel] || !hDecoder->time_out[cpe->paired_channel]) { + retval = 15; + goto exit; + } + if (!hDecoder->fb_intermed[cpe->channel] || !hDecoder->fb_intermed[cpe->paired_channel]) { + retval = 15; + goto exit; + } + /* dequantisation and scaling */ + retval = quant_to_spec(hDecoder, ics1, spec_data1, spec_coef1, hDecoder->frameLength); + if (retval > 0) goto exit; + retval = quant_to_spec(hDecoder, ics2, spec_data2, spec_coef2, hDecoder->frameLength); + if (retval > 0) goto exit; +#ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->requant_cycles += count; +#endif + /* pns decoding */ + if (ics1->ms_mask_present) { + pns_decode(ics1, ics2, spec_coef1, spec_coef2, hDecoder->frameLength, 1, hDecoder->object_type, &(hDecoder->__r1), &(hDecoder->__r2)); + } else { + pns_decode(ics1, ics2, spec_coef1, spec_coef2, hDecoder->frameLength, 0, hDecoder->object_type, &(hDecoder->__r1), &(hDecoder->__r2)); + } + /* mid/side decoding */ + ms_decode(ics1, ics2, spec_coef1, spec_coef2, hDecoder->frameLength); +#if 0 + { + int i; + for (i = 0; i < 1024; i++) + { + //printf("%d\n", spec_coef1[i]); + printf("0x%.8X\n", spec_coef1[i]); + } + for (i = 0; i < 1024; i++) + { + //printf("%d\n", spec_coef2[i]); + printf("0x%.8X\n", spec_coef2[i]); + } + } +#endif + /* intensity stereo decoding */ + is_decode(ics1, ics2, spec_coef1, spec_coef2, hDecoder->frameLength); +#ifdef MAIN_DEC + /* MAIN object type prediction */ + if (hDecoder->object_type == MAIN) { + /* intra channel prediction */ + ic_prediction(ics1, spec_coef1, hDecoder->pred_stat[cpe->channel], hDecoder->frameLength, hDecoder->sf_index); + ic_prediction(ics2, spec_coef2, hDecoder->pred_stat[cpe->paired_channel], hDecoder->frameLength, hDecoder->sf_index); + /* In addition, for scalefactor bands coded by perceptual + noise substitution the predictors belonging to the + corresponding spectral coefficients are reset. + */ + pns_reset_pred_state(ics1, hDecoder->pred_stat[cpe->channel]); + pns_reset_pred_state(ics2, hDecoder->pred_stat[cpe->paired_channel]); + } +#endif +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + ltp_info* ltp1 = &(ics1->ltp); + ltp_info* ltp2 = (cpe->common_window) ? &(ics2->ltp2) : &(ics2->ltp); + #ifdef LD_DEC + if (hDecoder->object_type == LD) { + if (ltp1->data_present) { + if (ltp1->lag_update) hDecoder->ltp_lag[cpe->channel] = ltp1->lag; + } + ltp1->lag = hDecoder->ltp_lag[cpe->channel]; + if (ltp2->data_present) { + if (ltp2->lag_update) hDecoder->ltp_lag[cpe->paired_channel] = ltp2->lag; + } + ltp2->lag = hDecoder->ltp_lag[cpe->paired_channel]; + } + #endif + /* long term prediction */ + lt_prediction(ics1, ltp1, spec_coef1, hDecoder->lt_pred_stat[cpe->channel], hDecoder->fb, ics1->window_shape, hDecoder->window_shape_prev[cpe->channel], hDecoder->sf_index, + hDecoder->object_type, hDecoder->frameLength); + lt_prediction(ics2, ltp2, spec_coef2, hDecoder->lt_pred_stat[cpe->paired_channel], hDecoder->fb, ics2->window_shape, hDecoder->window_shape_prev[cpe->paired_channel], hDecoder->sf_index, + hDecoder->object_type, hDecoder->frameLength); + } +#endif + /* tns decoding */ + tns_decode_frame(ics1, &(ics1->tns), hDecoder->sf_index, hDecoder->object_type, spec_coef1, hDecoder->frameLength); + tns_decode_frame(ics2, &(ics2->tns), hDecoder->sf_index, hDecoder->object_type, spec_coef2, hDecoder->frameLength); + /* drc decoding */ +#if APPLY_DRC + if (hDecoder->drc->present) { + if (!hDecoder->drc->exclude_mask[cpe->channel] || !hDecoder->drc->excluded_chns_present) drc_decode(hDecoder->drc, spec_coef1); + if (!hDecoder->drc->exclude_mask[cpe->paired_channel] || !hDecoder->drc->excluded_chns_present) drc_decode(hDecoder->drc, spec_coef2); + } +#endif + /* filter bank */ +#ifdef SSR_DEC + if (hDecoder->object_type != SSR) { +#endif + ifilter_bank(hDecoder->fb, ics1->window_sequence, ics1->window_shape, hDecoder->window_shape_prev[cpe->channel], spec_coef1, hDecoder->time_out[cpe->channel], + hDecoder->fb_intermed[cpe->channel], hDecoder->object_type, hDecoder->frameLength); + ifilter_bank(hDecoder->fb, ics2->window_sequence, ics2->window_shape, hDecoder->window_shape_prev[cpe->paired_channel], spec_coef2, hDecoder->time_out[cpe->paired_channel], + hDecoder->fb_intermed[cpe->paired_channel], hDecoder->object_type, hDecoder->frameLength); +#ifdef SSR_DEC + } else { + ssr_decode(&(ics1->ssr), hDecoder->fb, ics1->window_sequence, ics1->window_shape, hDecoder->window_shape_prev[cpe->channel], spec_coef1, hDecoder->time_out[cpe->channel], + hDecoder->ssr_overlap[cpe->channel], hDecoder->ipqf_buffer[cpe->channel], hDecoder->prev_fmd[cpe->channel], hDecoder->frameLength); + ssr_decode(&(ics2->ssr), hDecoder->fb, ics2->window_sequence, ics2->window_shape, hDecoder->window_shape_prev[cpe->paired_channel], spec_coef2, hDecoder->time_out[cpe->paired_channel], + hDecoder->ssr_overlap[cpe->paired_channel], hDecoder->ipqf_buffer[cpe->paired_channel], hDecoder->prev_fmd[cpe->paired_channel], hDecoder->frameLength); + } +#endif + /* save window shape for next frame */ + hDecoder->window_shape_prev[cpe->channel] = ics1->window_shape; + hDecoder->window_shape_prev[cpe->paired_channel] = ics2->window_shape; +#ifdef LTP_DEC + if (is_ltp_ot(hDecoder->object_type)) { + lt_update_state(hDecoder->lt_pred_stat[cpe->channel], hDecoder->time_out[cpe->channel], hDecoder->fb_intermed[cpe->channel], hDecoder->frameLength, hDecoder->object_type); + lt_update_state(hDecoder->lt_pred_stat[cpe->paired_channel], hDecoder->time_out[cpe->paired_channel], hDecoder->fb_intermed[cpe->paired_channel], hDecoder->frameLength, hDecoder->object_type); + } +#endif +#ifdef SBR_DEC + if (((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) && hDecoder->sbr_alloced[hDecoder->fr_ch_ele]) { + int ele = hDecoder->fr_ch_ele; + int ch0 = cpe->channel; + int ch1 = cpe->paired_channel; + /* following case can happen when forceUpSampling == 1 */ + if (hDecoder->sbr[ele] == NULL) { hDecoder->sbr[ele] = sbrDecodeInit(hDecoder->frameLength, hDecoder->element_id[ele], 2 * get_sample_rate(hDecoder->sf_index), hDecoder->downSampledSBR, 0); } + if (!hDecoder->sbr[ele]) { + retval = 19; + goto exit; + } + if (cpe->ics1.window_sequence == EIGHT_SHORT_SEQUENCE) + hDecoder->sbr[ele]->maxAACLine = 8 * min(cpe->ics1.swb_offset[max(cpe->ics1.max_sfb - 1, 0)], cpe->ics1.swb_offset_max); + else + hDecoder->sbr[ele]->maxAACLine = min(cpe->ics1.swb_offset[max(cpe->ics1.max_sfb - 1, 0)], cpe->ics1.swb_offset_max); + retval = sbrDecodeCoupleFrame(hDecoder->sbr[ele], hDecoder->time_out[ch0], hDecoder->time_out[ch1], hDecoder->postSeekResetFlag, hDecoder->downSampledSBR); + if (retval > 0) { goto exit; } + } else if (((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1)) && !hDecoder->sbr_alloced[hDecoder->fr_ch_ele]) { + retval = 23; + goto exit; + } +#endif + retval = 0; +exit: + faad_free(&spec_coef1); + faad_free(&spec_coef2); + return retval; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* TNS decoding for one channel and frame */ +void NeaacDecoder::tns_decode_frame(ic_stream* ics, tns_info* tns, uint8_t sr_index, uint8_t object_type, real_t* spec, uint16_t frame_len) { + uint8_t w, f, tns_order; + int8_t inc; + int16_t size; + uint16_t bottom, top, start, end; + uint16_t nshort = frame_len / 8; + real_t lpc[TNS_MAX_ORDER + 1]; + if (!ics->tns_data_present) return; + for (w = 0; w < ics->num_windows; w++) { + bottom = ics->num_swb; + for (f = 0; f < tns->n_filt[w]; f++) { + top = bottom; + bottom = max(top - tns->length[w][f], 0); + tns_order = min(tns->order[w][f], (uint8_t)TNS_MAX_ORDER); + if (!tns_order) continue; + tns_decode_coef(tns_order, tns->coef_res[w] + 3, tns->coef_compress[w][f], tns->coef[w][f], lpc); + start = min(bottom, (uint16_t)max_tns_sfb(sr_index, object_type, (ics->window_sequence == EIGHT_SHORT_SEQUENCE))); + start = min(start, (uint16_t)ics->max_sfb); + start = min(ics->swb_offset[start], ics->swb_offset_max); + end = min(top, (uint16_t)max_tns_sfb(sr_index, object_type, (ics->window_sequence == EIGHT_SHORT_SEQUENCE))); + end = min(end, (uint16_t)ics->max_sfb); + end = min(ics->swb_offset[end], ics->swb_offset_max); + size = end - start; + if (size <= 0) continue; + if (tns->direction[w][f]) { + inc = -1; + start = end - 1; + } else { + inc = 1; + } + tns_ar_filter(&spec[(w * nshort) + start], size, inc, lpc, tns_order); + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* TNS encoding for one channel and frame */ +void NeaacDecoder::tns_encode_frame(ic_stream* ics, tns_info* tns, uint8_t sr_index, uint8_t object_type, real_t* spec, uint16_t frame_len) { + uint8_t w, f, tns_order; + int8_t inc; + int16_t size; + uint16_t bottom, top, start, end; + uint16_t nshort = frame_len / 8; + real_t lpc[TNS_MAX_ORDER + 1]; + if (!ics->tns_data_present) return; + for (w = 0; w < ics->num_windows; w++) { + bottom = ics->num_swb; + for (f = 0; f < tns->n_filt[w]; f++) { + top = bottom; + bottom = max(top - tns->length[w][f], 0); + tns_order = min(tns->order[w][f], (uint8_t)TNS_MAX_ORDER); + if (!tns_order) continue; + tns_decode_coef(tns_order, tns->coef_res[w] + 3, tns->coef_compress[w][f], tns->coef[w][f], lpc); + start = min(bottom, (uint16_t)max_tns_sfb(sr_index, object_type, (ics->window_sequence == EIGHT_SHORT_SEQUENCE))); + start = min(start, (uint16_t)ics->max_sfb); + start = min(ics->swb_offset[start], ics->swb_offset_max); + end = min(top, (uint16_t)max_tns_sfb(sr_index, object_type, (ics->window_sequence == EIGHT_SHORT_SEQUENCE))); + end = min(end, (uint16_t)ics->max_sfb); + end = min(ics->swb_offset[end], ics->swb_offset_max); + size = end - start; + if (size <= 0) continue; + if (tns->direction[w][f]) { + inc = -1; + start = end - 1; + } else { + inc = 1; + } + tns_ma_filter(&spec[(w * nshort) + start], size, inc, lpc, tns_order); + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Decoder transmitted coefficients for one TNS filter */ +void NeaacDecoder::tns_decode_coef(uint8_t order, uint8_t coef_res_bits, uint8_t coef_compress, uint8_t* coef, real_t* a) { + uint8_t i, m; + real_t tmp2[TNS_MAX_ORDER + 1], b[TNS_MAX_ORDER + 1]; + /* Conversion to signed integer */ + for (i = 0; i < order; i++) { + if (coef_compress == 0) { + if (coef_res_bits == 3) { + tmp2[i] = tns_coef_0_3[coef[i]]; + } else { + tmp2[i] = tns_coef_0_4[coef[i]]; + } + } else { + if (coef_res_bits == 3) { + tmp2[i] = tns_coef_1_3[coef[i]]; + } else { + tmp2[i] = tns_coef_1_4[coef[i]]; + } + } + } + /* Conversion to LPC coefficients */ + a[0] = COEF_CONST(1.0); + for (m = 1; m <= order; m++) { + for (i = 1; i < m; i++) /* loop only while iframeLengthFlag = faad_get1bit(ld); +#ifndef ALLOW_SMALL_FRAMELENGTH + if (mp4ASC->frameLengthFlag == 1) return -3; +#endif + mp4ASC->dependsOnCoreCoder = faad_get1bit(ld); + if (mp4ASC->dependsOnCoreCoder == 1) { mp4ASC->coreCoderDelay = (uint16_t)faad_getbits(ld, 14); } + mp4ASC->extensionFlag = faad_get1bit(ld); + if (mp4ASC->channelsConfiguration == 0) { + if (program_config_element(&pce, ld)) return -3; + // mp4ASC->channelsConfiguration = pce.channels; + if (pce_out != NULL) memcpy(pce_out, &pce, sizeof(program_config)); + /* + if (pce.num_valid_cc_elements) + return -3; + */ + } +#ifdef ERROR_RESILIENCE + if (mp4ASC->extensionFlag == 1) { + /* Error resilience not supported yet */ + if (mp4ASC->objectTypeIndex >= ER_OBJECT_START) { + mp4ASC->aacSectionDataResilienceFlag = faad_get1bit(ld); + mp4ASC->aacScalefactorDataResilienceFlag = faad_get1bit(ld); + mp4ASC->aacSpectralDataResilienceFlag = faad_get1bit(ld); + } + /* 1 bit: extensionFlag3 */ + faad_getbits(ld, 1); + } +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.2 */ +/* An MPEG-4 Audio decoder is only required to follow the Program Configuration Element in GASpecificConfig(). The decoder shall ignore + any Program Configuration Elements that may occur in raw data blocks. PCEs transmitted in raw data blocks cannot be used to convey decoder + configuration information. +*/ +uint8_t NeaacDecoder::program_config_element(program_config* pce, bitfile* ld) { + uint8_t i; + memset(pce, 0, sizeof(program_config)); + pce->channels = 0; + pce->element_instance_tag = (uint8_t)faad_getbits(ld, 4); + pce->object_type = (uint8_t)faad_getbits(ld, 2); + pce->sf_index = (uint8_t)faad_getbits(ld, 4); + pce->num_front_channel_elements = (uint8_t)faad_getbits(ld, 4); + pce->num_side_channel_elements = (uint8_t)faad_getbits(ld, 4); + pce->num_back_channel_elements = (uint8_t)faad_getbits(ld, 4); + pce->num_lfe_channel_elements = (uint8_t)faad_getbits(ld, 2); + pce->num_assoc_data_elements = (uint8_t)faad_getbits(ld, 3); + pce->num_valid_cc_elements = (uint8_t)faad_getbits(ld, 4); + pce->mono_mixdown_present = faad_get1bit(ld); + if (pce->mono_mixdown_present == 1) { pce->mono_mixdown_element_number = (uint8_t)faad_getbits(ld, 4); } + pce->stereo_mixdown_present = faad_get1bit(ld); + if (pce->stereo_mixdown_present == 1) { pce->stereo_mixdown_element_number = (uint8_t)faad_getbits(ld, 4); } + pce->matrix_mixdown_idx_present = faad_get1bit(ld); + if (pce->matrix_mixdown_idx_present == 1) { + pce->matrix_mixdown_idx = (uint8_t)faad_getbits(ld, 2); + pce->pseudo_surround_enable = faad_get1bit(ld); + } + for (i = 0; i < pce->num_front_channel_elements; i++) { + pce->front_element_is_cpe[i] = faad_get1bit(ld); + pce->front_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + if (pce->front_element_is_cpe[i] & 1) { + pce->cpe_channel[pce->front_element_tag_select[i]] = pce->channels; + pce->num_front_channels += 2; + pce->channels += 2; + } else { + pce->sce_channel[pce->front_element_tag_select[i]] = pce->channels; + pce->num_front_channels++; + pce->channels++; + } + } + for (i = 0; i < pce->num_side_channel_elements; i++) { + pce->side_element_is_cpe[i] = faad_get1bit(ld); + pce->side_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + if (pce->side_element_is_cpe[i] & 1) { + pce->cpe_channel[pce->side_element_tag_select[i]] = pce->channels; + pce->num_side_channels += 2; + pce->channels += 2; + } else { + pce->sce_channel[pce->side_element_tag_select[i]] = pce->channels; + pce->num_side_channels++; + pce->channels++; + } + } + for (i = 0; i < pce->num_back_channel_elements; i++) { + pce->back_element_is_cpe[i] = faad_get1bit(ld); + pce->back_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + if (pce->back_element_is_cpe[i] & 1) { + pce->cpe_channel[pce->back_element_tag_select[i]] = pce->channels; + pce->channels += 2; + pce->num_back_channels += 2; + } else { + pce->sce_channel[pce->back_element_tag_select[i]] = pce->channels; + pce->num_back_channels++; + pce->channels++; + } + } + for (i = 0; i < pce->num_lfe_channel_elements; i++) { + pce->lfe_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + pce->sce_channel[pce->lfe_element_tag_select[i]] = pce->channels; + pce->num_lfe_channels++; + pce->channels++; + } + for (i = 0; i < pce->num_assoc_data_elements; i++) pce->assoc_data_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + for (i = 0; i < pce->num_valid_cc_elements; i++) { + pce->cc_element_is_ind_sw[i] = faad_get1bit(ld); + pce->valid_cc_element_tag_select[i] = (uint8_t)faad_getbits(ld, 4); + } + faad_byte_align(ld); + pce->comment_field_bytes = (uint8_t)faad_getbits(ld, 8); + for (i = 0; i < pce->comment_field_bytes; i++) { pce->comment_field_data[i] = (uint8_t)faad_getbits(ld, 8); } + pce->comment_field_data[i] = 0; + if (pce->channels > MAX_CHANNELS) return 22; + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::decode_sce_lfe(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, uint8_t id_syn_ele) { + uint8_t channels = hDecoder->fr_channels; + uint8_t tag = 0; + if (channels + 1 > MAX_CHANNELS) { + hInfo->error = 12; + return; + } + if (hDecoder->fr_ch_ele + 1 > MAX_SYNTAX_ELEMENTS) { + hInfo->error = 13; + return; + } + /* for SCE hDecoder->element_output_channels[] is not set here because this + can become 2 when some form of Parametric Stereo coding is used + */ + if (hDecoder->element_id[hDecoder->fr_ch_ele] != INVALID_ELEMENT_ID && hDecoder->element_id[hDecoder->fr_ch_ele] != id_syn_ele) { + /* element inconsistency */ + memset(&hDecoder->element_alloced[hDecoder->fr_ch_ele], 0, sizeof(uint8_t) * (MAX_SYNTAX_ELEMENTS - hDecoder->fr_ch_ele)); + hInfo->error = 21; + return; + } + /* save the syntax element id */ + hDecoder->element_id[hDecoder->fr_ch_ele] = id_syn_ele; + /* decode the element */ + hInfo->error = single_lfe_channel_element(hDecoder, ld, channels, &tag); + /* map output channels position to internal data channels */ + if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 2) { + /* this might be faulty when pce_set is true */ + hDecoder->internal_channel[channels] = channels; + hDecoder->internal_channel[channels + 1] = channels + 1; + } else { + if (hDecoder->pce_set) + hDecoder->internal_channel[hDecoder->pce.sce_channel[tag]] = channels; + else + hDecoder->internal_channel[channels] = channels; + } + hDecoder->fr_channels += hDecoder->element_output_channels[hDecoder->fr_ch_ele]; + hDecoder->fr_ch_ele++; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::decode_cpe(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, uint8_t id_syn_ele) { + uint8_t channels = hDecoder->fr_channels; + hInfo->error = 0; + uint8_t tag = 0; + if (channels + 2 > MAX_CHANNELS) { + hInfo->error = 12; + return; + } + if (hDecoder->fr_ch_ele + 1 > MAX_SYNTAX_ELEMENTS) { + hInfo->error = 13; + return; + } + /* for CPE the number of output channels is always 2 */ + if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 0) { + /* element_output_channels not set yet */ + hDecoder->element_output_channels[hDecoder->fr_ch_ele] = 2; + } else if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] != 2) { + /* element inconsistency */ + memset(&hDecoder->element_alloced[hDecoder->fr_ch_ele], 0, sizeof(uint8_t) * (MAX_SYNTAX_ELEMENTS - hDecoder->fr_ch_ele)); + hInfo->error = 21; + return; + } + if (hDecoder->element_id[hDecoder->fr_ch_ele] != INVALID_ELEMENT_ID && hDecoder->element_id[hDecoder->fr_ch_ele] != id_syn_ele) { + /* element inconsistency */ + memset(&hDecoder->element_alloced[hDecoder->fr_ch_ele], 0, sizeof(uint8_t) * (MAX_SYNTAX_ELEMENTS - hDecoder->fr_ch_ele)); + hInfo->error = 21; + return; + } + /* save the syntax element id */ + hDecoder->element_id[hDecoder->fr_ch_ele] = id_syn_ele; + /* decode the element */ + hInfo->error = channel_pair_element(hDecoder, ld, channels, &tag); + /* map output channel position to internal data channels */ + if (hDecoder->pce_set) { + hDecoder->internal_channel[hDecoder->pce.cpe_channel[tag]] = channels; + hDecoder->internal_channel[hDecoder->pce.cpe_channel[tag] + 1] = channels + 1; + } else { + hDecoder->internal_channel[channels] = channels; + hDecoder->internal_channel[channels + 1] = channels + 1; + } + hDecoder->fr_channels += 2; + hDecoder->fr_ch_ele++; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void NeaacDecoder::raw_data_block(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, program_config* pce, drc_info* drc) { + uint8_t id_syn_ele; + uint8_t ele_this_frame = 0; + hDecoder->fr_channels = 0; + hDecoder->fr_ch_ele = 0; + hDecoder->first_syn_ele = 25; + hDecoder->has_lfe = 0; +#ifdef ERROR_RESILIENCE + if (hDecoder->object_type < ER_OBJECT_START) { +#endif + /* Table 4.4.3: raw_data_block() */ + while ((id_syn_ele = (uint8_t)faad_getbits(ld, LEN_SE_ID)) != ID_END) { + switch (id_syn_ele) { + case ID_SCE: + ele_this_frame++; + if (hDecoder->first_syn_ele == 25) hDecoder->first_syn_ele = id_syn_ele; + decode_sce_lfe(hDecoder, hInfo, ld, id_syn_ele); + if (hInfo->error > 0) return; + break; + case ID_CPE: + ele_this_frame++; + if (hDecoder->first_syn_ele == 25) hDecoder->first_syn_ele = id_syn_ele; + decode_cpe(hDecoder, hInfo, ld, id_syn_ele); + if (hInfo->error > 0) return; + break; + case ID_LFE: +#ifdef DRM + hInfo->error = 32; +#else + ele_this_frame++; + hDecoder->has_lfe++; + decode_sce_lfe(hDecoder, hInfo, ld, id_syn_ele); +#endif + if (hInfo->error > 0) return; + break; + case ID_CCE: /* not implemented yet, but skip the bits */ +#ifdef DRM + hInfo->error = 32; +#else + ele_this_frame++; + #ifdef COUPLING_DEC + hInfo->error = coupling_channel_element(hDecoder, ld); + #else + hInfo->error = 6; + #endif +#endif + if (hInfo->error > 0) return; + break; + case ID_DSE: + ele_this_frame++; + data_stream_element(hDecoder, ld); + break; + case ID_PCE: + if (ele_this_frame != 0) { + hInfo->error = 31; + return; + } + ele_this_frame++; + /* 14496-4: 5.6.4.1.2.1.3: */ + /* program_configuration_element()'s in access units shall be ignored */ + program_config_element(pce, ld); + // if ((hInfo->error = program_config_element(pce, ld)) > 0) + // return; + // hDecoder->pce_set = 1; + break; + case ID_FIL: + ele_this_frame++; + /* one sbr_info describes a channel_element not a channel! */ + /* if we encounter SBR data here: error */ + /* SBR data will be read directly in the SCE/LFE/CPE element */ + if ((hInfo->error = fill_element(hDecoder, ld, drc, INVALID_SBR_ELEMENT)) > 0) return; + break; + } + } +#ifdef ERROR_RESILIENCE + } else { + /* Table 262: er_raw_data_block() */ + switch (hDecoder->channelConfiguration) { + case 1: + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + break; + case 2: + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + break; + case 3: + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + break; + case 4: + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + break; + case 5: + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + break; + case 6: + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_sce_lfe(hDecoder, hInfo, ld, ID_LFE); + if (hInfo->error > 0) return; + break; + case 7: /* 8 channels */ + decode_sce_lfe(hDecoder, hInfo, ld, ID_SCE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_cpe(hDecoder, hInfo, ld, ID_CPE); + if (hInfo->error > 0) return; + decode_sce_lfe(hDecoder, hInfo, ld, ID_LFE); + if (hInfo->error > 0) return; + break; + default: hInfo->error = 7; return; + } + #if 0 + cnt = bits_to_decode() / 8; + while (cnt >= 1) + { + cnt -= extension_payload(cnt); + } + #endif + } +#endif + /* new in corrigendum 14496-3:2002 */ +#ifdef DRM + if (hDecoder->object_type != DRM_ER_LC + #if 0 + && !hDecoder->latm_header_present + #endif + ) +#endif + { + faad_byte_align(ld); + } + return; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.4 and */ +/* Table 4.4.9 */ +uint8_t NeaacDecoder::single_lfe_channel_element(NeAACDecStruct* hDecoder, bitfile* ld, uint8_t channel, uint8_t* tag) { + uint8_t retval = 0; + // element sce = {0}; + element* sce = (element*)faad_calloc(1, sizeof(element)); + ic_stream* ics = &(sce->ics1); + // int16_t spec_data[1024] = {0}; + int16_t* spec_data = (int16_t*)faad_calloc(1024, sizeof(int16_t)); + sce->element_instance_tag = (uint8_t)faad_getbits(ld, LEN_TAG); + *tag = sce->element_instance_tag; + sce->channel = channel; + sce->paired_channel = -1; + retval = individual_channel_stream(hDecoder, sce, ld, ics, 0, spec_data); + if (retval > 0) goto exit; + /* IS not allowed in single channel */ + if (ics->is_used) { + retval = 32; + goto exit; + } +#ifdef SBR_DEC + /* check if next bitstream element is a fill element */ + /* if so, read it now so SBR decoding can be done in case of a file with SBR */ + if (faad_showbits(ld, LEN_SE_ID) == ID_FIL) { + faad_flushbits(ld, LEN_SE_ID); + /* one sbr_info describes a channel_element not a channel! */ + if ((retval = fill_element(hDecoder, ld, hDecoder->drc, hDecoder->fr_ch_ele)) > 0) { goto exit; } + } +#endif + /* noiseless coding is done, spectral reconstruction is done now */ + retval = reconstruct_single_channel(hDecoder, ics, sce, spec_data); + if (retval > 0) goto exit; + retval = 0; +exit: + faad_free(&sce); + faad_free(&spec_data); + return retval; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.5 */ +uint8_t NeaacDecoder::channel_pair_element(NeAACDecStruct* hDecoder, bitfile* ld, uint8_t channels, uint8_t* tag) { + // int16_t spec_data1[1024] = {0}; + // int16_t spec_data2[1024] = {0}; + int16_t* spec_data1 = (int16_t*)faad_calloc(1024, sizeof(int16_t)); + int16_t* spec_data2 = (int16_t*)faad_calloc(1024, sizeof(int16_t)); + // element cpe = {0}; + element* cpe = (element*)faad_calloc(1, sizeof(element)); + ic_stream* ics1 = &(cpe->ics1); + ic_stream* ics2 = &(cpe->ics2); + uint8_t result; + cpe->channel = channels; + cpe->paired_channel = channels + 1; + cpe->element_instance_tag = (uint8_t)faad_getbits(ld, LEN_TAG); + *tag = cpe->element_instance_tag; + if ((cpe->common_window = faad_get1bit(ld) & 1)) { + /* both channels have common ics information */ + if ((result = ics_info(hDecoder, ics1, ld, cpe->common_window)) > 0) goto exit; + ics1->ms_mask_present = (uint8_t)faad_getbits(ld, 2); + if (ics1->ms_mask_present == 3) { + /* bitstream error */ + result = 32; + goto exit; + } + if (ics1->ms_mask_present == 1) { + uint8_t g, sfb; + for (g = 0; g < ics1->num_window_groups; g++) { + for (sfb = 0; sfb < ics1->max_sfb; sfb++) { ics1->ms_used[g][sfb] = faad_get1bit(ld); } + } + } +#ifdef ERROR_RESILIENCE + if ((hDecoder->object_type >= ER_OBJECT_START) && (ics1->predictor_data_present)) { + if (( + #ifdef LTP_DEC + ics1->ltp.data_present = + #endif + faad_get1bit(ld)) & + 1) { + #ifdef LTP_DEC + if ((result = ltp_data(hDecoder, ics1, &(ics1->ltp), ld)) > 0) { goto exit; } + #else + result = 26; + goto exit; // return 26; + #endif + } + } +#endif + memcpy(ics2, ics1, sizeof(ic_stream)); + } else { + ics1->ms_mask_present = 0; + } + if ((result = individual_channel_stream(hDecoder, cpe, ld, ics1, 0, spec_data1)) > 0) { goto exit; } +#ifdef ERROR_RESILIENCE + if (cpe->common_window && (hDecoder->object_type >= ER_OBJECT_START) && (ics1->predictor_data_present)) { + if (( + #ifdef LTP_DEC + ics1->ltp2.data_present = + #endif + faad_get1bit(ld)) & + 1) { + #ifdef LTP_DEC + if ((result = ltp_data(hDecoder, ics1, &(ics1->ltp2), ld)) > 0) { goto exit; } + #else + result = 26; + goto exit; // return 26; + #endif + } + } +#endif + if ((result = individual_channel_stream(hDecoder, cpe, ld, ics2, 0, spec_data2)) > 0) { goto exit; } +#ifdef SBR_DEC + /* check if next bitstream element is a fill element */ + /* if so, read it now so SBR decoding can be done in case of a file with SBR */ + if (faad_showbits(ld, LEN_SE_ID) == ID_FIL) { + faad_flushbits(ld, LEN_SE_ID); + /* one sbr_info describes a channel_element not a channel! */ + if ((result = fill_element(hDecoder, ld, hDecoder->drc, hDecoder->fr_ch_ele)) > 0) { goto exit; } + } +#endif + /* noiseless coding is done, spectral reconstruction is done now */ + if ((result = reconstruct_channel_pair(hDecoder, ics1, ics2, cpe, spec_data1, spec_data2)) > 0) { goto exit; } + result = 0; +exit: + faad_free(&spec_data1); + faad_free(&spec_data2); + faad_free(&cpe); + return result; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.6 */ +uint8_t NeaacDecoder::ics_info(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, uint8_t common_window) { + uint8_t retval = 0; + uint8_t ics_reserved_bit; + ics_reserved_bit = faad_get1bit(ld); + if (ics_reserved_bit != 0) return 32; + ics->window_sequence = (uint8_t)faad_getbits(ld, 2); + ics->window_shape = faad_get1bit(ld); +#ifdef LD_DEC + /* No block switching in LD */ + if ((hDecoder->object_type == LD) && (ics->window_sequence != ONLY_LONG_SEQUENCE)) return 32; +#endif + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + ics->max_sfb = (uint8_t)faad_getbits(ld, 4); + ics->scale_factor_grouping = (uint8_t)faad_getbits(ld, 7); + } else { + ics->max_sfb = (uint8_t)faad_getbits(ld, 6); + } + /* get the grouping information */ + if ((retval = window_grouping_info(hDecoder, ics)) > 0) return retval; + /* should be an error */ + /* check the range of max_sfb */ + if (ics->max_sfb > ics->num_swb) return 16; + if (ics->window_sequence != EIGHT_SHORT_SEQUENCE) { + if ((ics->predictor_data_present = faad_get1bit(ld)) & 1) { + if (hDecoder->object_type == MAIN) /* MPEG2 style AAC predictor */ + { + uint8_t sfb; + uint8_t limit = min(ics->max_sfb, max_pred_sfb(hDecoder->sf_index)); +#ifdef MAIN_DEC + ics->pred.limit = limit; +#endif + if (( +#ifdef MAIN_DEC + ics->pred.predictor_reset = +#endif + faad_get1bit(ld)) & + 1) { +#ifdef MAIN_DEC + ics->pred.predictor_reset_group_number = +#endif + faad_getbits(ld, 5); + } + for (sfb = 0; sfb < limit; sfb++) { +#ifdef MAIN_DEC + ics->pred.prediction_used[sfb] = +#endif + faad_get1bit(ld); + } + } +#ifdef LTP_DEC + else { /* Long Term Prediction */ + if (hDecoder->object_type < ER_OBJECT_START) { + if ((ics->ltp.data_present = faad_get1bit(ld)) & 1) { + if ((retval = ltp_data(hDecoder, ics, &(ics->ltp), ld)) > 0) { return retval; } + } + if (common_window) { + if ((ics->ltp2.data_present = faad_get1bit(ld)) & 1) { + if ((retval = ltp_data(hDecoder, ics, &(ics->ltp2), ld)) > 0) { return retval; } + } + } + } + #ifdef ERROR_RESILIENCE + if (!common_window && (hDecoder->object_type >= ER_OBJECT_START)) { + if ((ics->ltp.data_present = faad_get1bit(ld)) & 1) { + if ((retval = ltp_data(hDecoder, ics, &(ics->ltp), ld)) > 0) { return retval; } + } + } + #endif + } +#endif + } + } + return retval; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.7 */ +uint8_t NeaacDecoder::pulse_data(ic_stream* ics, pulse_info* pul, bitfile* ld) { + uint8_t i; + pul->number_pulse = (uint8_t)faad_getbits(ld, 2); + pul->pulse_start_sfb = (uint8_t)faad_getbits(ld, 6); + /* check the range of pulse_start_sfb */ + if (pul->pulse_start_sfb > ics->num_swb) return 16; + for (i = 0; i < pul->number_pulse + 1; i++) { + pul->pulse_offset[i] = (uint8_t)faad_getbits(ld, 5); +#if 0 + printf("%d\n", pul->pulse_offset[i]); +#endif + pul->pulse_amp[i] = (uint8_t)faad_getbits(ld, 4); +#if 0 + printf("%d\n", pul->pulse_amp[i]); +#endif + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef COUPLING_DEC +/* Table 4.4.8: Currently just for skipping the bits... */ +uint8_t NeaacDecoder::coupling_channel_element(NeAACDecStruct* hDecoder, bitfile* ld) { + uint8_t c, result = 0; + uint8_t ind_sw_cce_flag = 0; + uint8_t num_gain_element_lists = 0; + uint8_t num_coupled_elements = 0; + element el_empty = {0}; + ic_stream ics_empty = {0}; + int16_t sh_data[1024]; + c = faad_getbits(ld, LEN_TAG); + ind_sw_cce_flag = faad_get1bit(ld); + num_coupled_elements = faad_getbits(ld, 3); + for (c = 0; c < num_coupled_elements + 1; c++) { + uint8_t cc_target_is_cpe, cc_target_tag_select; + num_gain_element_lists++; + cc_target_is_cpe = faad_get1bit(ld); + cc_target_tag_select = faad_getbits(ld, 4); + if (cc_target_is_cpe) { + uint8_t cc_l = faad_get1bit(ld); + uint8_t cc_r = faad_get1bit(ld); + if (cc_l && cc_r) num_gain_element_lists++; + } + } + faad_get1bit(ld); + faad_get1bit(ld); + faad_getbits(ld, 2); + if ((result = individual_channel_stream(hDecoder, &el_empty, ld, &ics_empty, 0, sh_data)) > 0) { return result; } + /* IS not allowed in single channel */ + if (ics->is_used) return 32; + for (c = 1; c < num_gain_element_lists; c++) { + uint8_t cge; + if (ind_sw_cce_flag) { + cge = 1; + } else { + cge = faad_get1bit(ld); + } + if (cge) { + huffman_scale_factor(ld); + } else { + uint8_t g, sfb; + for (g = 0; g < ics_empty.num_window_groups; g++) { + for (sfb = 0; sfb < ics_empty.max_sfb; sfb++) { + if (ics_empty.sfb_cb[g][sfb] != ZERO_HCB) huffman_scale_factor(ld); + } + } + } + } + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.10 */ +uint16_t NeaacDecoder::data_stream_element(NeAACDecStruct* hDecoder, bitfile* ld) { + uint8_t byte_aligned; + uint16_t i, count; + /* element_instance_tag = */ faad_getbits(ld, LEN_TAG); + byte_aligned = faad_get1bit(ld); + count = (uint16_t)faad_getbits(ld, 8); + if (count == 255) { count += (uint16_t)faad_getbits(ld, 8); } + if (byte_aligned) faad_byte_align(ld); + for (i = 0; i < count; i++) { faad_getbits(ld, LEN_BYTE); } + return count; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.11 */ +uint8_t NeaacDecoder::fill_element(NeAACDecStruct* hDecoder, bitfile* ld, drc_info* drc, uint8_t sbr_ele) { + uint16_t count; +#ifdef SBR_DEC + uint8_t bs_extension_type; +#endif + count = (uint16_t)faad_getbits(ld, 4); + if (count == 15) { count += (uint16_t)faad_getbits(ld, 8) - 1; } + if (count > 0) { +#ifdef SBR_DEC + bs_extension_type = (uint8_t)faad_showbits(ld, 4); + if ((bs_extension_type == EXT_SBR_DATA) || (bs_extension_type == EXT_SBR_DATA_CRC)) { + if (sbr_ele == INVALID_SBR_ELEMENT) return 24; + if (!hDecoder->sbr[sbr_ele]) { + hDecoder->sbr[sbr_ele] = sbrDecodeInit(hDecoder->frameLength, hDecoder->element_id[sbr_ele], 2 * get_sample_rate(hDecoder->sf_index), hDecoder->downSampledSBR, 0); + } + if (!hDecoder->sbr[sbr_ele]) return 19; + hDecoder->sbr_present_flag = 1; + /* parse the SBR data */ + hDecoder->sbr[sbr_ele]->ret = sbr_extension_data(ld, hDecoder->sbr[sbr_ele], count, hDecoder->postSeekResetFlag); + #if 0 + if (hDecoder->sbr[sbr_ele]->ret > 0) + { + printf("%s\n", NeAACDecGetErrorMessage(hDecoder->sbr[sbr_ele]->ret)); + } + #endif + #if (defined(PS_DEC) || defined(DRM_PS)) + if (hDecoder->sbr[sbr_ele]->ps_used) { + hDecoder->ps_used[sbr_ele] = 1; + /* set element independent flag to 1 as well */ + hDecoder->ps_used_global = 1; + } + #endif + } else { +#endif +#ifndef DRM + while (count > 0) { count -= extension_payload(ld, drc, count); } +#else + return 30; +#endif +#ifdef SBR_DEC + } +#endif + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.12 */ +#ifdef SSR_DEC +void NeaacDecoder::gain_control_data(bitfile* ld, ic_stream* ics) { + uint8_t bd, wd, ad; + ssr_info* ssr = &(ics->ssr); + ssr->max_band = (uint8_t)faad_getbits(ld, 2); + if (ics->window_sequence == ONLY_LONG_SEQUENCE) { + for (bd = 1; bd <= ssr->max_band; bd++) { + for (wd = 0; wd < 1; wd++) { + ssr->adjust_num[bd][wd] = (uint8_t)faad_getbits(ld, 3); + for (ad = 0; ad < ssr->adjust_num[bd][wd]; ad++) { + ssr->alevcode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 5); + } + } + } + } else if (ics->window_sequence == LONG_START_SEQUENCE) { + for (bd = 1; bd <= ssr->max_band; bd++) { + for (wd = 0; wd < 2; wd++) { + ssr->adjust_num[bd][wd] = (uint8_t)faad_getbits(ld, 3); + for (ad = 0; ad < ssr->adjust_num[bd][wd]; ad++) { + ssr->alevcode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + if (wd == 0) { + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + } else { + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 2); + } + } + } + } + } else if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + for (bd = 1; bd <= ssr->max_band; bd++) { + for (wd = 0; wd < 8; wd++) { + ssr->adjust_num[bd][wd] = (uint8_t)faad_getbits(ld, 3); + for (ad = 0; ad < ssr->adjust_num[bd][wd]; ad++) { + ssr->alevcode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 2); + } + } + } + } else if (ics->window_sequence == LONG_STOP_SEQUENCE) { + for (bd = 1; bd <= ssr->max_band; bd++) { + for (wd = 0; wd < 2; wd++) { + ssr->adjust_num[bd][wd] = (uint8_t)faad_getbits(ld, 3); + for (ad = 0; ad < ssr->adjust_num[bd][wd]; ad++) { + ssr->alevcode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + if (wd == 0) { + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 4); + } else { + ssr->aloccode[bd][wd][ad] = (uint8_t)faad_getbits(ld, 5); + } + } + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef DRM +/* Table 4.4.13 ASME */ +void NeaacDecoder::DRM_aac_scalable_main_element(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, program_config* pce, drc_info* drc) { + uint8_t retval = 0; + (void)retval; + uint8_t channels = hDecoder->fr_channels = 0; + uint8_t ch; + (void)ch; + uint8_t this_layer_stereo = (hDecoder->channelConfiguration > 1) ? 1 : 0; + element cpe = {0}; + ic_stream* ics1 = &(cpe.ics1); + ic_stream* ics2 = &(cpe.ics2); + int16_t* spec_data; + (void)spec_data; + int16_t spec_data1[1024] = {0}; + int16_t spec_data2[1024] = {0}; + hDecoder->fr_ch_ele = 0; + hInfo->error = DRM_aac_scalable_main_header(hDecoder, ics1, ics2, ld, this_layer_stereo); + if (hInfo->error > 0) return; + cpe.common_window = 1; + if (this_layer_stereo) { + hDecoder->element_id[0] = ID_CPE; + if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 0) hDecoder->element_output_channels[hDecoder->fr_ch_ele] = 2; + } else { + hDecoder->element_id[0] = ID_SCE; + } + if (this_layer_stereo) { + cpe.channel = 0; + cpe.paired_channel = 1; + } + /* Stereo2 / Mono1 */ + ics1->tns_data_present = faad_get1bit(ld); + #if defined(LTP_DEC) + ics1->ltp.data_present = faad_get1bit(ld); + #elif defined(DRM) + if (faad_get1bit(ld)) { + hInfo->error = 26; + return; + } + #else + faad_get1bit(ld); + #endif + hInfo->error = side_info(hDecoder, &cpe, ld, ics1, 1); + if (hInfo->error > 0) return; + if (this_layer_stereo) { + /* Stereo3 */ + ics2->tns_data_present = faad_get1bit(ld); + #ifdef LTP_DEC + ics1->ltp.data_present = + #endif + faad_get1bit(ld); + hInfo->error = side_info(hDecoder, &cpe, ld, ics2, 1); + if (hInfo->error > 0) return; + } + /* Stereo4 / Mono2 */ + if (ics1->tns_data_present) tns_data(ics1, &(ics1->tns), ld); + if (this_layer_stereo) { + /* Stereo5 */ + if (ics2->tns_data_present) tns_data(ics2, &(ics2->tns), ld); + } + #ifdef DRM + /* CRC check */ + if (hDecoder->object_type == DRM_ER_LC) { + if ((hInfo->error = (uint8_t)faad_check_CRC(ld, (uint16_t)faad_get_processed_bits(ld) - 8)) > 0) return; + } + #endif + /* Stereo6 / Mono3 */ + /* error resilient spectral data decoding */ + if ((hInfo->error = reordered_spectral_data(hDecoder, ics1, ld, spec_data1)) > 0) { return; } + if (this_layer_stereo) { + /* Stereo7 */ + /* error resilient spectral data decoding */ + if ((hInfo->error = reordered_spectral_data(hDecoder, ics2, ld, spec_data2)) > 0) { return; } + } + #ifdef DRM + #ifdef SBR_DEC + /* In case of DRM we need to read the SBR info before channel reconstruction */ + if ((hDecoder->sbr_present_flag == 1) && (hDecoder->object_type == DRM_ER_LC)) { + bitfile ld_sbr = {0}; + uint32_t i; + uint16_t count = 0; + uint8_t* revbuffer; + uint8_t* prevbufstart; + uint8_t* pbufend; + /* all forward bitreading should be finished at this point */ + uint32_t bitsconsumed = faad_get_processed_bits(ld); + uint32_t buffer_size = faad_origbitbuffer_size(ld); + uint8_t* buffer = (uint8_t*)faad_origbitbuffer(ld); + if (bitsconsumed + 8 > buffer_size * 8) { + hInfo->error = 14; + return; + } + if (!hDecoder->sbr[0]) { hDecoder->sbr[0] = sbrDecodeInit(hDecoder->frameLength, hDecoder->element_id[0], 2 * get_sample_rate(hDecoder->sf_index), 0 /* ds SBR */, 1); } + if (!hDecoder->sbr[0]) { + hInfo->error = 19; + return; + } + /* Reverse bit reading of SBR data in DRM audio frame */ + revbuffer = (uint8_t*)faad_malloc(buffer_size * sizeof(uint8_t)); + prevbufstart = revbuffer; + pbufend = &buffer[buffer_size - 1]; + for (i = 0; i < buffer_size; i++) *prevbufstart++ = tabFlipbits[*pbufend--]; + /* Set SBR data */ + /* consider 8 bits from AAC-CRC */ + /* SBR buffer size is original buffer size minus AAC buffer size */ + count = (uint16_t)bit2byte(buffer_size * 8 - bitsconsumed); + faad_initbits(&ld_sbr, revbuffer, count); + hDecoder->sbr[0]->sample_rate = get_sample_rate(hDecoder->sf_index); + hDecoder->sbr[0]->sample_rate *= 2; + faad_getbits(&ld_sbr, 8); /* Skip 8-bit CRC */ + hDecoder->sbr[0]->ret = sbr_extension_data(&ld_sbr, hDecoder->sbr[0], count, hDecoder->postSeekResetFlag); + #if (defined(PS_DEC) || defined(DRM_PS)) + if (hDecoder->sbr[0]->ps_used) { + hDecoder->ps_used[0] = 1; + hDecoder->ps_used_global = 1; + } + #endif + if (ld_sbr.error) { hDecoder->sbr[0]->ret = 1; } + /* check CRC */ + /* no need to check it if there was already an error */ + if (hDecoder->sbr[0]->ret == 0) hDecoder->sbr[0]->ret = (uint8_t)faad_check_CRC(&ld_sbr, (uint16_t)faad_get_processed_bits(&ld_sbr) - 8); + /* SBR data was corrupted, disable it until the next header */ + if (hDecoder->sbr[0]->ret != 0) { hDecoder->sbr[0]->header_count = 0; } + faad_endbits(&ld_sbr); + if (revbuffer) faad_free(&revbuffer); + } + #endif + #endif + if (this_layer_stereo) { + hInfo->error = reconstruct_channel_pair(hDecoder, ics1, ics2, &cpe, spec_data1, spec_data2); + if (hInfo->error > 0) return; + } else { + hInfo->error = reconstruct_single_channel(hDecoder, ics1, &cpe, spec_data1); + if (hInfo->error > 0) return; + } + /* map output channels position to internal data channels */ + if (hDecoder->element_output_channels[hDecoder->fr_ch_ele] == 2) { + /* this might be faulty when pce_set is true */ + hDecoder->internal_channel[channels] = channels; + hDecoder->internal_channel[channels + 1] = channels + 1; + } else { + hDecoder->internal_channel[channels] = channels; + } + hDecoder->fr_channels += hDecoder->element_output_channels[hDecoder->fr_ch_ele]; + hDecoder->fr_ch_ele++; + return; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.15 */ +int8_t NeaacDecoder::DRM_aac_scalable_main_header(NeAACDecStruct* hDecoder, ic_stream* ics1, ic_stream* ics2, bitfile* ld, uint8_t this_layer_stereo) { + uint8_t retval = 0; + uint8_t ch; + (void)ch; + ic_stream* ics; + (void)ics; + uint8_t ics_reserved_bit; + ics_reserved_bit = faad_get1bit(ld); + if (ics_reserved_bit != 0) return 32; + ics1->window_sequence = (uint8_t)faad_getbits(ld, 2); + ics1->window_shape = faad_get1bit(ld); + if (ics1->window_sequence == EIGHT_SHORT_SEQUENCE) { + ics1->max_sfb = (uint8_t)faad_getbits(ld, 4); + ics1->scale_factor_grouping = (uint8_t)faad_getbits(ld, 7); + } else { + ics1->max_sfb = (uint8_t)faad_getbits(ld, 6); + } + /* get the grouping information */ + if ((retval = window_grouping_info(hDecoder, ics1)) > 0) return retval; + /* should be an error */ + /* check the range of max_sfb */ + if (ics1->max_sfb > ics1->num_swb) return 16; + if (this_layer_stereo) { + ics1->ms_mask_present = (uint8_t)faad_getbits(ld, 2); + if (ics1->ms_mask_present == 3) { + /* bitstream error */ + return 32; + } + if (ics1->ms_mask_present == 1) { + uint8_t g, sfb; + for (g = 0; g < ics1->num_window_groups; g++) { + for (sfb = 0; sfb < ics1->max_sfb; sfb++) { ics1->ms_used[g][sfb] = faad_get1bit(ld); } + } + } + memcpy(ics2, ics1, sizeof(ic_stream)); + } else { + ics1->ms_mask_present = 0; + } + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::side_info(NeAACDecStruct* hDecoder, element* ele, bitfile* ld, ic_stream* ics, uint8_t scal_flag) { + uint8_t result; + ics->global_gain = (uint8_t)faad_getbits(ld, 8); + if (!ele->common_window && !scal_flag) { + if ((result = ics_info(hDecoder, ics, ld, ele->common_window)) > 0) return result; + } + if ((result = section_data(hDecoder, ics, ld)) > 0) return result; + if ((result = scale_factor_data(hDecoder, ics, ld)) > 0) return result; + if (!scal_flag) { + /** + ** NOTE: It could be that pulse data is available in scalable AAC too, + ** as said in Amendment 1, this could be only the case for ER AAC, + ** though. (have to check this out later) + **/ + /* get pulse data */ + if ((ics->pulse_data_present = faad_get1bit(ld)) & 1) { + if ((result = pulse_data(ics, &(ics->pul), ld)) > 0) return result; + } + /* get tns data */ + if ((ics->tns_data_present = faad_get1bit(ld)) & 1) { +#ifdef ERROR_RESILIENCE + if (hDecoder->object_type < ER_OBJECT_START) +#endif + tns_data(ics, &(ics->tns), ld); + } + /* get gain control data */ + if ((ics->gain_control_data_present = faad_get1bit(ld)) & 1) { +#ifdef SSR_DEC + if (hDecoder->object_type != SSR) + return 1; + else + gain_control_data(ld, ics); +#else + return 1; +#endif + } + } +#ifdef ERROR_RESILIENCE + if (hDecoder->aacSpectralDataResilienceFlag) { + ics->length_of_reordered_spectral_data = (uint16_t)faad_getbits(ld, 14); + if (hDecoder->channelConfiguration == 2) { + if (ics->length_of_reordered_spectral_data > 6144) ics->length_of_reordered_spectral_data = 6144; + } else { + if (ics->length_of_reordered_spectral_data > 12288) ics->length_of_reordered_spectral_data = 12288; + } + ics->length_of_longest_codeword = (uint8_t)faad_getbits(ld, 6); + if (ics->length_of_longest_codeword >= 49) ics->length_of_longest_codeword = 49; + } + /* RVLC spectral data is put here */ + if (hDecoder->aacScalefactorDataResilienceFlag) { + if ((result = rvlc_decode_scale_factors(ics, ld)) > 0) return result; + } +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.24 */ +uint8_t NeaacDecoder::individual_channel_stream(NeAACDecStruct* hDecoder, element* ele, bitfile* ld, ic_stream* ics, uint8_t scal_flag, int16_t* spec_data) { + uint8_t result; + result = side_info(hDecoder, ele, ld, ics, scal_flag); + if (result > 0) return result; + if (hDecoder->object_type >= ER_OBJECT_START) { + if (ics->tns_data_present) tns_data(ics, &(ics->tns), ld); + } +#ifdef DRM + /* CRC check */ + if (hDecoder->object_type == DRM_ER_LC) { + if ((result = (uint8_t)faad_check_CRC(ld, (uint16_t)faad_get_processed_bits(ld) - 8)) > 0) return result; + } +#endif +#ifdef ERROR_RESILIENCE + if (hDecoder->aacSpectralDataResilienceFlag) { + /* error resilient spectral data decoding */ + if ((result = reordered_spectral_data(hDecoder, ics, ld, spec_data)) > 0) { return result; } + } else { +#endif + /* decode the spectral data */ + if ((result = spectral_data(hDecoder, ics, ld, spec_data)) > 0) { return result; } +#ifdef ERROR_RESILIENCE + } +#endif + /* pulse coding reconstruction */ + if (ics->pulse_data_present) { + if (ics->window_sequence != EIGHT_SHORT_SEQUENCE) { + if ((result = pulse_decode(ics, spec_data, hDecoder->frameLength)) > 0) return result; + } else { + return 2; /* pulse coding not allowed for short blocks */ + } + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.25 */ +uint8_t NeaacDecoder::section_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld) { + uint8_t g; + uint8_t sect_esc_val, sect_bits; + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) + sect_bits = 3; + else + sect_bits = 5; + sect_esc_val = (1 << sect_bits) - 1; +#if 0 + printf("\ntotal sfb %d\n", ics->max_sfb); + printf(" sect top cb\n"); +#endif + for (g = 0; g < ics->num_window_groups; g++) { + uint8_t k = 0; + uint8_t i = 0; + while (k < ics->max_sfb) { +#ifdef ERROR_RESILIENCE + uint8_t vcb11 = 0; +#endif + uint8_t sfb; + uint8_t sect_len_incr; + uint16_t sect_len = 0; + uint8_t sect_cb_bits = 4; + /* if "faad_getbits" detects error and returns "0", "k" is never + incremented and we cannot leave the while loop */ + if (ld->error != 0) return 14; +#ifdef ERROR_RESILIENCE + if (hDecoder->aacSectionDataResilienceFlag) sect_cb_bits = 5; +#endif + ics->sect_cb[g][i] = (uint8_t)faad_getbits(ld, sect_cb_bits); + if (ics->sect_cb[g][i] == 12) return 32; +#if 0 + printf("%d\n", ics->sect_cb[g][i]); +#endif +#ifndef DRM + if (ics->sect_cb[g][i] == NOISE_HCB) ics->noise_used = 1; +#else + /* PNS not allowed in DRM */ + if (ics->sect_cb[g][i] == NOISE_HCB) return 29; +#endif + if (ics->sect_cb[g][i] == INTENSITY_HCB2 || ics->sect_cb[g][i] == INTENSITY_HCB) ics->is_used = 1; +#ifdef ERROR_RESILIENCE + if (hDecoder->aacSectionDataResilienceFlag) { + if ((ics->sect_cb[g][i] == 11) || ((ics->sect_cb[g][i] >= 16) && (ics->sect_cb[g][i] <= 32))) { vcb11 = 1; } + } + if (vcb11) { + sect_len_incr = 1; + } else { +#endif + sect_len_incr = (uint8_t)faad_getbits(ld, sect_bits); +#ifdef ERROR_RESILIENCE + } +#endif + while ((sect_len_incr == sect_esc_val) /* && + (k+sect_len < ics->max_sfb)*/) + { + sect_len += sect_len_incr; + sect_len_incr = (uint8_t)faad_getbits(ld, sect_bits); + } + sect_len += sect_len_incr; + ics->sect_start[g][i] = k; + ics->sect_end[g][i] = k + sect_len; +#if 0 + printf("%d\n", ics->sect_start[g][i]); +#endif +#if 0 + printf("%d\n", ics->sect_end[g][i]); +#endif + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + if (k + sect_len > 8 * 15) return 15; + if (i >= 8 * 15) return 15; + } else { + if (k + sect_len > MAX_SFB) return 15; + if (i >= MAX_SFB) return 15; + } + for (sfb = k; sfb < k + sect_len; sfb++) { + ics->sfb_cb[g][sfb] = ics->sect_cb[g][i]; +#if 0 + printf("%d\n", ics->sfb_cb[g][sfb]); +#endif + } +#if 0 + printf(" %6d %6d %6d\n", + i, + ics->sect_end[g][i], + ics->sect_cb[g][i]); +#endif + k += sect_len; + i++; + } + if (g < 8) { ics->num_sec[g] = i; } + /* the sum of all sect_len_incr elements for a given window + * group shall equal max_sfb */ + if (k != ics->max_sfb) { return 32; } +#if 0 + printf("%d\n", ics->num_sec[g]); +#endif + } +#if 0 + printf("\n"); +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* decode_scale_factors() decodes the scalefactors from the bitstream + * All scalefactors (and also the stereo positions and pns energies) are transmitted using Huffman coded DPCM relative to the previous active + * scalefactor (respectively previous stereo position or previous pns energy, see subclause 4.6.2 and 4.6.3). The first active scalefactor is + * differentially coded relative to the global gain. + */ +uint8_t NeaacDecoder::decode_scale_factors(ic_stream* ics, bitfile* ld) { + uint8_t g, sfb; + int16_t t; + int8_t noise_pcm_flag = 1; + (void)noise_pcm_flag; + int16_t scale_factor = ics->global_gain; + int16_t is_position = 0; + int16_t noise_energy = ics->global_gain - 90; + (void)noise_energy; + for (g = 0; g < ics->num_window_groups; g++) { + for (sfb = 0; sfb < ics->max_sfb; sfb++) { + switch (ics->sfb_cb[g][sfb]) { + case ZERO_HCB: /* zero book */ + ics->scale_factors[g][sfb] = 0; +// #define SF_PRINT +#ifdef SF_PRINT + printf("%d\n", ics->scale_factors[g][sfb]); +#endif + break; + case INTENSITY_HCB: /* intensity books */ + case INTENSITY_HCB2: + /* decode intensity position */ + t = huffman_scale_factor(ld); + is_position += (t - 60); + ics->scale_factors[g][sfb] = is_position; +#ifdef SF_PRINT + printf("%d\n", ics->scale_factors[g][sfb]); +#endif + break; + case NOISE_HCB: /* noise books */ +#ifndef DRM + /* decode noise energy */ + if (noise_pcm_flag) { + noise_pcm_flag = 0; + t = (int16_t)faad_getbits(ld, 9) - 256; + } else { + t = huffman_scale_factor(ld); + t -= 60; + } + noise_energy += t; + ics->scale_factors[g][sfb] = noise_energy; + #ifdef SF_PRINT + printf("%d\n", ics->scale_factors[g][sfb]); + #endif +#else + /* PNS not allowed in DRM */ + return 29; +#endif + break; + default: /* spectral books */ + /* ics->scale_factors[g][sfb] must be between 0 and 255 */ + ics->scale_factors[g][sfb] = 0; + /* decode scale factor */ + t = huffman_scale_factor(ld); + scale_factor += (t - 60); + if (scale_factor < 0 || scale_factor > 255) return 4; + ics->scale_factors[g][sfb] = scale_factor; +#ifdef SF_PRINT + printf("%d\n", ics->scale_factors[g][sfb]); +#endif + break; + } + } + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.26 */ +uint8_t NeaacDecoder::scale_factor_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld) { + uint8_t ret = 0; +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif +#ifdef ERROR_RESILIENCE + if (!hDecoder->aacScalefactorDataResilienceFlag) { +#endif + ret = decode_scale_factors(ics, ld); +#ifdef ERROR_RESILIENCE + } else { + /* In ER AAC the parameters for RVLC are seperated from the actual + data that holds the scale_factors. + Strangely enough, 2 parameters for HCR are put inbetween them. + */ + ret = rvlc_scale_factor_data(ics, ld); + } +#endif +#ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->scalefac_cycles += count; +#endif + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.27 */ +void NeaacDecoder::tns_data(ic_stream* ics, tns_info* tns, bitfile* ld) { + uint8_t w, filt, i, start_coef_bits = 0, coef_bits; + uint8_t n_filt_bits = 2; + uint8_t length_bits = 6; + uint8_t order_bits = 5; + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + n_filt_bits = 1; + length_bits = 4; + order_bits = 3; + } + for (w = 0; w < ics->num_windows; w++) { + tns->n_filt[w] = (uint8_t)faad_getbits(ld, (uint32_t)n_filt_bits); +#if 0 + printf("%d\n", tns->n_filt[w]); +#endif + if (tns->n_filt[w]) { + if ((tns->coef_res[w] = faad_get1bit(ld)) & 1) { + start_coef_bits = 4; + } else { + start_coef_bits = 3; + } +#if 0 + printf("%d\n", tns->coef_res[w]); +#endif + } + for (filt = 0; filt < tns->n_filt[w]; filt++) { + tns->length[w][filt] = (uint8_t)faad_getbits(ld, length_bits); +#if 0 + printf("%d\n", tns->length[w][filt]); +#endif + tns->order[w][filt] = (uint8_t)faad_getbits(ld, order_bits); +#if 0 + printf("%d\n", tns->order[w][filt]); +#endif + if (tns->order[w][filt]) { + tns->direction[w][filt] = faad_get1bit(ld); +#if 0 + printf("%d\n", tns->direction[w][filt]); +#endif + tns->coef_compress[w][filt] = faad_get1bit(ld); +#if 0 + printf("%d\n", tns->coef_compress[w][filt]); +#endif + coef_bits = start_coef_bits - tns->coef_compress[w][filt]; + for (i = 0; i < tns->order[w][filt]; i++) { + tns->coef[w][filt][i] = (uint8_t)faad_getbits(ld, coef_bits); +#if 0 + printf("%d\n", tns->coef[w][filt][i]); +#endif + } + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +/* Table 4.4.28 */ +uint8_t NeaacDecoder::ltp_data(NeAACDecStruct* hDecoder, ic_stream* ics, ltp_info* ltp, bitfile* ld) { + uint8_t sfb, w; + ltp->lag = 0; + #ifdef LD_DEC + if (hDecoder->object_type == LD) { + ltp->lag_update = (uint8_t)faad_getbits(ld, 1); + if (ltp->lag_update) { ltp->lag = (uint16_t)faad_getbits(ld, 10); } + } else { + #endif + ltp->lag = (uint16_t)faad_getbits(ld, 11); + #ifdef LD_DEC + } + #endif + /* Check length of lag */ + if (ltp->lag > (hDecoder->frameLength << 1)) return 18; + ltp->coef = (uint8_t)faad_getbits(ld, 3); + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) { + for (w = 0; w < ics->num_windows; w++) { + if ((ltp->short_used[w] = faad_get1bit(ld)) & 1) { + ltp->short_lag_present[w] = faad_get1bit(ld); + if (ltp->short_lag_present[w]) { ltp->short_lag[w] = (uint8_t)faad_getbits(ld, 4); } + } + } + } else { + ltp->last_band = (ics->max_sfb < MAX_LTP_SFB ? ics->max_sfb : MAX_LTP_SFB); + for (sfb = 0; sfb < ltp->last_band; sfb++) { ltp->long_used[sfb] = faad_get1bit(ld); } + } + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.29 */ +uint8_t NeaacDecoder::spectral_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, int16_t* spectral_data) { + int8_t i; + uint8_t g; + uint16_t inc, k, p = 0; + uint8_t groups = 0; + uint8_t sect_cb; + uint8_t result; + uint16_t nshort = hDecoder->frameLength / 8; +#ifdef PROFILE + int64_t count = faad_get_ts(); +#endif + for (g = 0; g < ics->num_window_groups; g++) { + p = groups * nshort; + for (i = 0; i < ics->num_sec[g]; i++) { + sect_cb = ics->sect_cb[g][i]; + inc = (sect_cb >= FIRST_PAIR_HCB) ? 2 : 4; + switch (sect_cb) { + case ZERO_HCB: + case NOISE_HCB: + case INTENSITY_HCB: + case INTENSITY_HCB2: +// #define SD_PRINT +#ifdef SD_PRINT + { + int j; + for (j = ics->sect_sfb_offset[g][ics->sect_start[g][i]]; j < ics->sect_sfb_offset[g][ics->sect_end[g][i]]; j++) { printf("%d\n", 0); } + } +#endif +// #define SFBO_PRINT +#ifdef SFBO_PRINT + printf("%d\n", ics->sect_sfb_offset[g][ics->sect_start[g][i]]); +#endif + p += (ics->sect_sfb_offset[g][ics->sect_end[g][i]] - ics->sect_sfb_offset[g][ics->sect_start[g][i]]); + break; + default: +#ifdef SFBO_PRINT + printf("%d\n", ics->sect_sfb_offset[g][ics->sect_start[g][i]]); +#endif + for (k = ics->sect_sfb_offset[g][ics->sect_start[g][i]]; k < ics->sect_sfb_offset[g][ics->sect_end[g][i]]; k += inc) { + if ((result = huffman_spectral_data(sect_cb, ld, &spectral_data[p])) > 0) return result; +#ifdef SD_PRINT + { + int j; + for (j = p; j < p + inc; j++) { printf("%d\n", spectral_data[j]); } + } +#endif + p += inc; + } + break; + } + } + groups += ics->window_group_length[g]; + } +#ifdef PROFILE + count = faad_get_ts() - count; + hDecoder->spectral_cycles += count; +#endif + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.30 */ +uint16_t NeaacDecoder::extension_payload(bitfile* ld, drc_info* drc, uint16_t count) { + uint16_t i, dri, dataElementLength; + uint8_t dataElementLengthPart; + uint8_t align = 4, data_element_version, loopCounter; + uint8_t extension_type = (uint8_t)faad_getbits(ld, 4); + switch (extension_type) { + case EXT_DYNAMIC_RANGE: + drc->present = 1; + dri = dynamic_range_info(ld, drc); + return dri; + case EXT_FILL_DATA: + /* fill_nibble = */ faad_getbits(ld, 4); /* must be '0000' */ + for (i = 0; i < count - 1; i++) { /* fill_byte[i] = */ + faad_getbits(ld, 8); /* must be '10100101' */ + } + return count; + break; + case EXT_DATA_ELEMENT: + data_element_version = (uint8_t)faad_getbits(ld, 4); + switch (data_element_version) { + case ANC_DATA: + loopCounter = 0; + dataElementLength = 0; + do { + dataElementLengthPart = (uint8_t)faad_getbits(ld, 8); + dataElementLength += dataElementLengthPart; + loopCounter++; + } while (dataElementLengthPart == 255); + for (i = 0; i < dataElementLength; i++) { + /* data_element_byte[i] = */ faad_getbits(ld, 8); + return (dataElementLength + loopCounter + 1); + } + /* fallthrough */ + default: align = 0; break; + } + /* fallthrough */ + case EXT_FIL: + /* fallthrough */ + default: + faad_getbits(ld, align); + for (i = 0; i < count - 1; i++) { /* other_bits[i] = */ + faad_getbits(ld, 8); + } + return count; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.31 */ +uint8_t NeaacDecoder::dynamic_range_info(bitfile* ld, drc_info* drc) { + uint8_t i, idx = 1; + uint8_t band_incr; + drc->num_bands = 1; + if (faad_get1bit(ld) & 1) { + drc->pce_instance_tag = (uint8_t)faad_getbits(ld, 4); + /* drc->drc_tag_reserved_bits = */ faad_getbits(ld, 4); + idx++; + } + drc->excluded_chns_present = faad_get1bit(ld); + if (drc->excluded_chns_present == 1) { idx += excluded_channels(ld, drc); } + if (faad_get1bit(ld)) { + band_incr = (uint8_t)faad_getbits(ld, 4); + /* drc->drc_bands_reserved_bits = */ faad_getbits(ld, 4); + idx++; + drc->num_bands += band_incr; + for (i = 0; i < drc->num_bands; i++) { + drc->band_top[i] = (uint8_t)faad_getbits(ld, 8); + idx++; + } + } + if (faad_get1bit(ld) & 1) { + drc->prog_ref_level = (uint8_t)faad_getbits(ld, 7); + /* drc->prog_ref_level_reserved_bits = */ faad_get1bit(ld); + idx++; + } + for (i = 0; i < drc->num_bands; i++) { + drc->dyn_rng_sgn[i] = faad_get1bit(ld); + drc->dyn_rng_ctl[i] = (uint8_t)faad_getbits(ld, 7); + idx++; + } + return idx; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 4.4.32 */ +uint8_t NeaacDecoder::excluded_channels(bitfile* ld, drc_info* drc) { + uint8_t i, idx = 0; + uint8_t num_excl_chan = 7; + for (i = 0; i < 7; i++) { drc->exclude_mask[i] = faad_get1bit(ld); } + idx++; + while ((drc->additional_excluded_chns[idx - 1] = faad_get1bit(ld)) == 1) { + if (i >= MAX_CHANNELS - num_excl_chan - 7) return idx; + for (i = num_excl_chan; i < num_excl_chan + 7; i++) { drc->exclude_mask[i] = faad_get1bit(ld); } + idx++; + num_excl_chan += 7; + } + return idx; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Annex A: Audio Interchange Formats */ +/* Table 1.A.2 */ +void NeaacDecoder::get_adif_header(adif_header* adif, bitfile* ld) { + uint8_t i; + /* adif_id[0] = */ faad_getbits(ld, 8); + /* adif_id[1] = */ faad_getbits(ld, 8); + /* adif_id[2] = */ faad_getbits(ld, 8); + /* adif_id[3] = */ faad_getbits(ld, 8); + adif->copyright_id_present = faad_get1bit(ld); + if (adif->copyright_id_present) { + for (i = 0; i < 72 / 8; i++) { adif->copyright_id[i] = (int8_t)faad_getbits(ld, 8); } + adif->copyright_id[i] = 0; + } + adif->original_copy = faad_get1bit(ld); + adif->home = faad_get1bit(ld); + adif->bitstream_type = faad_get1bit(ld); + adif->bitrate = faad_getbits(ld, 23); + adif->num_program_config_elements = (uint8_t)faad_getbits(ld, 4); + for (i = 0; i < adif->num_program_config_elements + 1; i++) { + if (adif->bitstream_type == 0) { + adif->adif_buffer_fullness = faad_getbits(ld, 20); + } else { + adif->adif_buffer_fullness = 0; + } + program_config_element(&adif->pce[i], ld); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.A.5 */ +uint8_t NeaacDecoder::adts_frame(adts_header* adts, bitfile* ld) { + /* faad_byte_align(ld); */ + uint8_t ret = adts_fixed_header(adts, ld); + if (ret) return ret; + adts_variable_header(adts, ld); + adts_error_check(adts, ld); + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.A.6 */ +uint8_t NeaacDecoder::adts_fixed_header(adts_header* adts, bitfile* ld) { + uint16_t i; + uint8_t id3[3] = {0}; + uint8_t sync_err = 1; + /* try to recover from sync errors */ + for (i = 0; i < 768; i++) { + adts->syncword = (uint16_t)faad_showbits(ld, 12); + + if (adts->syncword != 0xFFF) { + if (i < 3) id3[i] = (uint8_t)faad_showbits(ld, 8); + if (i == 3) { + if (id3[0] == 73 && id3[1] == 68 && id3[2] == 51) { return 100; } // ID3 header found + } + faad_getbits(ld, 8); + } else { + sync_err = 0; + faad_getbits(ld, 12); + break; + } + } + if (sync_err) return 5; + adts->id = faad_get1bit(ld); + adts->layer = (uint8_t)faad_getbits(ld, 2); + adts->protection_absent = faad_get1bit(ld); + adts->profile = (uint8_t)faad_getbits(ld, 2); + adts->sf_index = (uint8_t)faad_getbits(ld, 4); + adts->private_bit = faad_get1bit(ld); + adts->channel_configuration = (uint8_t)faad_getbits(ld, 3); + adts->original = faad_get1bit(ld); + adts->home = faad_get1bit(ld); + if (adts->old_format == 1) { + /* Removed in corrigendum 14496-3:2002 */ + if (adts->id == 0) { adts->emphasis = (uint8_t)faad_getbits(ld, 2); } + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.A.7 */ +void NeaacDecoder::adts_variable_header(adts_header* adts, bitfile* ld) { + adts->copyright_identification_bit = faad_get1bit(ld); + adts->copyright_identification_start = faad_get1bit(ld); + adts->aac_frame_length = (uint16_t)faad_getbits(ld, 13); + adts->adts_buffer_fullness = (uint16_t)faad_getbits(ld, 11); + adts->no_raw_data_blocks_in_frame = (uint8_t)faad_getbits(ld, 2); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.A.8 */ +void NeaacDecoder::adts_error_check(adts_header* adts, bitfile* ld) { + if (adts->protection_absent == 0) { adts->crc_check = (uint16_t)faad_getbits(ld, 16); } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* LATM parsing functions */ +uint32_t NeaacDecoder::latm_get_value(bitfile* ld) { + uint32_t l, value; + uint8_t bytesForValue; + bytesForValue = (uint8_t)faad_getbits(ld, 2); + value = 0; + for (l = 0; l < bytesForValue; l++) value = (value << 8) | (uint8_t)faad_getbits(ld, 8); + return value; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::latmParsePayload(latm_header* latm, bitfile* ld) { + // assuming there's only one program with a single layer and 1 subFrame, + // allStreamsSametimeframing is set, + uint32_t framelen; + uint8_t tmp; + // this should be the payload length field for the current configuration + framelen = 0; + if (latm->framelen_type == 0) { + do { + tmp = (uint8_t)faad_getbits(ld, 8); + framelen += tmp; + } while (tmp == 0xff); + } else if (latm->framelen_type == 1) + framelen = latm->frameLength; + return framelen; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::latmAudioMuxElement(latm_header* latm, bitfile* ld) { + uint32_t ascLen, asc_bits = 0; + uint32_t x1, y1, m, n, i; + program_config pce; + mp4AudioSpecificConfig mp4ASC; + latm->useSameStreamMux = (uint8_t)faad_getbits(ld, 1); + if (!latm->useSameStreamMux) { + // parseSameStreamMuxConfig + latm->version = (uint8_t)faad_getbits(ld, 1); + if (latm->version) latm->versionA = (uint8_t)faad_getbits(ld, 1); + if (latm->versionA) { + // dunno the payload format for versionA + fprintf(stderr, "versionA not supported\n"); + return 0; + } + if (latm->version) // read taraBufferFullness + latm_get_value(ld); + latm->allStreamsSameTimeFraming = (uint8_t)faad_getbits(ld, 1); + latm->numSubFrames = (uint8_t)faad_getbits(ld, 6) + 1; + latm->numPrograms = (uint8_t)faad_getbits(ld, 4) + 1; + latm->numLayers = faad_getbits(ld, 3) + 1; + if (latm->numPrograms > 1 || !latm->allStreamsSameTimeFraming || latm->numSubFrames > 1 || latm->numLayers > 1) { + fprintf(stderr, "\r\nUnsupported LATM configuration: %d programs/ %d subframes, %d layers, allstreams: %d\n", latm->numPrograms, latm->numSubFrames, latm->numLayers, + latm->allStreamsSameTimeFraming); + return 0; + } + ascLen = 0; + if (latm->version) ascLen = latm_get_value(ld); + x1 = faad_get_processed_bits(ld); + if (AudioSpecificConfigFromBitfile(ld, &mp4ASC, &pce, 0, 1) < 0) return 0; + // horrid hack to unread the ASC bits and store them in latm->ASC + // the correct code would rely on an ideal faad_ungetbits() + y1 = faad_get_processed_bits(ld); + if ((y1 - x1) <= MAX_ASC_BYTES * 8) { + faad_rewindbits(ld); + m = x1; + while (m > 0) { + n = min(m, (uint32_t)32); + faad_getbits(ld, n); + m -= n; + } + i = 0; + m = latm->ASCbits = y1 - x1; + while (m > 0) { + n = min(m, (uint32_t)8); + latm->ASC[i++] = (uint8_t)faad_getbits(ld, n); + m -= n; + } + } + asc_bits = y1 - x1; + if (ascLen > asc_bits) faad_getbits(ld, ascLen - asc_bits); + latm->framelen_type = (uint8_t)faad_getbits(ld, 3); + if (latm->framelen_type == 0) { + latm->frameLength = 0; + faad_getbits(ld, 8); // buffer fullness for frame_len_type==0, useless + } else if (latm->framelen_type == 1) { + latm->frameLength = faad_getbits(ld, 9); + if (latm->frameLength == 0) { + fprintf(stderr, "Invalid frameLength: 0\r\n"); + return 0; + } + latm->frameLength = (latm->frameLength + 20) * 8; + } else { // hellish CELP or HCVX stuff, discard + fprintf(stderr, "Unsupported CELP/HCVX framelentype: %d\n", latm->framelen_type); + return 0; + } + latm->otherDataLenBits = 0; + if (faad_getbits(ld, 1)) { // other data present + int esc, tmp; + if (latm->version) + latm->otherDataLenBits = latm_get_value(ld); + else + do { + esc = faad_getbits(ld, 1); + tmp = faad_getbits(ld, 8); + latm->otherDataLenBits = (latm->otherDataLenBits << 8) + tmp; + } while (esc); + } + if (faad_getbits(ld, 1)) // crc + faad_getbits(ld, 8); + latm->inited = 1; + } + // read payload + if (latm->inited) + return latmParsePayload(latm, ld); + else + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t NeaacDecoder::faad_latm_frame(latm_header* latm, bitfile* ld) { + uint16_t len; + uint32_t initpos, endpos, firstpos, ret; + (void)firstpos; + firstpos = faad_get_processed_bits(ld); + while (ld->bytes_left) { + faad_byte_align(ld); + if (faad_showbits(ld, 11) != 0x2B7) { + faad_getbits(ld, 8); + continue; + } + faad_getbits(ld, 11); + len = faad_getbits(ld, 13); + if (!len) continue; + initpos = faad_get_processed_bits(ld); + ret = latmAudioMuxElement(latm, ld); + endpos = faad_get_processed_bits(ld); + if (ret > 0) return (len * 8) - (endpos - initpos); + // faad_getbits(ld, initpos-endpos); //go back to initpos, but is valid a getbits(-N) ? + } + return 0xFFFFFFFF; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +uint8_t NeaacDecoder::rvlc_scale_factor_data(ic_stream* ics, bitfile* ld) { + uint8_t bits = 9; + ics->sf_concealment = faad_get1bit(ld); + ics->rev_global_gain = (uint8_t)faad_getbits(ld, 8); + if (ics->window_sequence == EIGHT_SHORT_SEQUENCE) bits = 11; + /* the number of bits used for the huffman codewords */ + ics->length_of_rvlc_sf = (uint16_t)faad_getbits(ld, bits); + if (ics->noise_used) { + ics->dpcm_noise_nrg = (uint16_t)faad_getbits(ld, 9); + + /* the 9 bits of dpcm_noise_nrg are counted in length_of_rvlc_sf, so a conformant value is at least 9; reject a smaller one before the + unsigned subtraction wraps length_of_rvlc_sf to a huge value */ + if (ics->length_of_rvlc_sf < 9) return 8; + + ics->length_of_rvlc_sf -= 9; + } + ics->sf_escapes_present = faad_get1bit(ld); + if (ics->sf_escapes_present) { ics->length_of_rvlc_escapes = (uint8_t)faad_getbits(ld, 8); } + if (ics->noise_used) { ics->dpcm_noise_last_position = (uint16_t)faad_getbits(ld, 9); } + return 0; +} +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +uint8_t NeaacDecoder::rvlc_decode_scale_factors(ic_stream* ics, bitfile* ld) { + + uint8_t result; + uint8_t intensity_used = 0; + uint8_t* rvlc_sf_buffer = NULL; + uint8_t* rvlc_esc_buffer = NULL; + bitfile ld_rvlc_sf, ld_rvlc_esc; + // bitfile ld_rvlc_sf_rev, ld_rvlc_esc_rev; + if (ics->length_of_rvlc_sf > 0) { + /* We read length_of_rvlc_sf bits here to put it in a seperate bitfile. */ + rvlc_sf_buffer = faad_getbitbuffer(ld, ics->length_of_rvlc_sf); + faad_initbits(&ld_rvlc_sf, (void*)rvlc_sf_buffer, bit2byte(ics->length_of_rvlc_sf)); + // faad_initbits_rev(&ld_rvlc_sf_rev, (void*)rvlc_sf_buffer, + // ics->length_of_rvlc_sf); + } + if (ics->sf_escapes_present) { + /* We read length_of_rvlc_escapes bits here to put it in a seperate bitfile. */ + rvlc_esc_buffer = faad_getbitbuffer(ld, ics->length_of_rvlc_escapes); + faad_initbits(&ld_rvlc_esc, (void*)rvlc_esc_buffer, bit2byte(ics->length_of_rvlc_escapes)); + // faad_initbits_rev(&ld_rvlc_esc_rev, (void*)rvlc_esc_buffer, + // ics->length_of_rvlc_escapes); + } + /* decode the rvlc scale factors and escapes */ + result = rvlc_decode_sf_forward(ics, &ld_rvlc_sf, &ld_rvlc_esc, &intensity_used); + // result = rvlc_decode_sf_reverse(ics, &ld_rvlc_sf_rev, + // &ld_rvlc_esc_rev, intensity_used); + if (rvlc_esc_buffer) faad_free(&rvlc_esc_buffer); + if (rvlc_sf_buffer) faad_free(&rvlc_sf_buffer); + if (ics->length_of_rvlc_sf > 0) faad_endbits(&ld_rvlc_sf); + if (ics->sf_escapes_present) faad_endbits(&ld_rvlc_esc); + return result; +} +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +uint8_t NeaacDecoder::rvlc_decode_sf_forward(ic_stream* ics, bitfile* ld_sf, bitfile* ld_esc, uint8_t* intensity_used) { + int8_t g, sfb; + int8_t t = 0; + int8_t error = 0; + int8_t noise_pcm_flag = 1; + int16_t scale_factor = ics->global_gain; + int16_t is_position = 0; + int16_t noise_energy = ics->global_gain - 90 - 256; + #ifdef PRINT_RVLC + printf("\nglobal_gain: %d\n", ics->global_gain); + #endif + for (g = 0; g < ics->num_window_groups; g++) { + for (sfb = 0; sfb < ics->max_sfb; sfb++) { + if (error) { + ics->scale_factors[g][sfb] = 0; + } else { + switch (ics->sfb_cb[g][sfb]) { + case ZERO_HCB: /* zero book */ ics->scale_factors[g][sfb] = 0; break; + case INTENSITY_HCB: /* intensity books */ + case INTENSITY_HCB2: + *intensity_used = 1; + /* decode intensity position */ + t = rvlc_huffman_sf(ld_sf, ld_esc, +1); + is_position += t; + ics->scale_factors[g][sfb] = is_position; + break; + case NOISE_HCB: /* noise books */ + /* decode noise energy */ + if (noise_pcm_flag) { + int16_t n = ics->dpcm_noise_nrg; + noise_pcm_flag = 0; + noise_energy += n; + } else { + t = rvlc_huffman_sf(ld_sf, ld_esc, +1); + noise_energy += t; + } + ics->scale_factors[g][sfb] = noise_energy; + break; + default: /* spectral books */ + /* decode scale factor */ + t = rvlc_huffman_sf(ld_sf, ld_esc, +1); + scale_factor += t; + if (scale_factor < 0) return 4; + ics->scale_factors[g][sfb] = scale_factor; + break; + } + #ifdef PRINT_RVLC + printf("%3d:%4d%4d\n", sfb, ics->sfb_cb[g][sfb], ics->scale_factors[g][sfb]); + #endif + if (t == 99) { error = 1; } + } + } + } + #ifdef PRINT_RVLC + printf("\n\n"); + #endif + return 0; +} +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE + #if 0 // not used right now, doesn't work correctly yet +uint8_t NeaacDecoder::rvlc_decode_sf_reverse(ic_stream *ics, bitfile *ld_sf, bitfile *ld_esc, uint8_t intensity_used){ + int8_t g, sfb; + int8_t t = 0; + int8_t error = 0; + int8_t noise_pcm_flag = 1, is_pcm_flag = 1, sf_pcm_flag = 1; + int16_t scale_factor = ics->rev_global_gain; + int16_t is_position = 0; + int16_t noise_energy = ics->rev_global_gain; + #ifdef PRINT_RVLC + printf("\nrev_global_gain: %d\n", ics->rev_global_gain); + #endif + if (intensity_used) + { + is_position = rvlc_huffman_sf(ld_sf, ld_esc, -1); + #ifdef PRINT_RVLC + printf("is_position: %d\n", is_position); + #endif + } + for (g = ics->num_window_groups-1; g >= 0; g--) + { + for (sfb = ics->max_sfb-1; sfb >= 0; sfb--) + { + if (error) + { + ics->scale_factors[g][sfb] = 0; + } else { + switch (ics->sfb_cb[g][sfb]) + { + case ZERO_HCB: /* zero book */ + ics->scale_factors[g][sfb] = 0; + break; + case INTENSITY_HCB: /* intensity books */ + case INTENSITY_HCB2: + if (is_pcm_flag) + { + is_pcm_flag = 0; + ics->scale_factors[g][sfb] = is_position; + } else { + t = rvlc_huffman_sf(ld_sf, ld_esc, -1); + is_position -= t; + ics->scale_factors[g][sfb] = (uint8_t)is_position; + } + break; + case NOISE_HCB: /* noise books */ + /* decode noise energy */ + if (noise_pcm_flag) + { + noise_pcm_flag = 0; + noise_energy = ics->dpcm_noise_last_position; + } else { + t = rvlc_huffman_sf(ld_sf, ld_esc, -1); + noise_energy -= t; + } + ics->scale_factors[g][sfb] = (uint8_t)noise_energy; + break; + default: /* spectral books */ + if (sf_pcm_flag || (sfb == 0)) + { + sf_pcm_flag = 0; + if (sfb == 0) + scale_factor = ics->global_gain; + } else { + /* decode scale factor */ + t = rvlc_huffman_sf(ld_sf, ld_esc, -1); + scale_factor -= t; + } + if (scale_factor < 0) + return 4; + ics->scale_factors[g][sfb] = (uint8_t)scale_factor; + break; + } + #ifdef PRINT_RVLC + printf("%3d:%4d%4d\n", sfb, ics->sfb_cb[g][sfb], + ics->scale_factors[g][sfb]); + #endif + if (t == 99) + { + error = 1; + } + } + } + } + #ifdef PRINT_RVLC + printf("\n\n"); + #endif + return 0; +} + #endif // 0 +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +int8_t NeaacDecoder::rvlc_huffman_sf(bitfile* ld_sf, bitfile* ld_esc, int8_t direction) { + uint8_t i, j; + int8_t index; + uint32_t cw; + rvlc_huff_table* h = book_rvlc; + i = h->len; + if (direction > 0) + cw = faad_getbits(ld_sf, i); + else + cw = faad_getbits_rev(ld_sf, i); + while ((cw != h->cw) && (i < 10)) { + h++; + j = h->len - i; + i += j; + cw <<= j; + if (direction > 0) + cw |= faad_getbits(ld_sf, j); + else + cw |= faad_getbits_rev(ld_sf, j); + } + index = h->index; + if (index == +ESC_VAL) { + int8_t esc = rvlc_huffman_esc(ld_esc, direction); + if (esc == 99) return 99; + index += esc; + #ifdef PRINT_RVLC + printf("esc: %d - ", esc); + #endif + } + if (index == -ESC_VAL) { + int8_t esc = rvlc_huffman_esc(ld_esc, direction); + if (esc == 99) return 99; + index -= esc; + #ifdef PRINT_RVLC + printf("esc: %d - ", esc); + #endif + } + return index; +} +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef ERROR_RESILIENCE +int8_t NeaacDecoder::rvlc_huffman_esc(bitfile* ld, int8_t direction) { + uint8_t i, j; + uint32_t cw; + rvlc_huff_table* h = book_escape; + i = h->len; + if (direction > 0) + cw = faad_getbits(ld, i); + else + cw = faad_getbits_rev(ld, i); + while ((cw != h->cw) && (i < 21)) { + h++; + j = h->len - i; + i += j; + cw <<= j; + if (direction > 0) + cw |= faad_getbits(ld, j); + else + cw |= faad_getbits_rev(ld, j); + } + return h->index; +} +#endif // ERROR_RESILIENCE +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::ssr_decode(ssr_info* ssr, fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, real_t* overlap, + real_t ipqf_buffer[SSR_BANDS][96 / 4], real_t* prev_fmd, uint16_t frame_len) { + uint8_t band; + uint16_t ssr_frame_len = frame_len / SSR_BANDS; + real_t time_tmp[2048] = {0}; + real_t output[1024] = {0}; + for (band = 0; band < SSR_BANDS; band++) { + int16_t j; + /* uneven bands have inverted frequency scale */ + if (band == 1 || band == 3) { + for (j = 0; j < ssr_frame_len / 2; j++) { + real_t tmp; + tmp = freq_in[j + ssr_frame_len * band]; + freq_in[j + ssr_frame_len * band] = freq_in[ssr_frame_len - j - 1 + ssr_frame_len * band]; + freq_in[ssr_frame_len - j - 1 + ssr_frame_len * band] = tmp; + } + } + /* non-overlapping inverse filterbank for SSR */ + ssr_ifilter_bank(fb, window_sequence, window_shape, window_shape_prev, freq_in + band * ssr_frame_len, time_tmp + band * ssr_frame_len, ssr_frame_len); + /* gain control */ + ssr_gain_control(ssr, time_tmp, output, overlap, prev_fmd, band, window_sequence, ssr_frame_len); + } + /* inverse pqf to bring subbands together again */ + ssr_ipqf(ssr, output, time_out, ipqf_buffer, frame_len, SSR_BANDS); +} +#endif // SSR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::ssr_gain_control(ssr_info* ssr, real_t* data, real_t* output, real_t* overlap, real_t* prev_fmd, uint8_t band, uint8_t window_sequence, uint16_t frame_len) { + uint16_t i; + real_t gc_function[2 * 1024 / SSR_BANDS]; + if (window_sequence != EIGHT_SHORT_SEQUENCE) { + ssr_gc_function(ssr, &prev_fmd[band * frame_len * 2], gc_function, window_sequence, frame_len); + for (i = 0; i < frame_len * 2; i++) data[band * frame_len * 2 + i] *= gc_function[i]; + for (i = 0; i < frame_len; i++) { output[band * frame_len + i] = overlap[band * frame_len + i] + data[band * frame_len * 2 + i]; } + for (i = 0; i < frame_len; i++) { overlap[band * frame_len + i] = data[band * frame_len * 2 + frame_len + i]; } + } else { + uint8_t w; + for (w = 0; w < 8; w++) { + uint16_t frame_len8 = frame_len / 8; + uint16_t frame_len16 = frame_len / 16; + ssr_gc_function(ssr, &prev_fmd[band * frame_len * 2 + w * frame_len * 2 / 8], gc_function, window_sequence, frame_len); + for (i = 0; i < frame_len8 * 2; i++) data[band * frame_len * 2 + w * frame_len8 * 2 + i] *= gc_function[i]; + for (i = 0; i < frame_len8; i++) { overlap[band * frame_len + i + 7 * frame_len16 + w * frame_len8] += data[band * frame_len * 2 + 2 * w * frame_len8 + i]; } + for (i = 0; i < frame_len8; i++) { overlap[band * frame_len + i + 7 * frame_len16 + (w + 1) * frame_len8] = data[band * frame_len * 2 + 2 * w * frame_len8 + frame_len8 + i]; } + } + for (i = 0; i < frame_len; i++) output[band * frame_len + i] = overlap[band * frame_len + i]; + for (i = 0; i < frame_len; i++) overlap[band * frame_len + i] = overlap[band * frame_len + i + frame_len]; + } +} +#endif // SSR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::ssr_gc_function(ssr_info* ssr, real_t* prev_fmd, real_t* gc_function, uint8_t window_sequence, uint16_t frame_len) { + uint16_t i; + uint16_t len_area1, len_area2; + (void)len_area1; + (void)len_area2; + int32_t aloc[10]; + (void)aloc; + real_t alev[10]; + (void)alev; + switch (window_sequence) { + case ONLY_LONG_SEQUENCE: + len_area1 = frame_len / SSR_BANDS; + len_area2 = 0; + break; + case LONG_START_SEQUENCE: + len_area1 = (frame_len / SSR_BANDS) * 7 / 32; + len_area2 = (frame_len / SSR_BANDS) / 16; + break; + case EIGHT_SHORT_SEQUENCE: + len_area1 = (frame_len / 8) / SSR_BANDS; + len_area2 = 0; + break; + case LONG_STOP_SEQUENCE: + len_area1 = (frame_len / SSR_BANDS); + len_area2 = 0; + break; + } + /* decode bitstream information */ + /* build array M */ + for (i = 0; i < frame_len * 2; i++) gc_function[i] = 1; +} +#endif // SSR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t NeaacDecoder::pulse_decode(ic_stream* ics, int16_t* spec_data, uint16_t framelen) { + uint8_t i; + uint16_t k; + pulse_info* pul = &(ics->pul); + k = min(ics->swb_offset[pul->pulse_start_sfb], ics->swb_offset_max); + for (i = 0; i <= pul->number_pulse; i++) { + k += pul->pulse_offset[i]; + if (k >= framelen) return 15; /* should not be possible */ + if (spec_data[k] > 0) + spec_data[k] += pul->pulse_amp[i]; + else + spec_data[k] -= pul->pulse_amp[i]; + } + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Table 1.6.1 */ +char NeaacDecoder::NeAACDecAudioSpecificConfig(uint8_t* pBuffer, uint32_t buffer_size, mp4AudioSpecificConfig* mp4ASC) { + return AudioSpecificConfig2(pBuffer, buffer_size, mp4ASC, NULL, 0); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t NeaacDecoder::AudioSpecificConfigFromBitfile(bitfile* ld, mp4AudioSpecificConfig* mp4ASC, program_config* pce, uint32_t buffer_size, uint8_t short_form) { + int8_t result = 0; + uint32_t startpos = faad_get_processed_bits(ld); +#ifdef SBR_DEC + int8_t bits_to_decode = 0; +#endif + if (mp4ASC == NULL) return -8; + memset(mp4ASC, 0, sizeof(mp4AudioSpecificConfig)); + mp4ASC->objectTypeIndex = (uint8_t)faad_getbits(ld, 5); + mp4ASC->samplingFrequencyIndex = (uint8_t)faad_getbits(ld, 4); + if (mp4ASC->samplingFrequencyIndex == 0x0f) faad_getbits(ld, 24); + mp4ASC->channelsConfiguration = (uint8_t)faad_getbits(ld, 4); + mp4ASC->samplingFrequency = get_sample_rate(mp4ASC->samplingFrequencyIndex); + if (ObjectTypesTable[mp4ASC->objectTypeIndex] != 1) { return -1; } + if (mp4ASC->samplingFrequency == 0) { return -2; } + if (mp4ASC->channelsConfiguration > 7) { return -3; } +#if (defined(PS_DEC) || defined(DRM_PS)) + /* check if we have a mono file */ + if (mp4ASC->channelsConfiguration == 1) { + /* upMatrix to 2 channels for implicit signalling of PS */ + mp4ASC->channelsConfiguration = 2; + } +#endif +#ifdef SBR_DEC + mp4ASC->sbr_present_flag = -1; + if (mp4ASC->objectTypeIndex == 5 || mp4ASC->objectTypeIndex == 29) { + uint8_t tmp; + mp4ASC->sbr_present_flag = 1; + tmp = (uint8_t)faad_getbits(ld, 4); + /* check for downsampled SBR */ + if (tmp == mp4ASC->samplingFrequencyIndex) mp4ASC->downSampledSBR = 1; + mp4ASC->samplingFrequencyIndex = tmp; + if (mp4ASC->samplingFrequencyIndex == 15) { + mp4ASC->samplingFrequency = (uint32_t)faad_getbits(ld, 24); + } else { + mp4ASC->samplingFrequency = get_sample_rate(mp4ASC->samplingFrequencyIndex); + } + mp4ASC->objectTypeIndex = (uint8_t)faad_getbits(ld, 5); + } +#endif + /* get GASpecificConfig */ + if (mp4ASC->objectTypeIndex == 1 || mp4ASC->objectTypeIndex == 2 || mp4ASC->objectTypeIndex == 3 || mp4ASC->objectTypeIndex == 4 || mp4ASC->objectTypeIndex == 6 || mp4ASC->objectTypeIndex == 7) { + result = GASpecificConfig(ld, mp4ASC, pce); +#ifdef ERROR_RESILIENCE + } else if (mp4ASC->objectTypeIndex >= ER_OBJECT_START) { /* ER */ + result = GASpecificConfig(ld, mp4ASC, pce); + mp4ASC->epConfig = (uint8_t)faad_getbits(ld, 2); + if (mp4ASC->epConfig != 0) result = -5; +#endif + } else { + result = -4; + } +#ifdef SSR_DEC + /* shorter frames not allowed for SSR */ + if ((mp4ASC->objectTypeIndex == 4) && mp4ASC->frameLengthFlag) return -6; +#endif +#ifdef SBR_DEC + if (short_form) + bits_to_decode = 0; + else + bits_to_decode = (int8_t)(buffer_size * 8 - (startpos - faad_get_processed_bits(ld))); + if ((mp4ASC->objectTypeIndex != 5 && mp4ASC->objectTypeIndex != 29) && (bits_to_decode >= 16)) { + int16_t syncExtensionType = (int16_t)faad_getbits(ld, 11); + if (syncExtensionType == 0x2b7) { + uint8_t tmp_OTi = (uint8_t)faad_getbits(ld, 5); + if (tmp_OTi == 5) { + mp4ASC->sbr_present_flag = (uint8_t)faad_get1bit(ld); + if (mp4ASC->sbr_present_flag) { + uint8_t tmp; + /* Don't set OT to SBR until checked that it is actually there */ + mp4ASC->objectTypeIndex = tmp_OTi; + tmp = (uint8_t)faad_getbits(ld, 4); + /* check for downsampled SBR */ + if (tmp == mp4ASC->samplingFrequencyIndex) mp4ASC->downSampledSBR = 1; + mp4ASC->samplingFrequencyIndex = tmp; + if (mp4ASC->samplingFrequencyIndex == 15) { + mp4ASC->samplingFrequency = (uint32_t)faad_getbits(ld, 24); + } else { + mp4ASC->samplingFrequency = get_sample_rate(mp4ASC->samplingFrequencyIndex); + } + } + } + } + } + /* no SBR signalled, this could mean either implicit signalling or no SBR in this file */ + /* MPEG specification states: assume SBR on files with samplerate <= 24000 Hz */ + if (mp4ASC->sbr_present_flag == (char)-1) /* cannot be -1 on systems with uint8_t */ + { + if (mp4ASC->samplingFrequency <= 24000) { + mp4ASC->samplingFrequency *= 2; + mp4ASC->forceUpSampling = 1; + } else /* > 24000*/ { + mp4ASC->downSampledSBR = 1; + } + } +#endif + faad_endbits(ld); + return result; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t NeaacDecoder::AudioSpecificConfig2(uint8_t* pBuffer, uint32_t buffer_size, mp4AudioSpecificConfig* mp4ASC, program_config* pce, uint8_t short_form) { + uint8_t ret = 0; + bitfile ld; + faad_initbits(&ld, pBuffer, buffer_size); + faad_byte_align(&ld); + ret = AudioSpecificConfigFromBitfile(&ld, mp4ASC, pce, buffer_size, short_form); + faad_endbits(&ld); + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +fb_info* NeaacDecoder::ssr_filter_bank_init(uint16_t frame_len) { + uint16_t nshort = frame_len / 8; + fb_info* fb = (fb_info*)faad_malloc(sizeof(fb_info)); + memset(fb, 0, sizeof(fb_info)); + /* normal */ + faad_mdct_init(256, 2 * nshort); + faad_mdct_init(2048, 2 * frame_len); + fb->long_window[0] = sine_long_256; + fb->short_window[0] = sine_short_32; + fb->long_window[1] = kbd_long_256; + fb->short_window[1] = kbd_short_32; + return fb; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::ssr_filter_bank_end(fb_info* fb) { + faad_mdct_end(256); + faad_mdct_end(2048); + if (fb) faad_free(&fb); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::imdct_ssr(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len) { + int16_t mdct_select = 0; + switch (len) { + case 512: mdct_select = 2048; break; + case 64: mdct_select = 256; break; + } + faad_imdct(mdct_select, in_data, out_data); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +/* NON-overlapping inverse filterbank for use with SSR */ +void NeaacDecoder::ssr_ifilter_bank(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, uint16_t frame_len) { + #define MUL_R_C(A, B) ((A) * (B)) + int16_t i; + real_t* transf_buf; + real_t* window_long; + real_t* window_long_prev; + real_t* window_short; + real_t* window_short_prev; + uint16_t nlong = frame_len; + uint16_t nshort = frame_len / 8; + uint16_t trans = nshort / 2; + (void)trans; + uint16_t nflat_ls = (nlong - nshort) / 2; + transf_buf = (real_t*)faad_malloc(2 * nlong * sizeof(real_t)); + window_long = (real_t*)fb->long_window[window_shape]; + window_long_prev = (real_t*)fb->long_window[window_shape_prev]; + window_short = (real_t*)fb->short_window[window_shape]; + window_short_prev = (real_t*)fb->short_window[window_shape_prev]; + switch (window_sequence) { + case ONLY_LONG_SEQUENCE: + imdct_ssr(fb, freq_in, transf_buf, 2 * nlong); + for (i = nlong - 1; i >= 0; i--) { + time_out[i] = MUL_R_C(transf_buf[i], window_long_prev[i]); + time_out[nlong + i] = MUL_R_C(transf_buf[nlong + i], window_long[nlong - 1 - i]); + } + break; + case LONG_START_SEQUENCE: + imdct_ssr(fb, freq_in, transf_buf, 2 * nlong); + for (i = 0; i < nlong; i++) time_out[i] = MUL_R_C(transf_buf[i], window_long_prev[i]); + for (i = 0; i < nflat_ls; i++) time_out[nlong + i] = transf_buf[nlong + i]; + for (i = 0; i < nshort; i++) time_out[nlong + nflat_ls + i] = MUL_R_C(transf_buf[nlong + nflat_ls + i], window_short[nshort - i - 1]); + for (i = 0; i < nflat_ls; i++) time_out[nlong + nflat_ls + nshort + i] = 0; + break; + case EIGHT_SHORT_SEQUENCE: + imdct_ssr(fb, freq_in + 0 * nshort, transf_buf + 2 * nshort * 0, 2 * nshort); + imdct_ssr(fb, freq_in + 1 * nshort, transf_buf + 2 * nshort * 1, 2 * nshort); + imdct_ssr(fb, freq_in + 2 * nshort, transf_buf + 2 * nshort * 2, 2 * nshort); + imdct_ssr(fb, freq_in + 3 * nshort, transf_buf + 2 * nshort * 3, 2 * nshort); + imdct_ssr(fb, freq_in + 4 * nshort, transf_buf + 2 * nshort * 4, 2 * nshort); + imdct_ssr(fb, freq_in + 5 * nshort, transf_buf + 2 * nshort * 5, 2 * nshort); + imdct_ssr(fb, freq_in + 6 * nshort, transf_buf + 2 * nshort * 6, 2 * nshort); + imdct_ssr(fb, freq_in + 7 * nshort, transf_buf + 2 * nshort * 7, 2 * nshort); + for (i = nshort - 1; i >= 0; i--) { + time_out[i + 0 * nshort] = MUL_R_C(transf_buf[nshort * 0 + i], window_short_prev[i]); + time_out[i + 1 * nshort] = MUL_R_C(transf_buf[nshort * 1 + i], window_short[i]); + time_out[i + 2 * nshort] = MUL_R_C(transf_buf[nshort * 2 + i], window_short_prev[i]); + time_out[i + 3 * nshort] = MUL_R_C(transf_buf[nshort * 3 + i], window_short[i]); + time_out[i + 4 * nshort] = MUL_R_C(transf_buf[nshort * 4 + i], window_short_prev[i]); + time_out[i + 5 * nshort] = MUL_R_C(transf_buf[nshort * 5 + i], window_short[i]); + time_out[i + 6 * nshort] = MUL_R_C(transf_buf[nshort * 6 + i], window_short_prev[i]); + time_out[i + 7 * nshort] = MUL_R_C(transf_buf[nshort * 7 + i], window_short[i]); + time_out[i + 8 * nshort] = MUL_R_C(transf_buf[nshort * 8 + i], window_short_prev[i]); + time_out[i + 9 * nshort] = MUL_R_C(transf_buf[nshort * 9 + i], window_short[i]); + time_out[i + 10 * nshort] = MUL_R_C(transf_buf[nshort * 10 + i], window_short_prev[i]); + time_out[i + 11 * nshort] = MUL_R_C(transf_buf[nshort * 11 + i], window_short[i]); + time_out[i + 12 * nshort] = MUL_R_C(transf_buf[nshort * 12 + i], window_short_prev[i]); + time_out[i + 13 * nshort] = MUL_R_C(transf_buf[nshort * 13 + i], window_short[i]); + time_out[i + 14 * nshort] = MUL_R_C(transf_buf[nshort * 14 + i], window_short_prev[i]); + time_out[i + 15 * nshort] = MUL_R_C(transf_buf[nshort * 15 + i], window_short[i]); + } + break; + case LONG_STOP_SEQUENCE: + imdct_ssr(fb, freq_in, transf_buf, 2 * nlong); + for (i = 0; i < nflat_ls; i++) time_out[i] = 0; + for (i = 0; i < nshort; i++) time_out[nflat_ls + i] = MUL_R_C(transf_buf[nflat_ls + i], window_short_prev[i]); + for (i = 0; i < nflat_ls; i++) time_out[nflat_ls + nshort + i] = transf_buf[nflat_ls + nshort + i]; + for (i = 0; i < nlong; i++) time_out[nlong + i] = MUL_R_C(transf_buf[nlong + i], window_long[nlong - 1 - i]); + break; + } + faad_free(&transf_buf); +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +/* check if the object type is an object type that can have LTP */ +uint8_t NeaacDecoder::is_ltp_ot(uint8_t object_type) { + #ifdef LTP_DEC + if ((object_type == LTP) + #ifdef ERROR_RESILIENCE + || (object_type == ER_LTP) + #endif + #ifdef LD_DEC + || (object_type == LD) + #endif + ) { + return 1; + } + #endif + return 0; +} +#endif // LPT_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +void NeaacDecoder::lt_prediction(ic_stream* ics, ltp_info* ltp, real_t* spec, int16_t* lt_pred_stat, fb_info* fb, uint8_t win_shape, uint8_t win_shape_prev, uint8_t sr_index, uint8_t object_type, + uint16_t frame_len) { + uint8_t sfb; + uint16_t bin, i, num_samples; + // real_t x_est[2048]; + // real_t X_est[2048]; + real_t* x_est = (real_t*)faad_malloc(2048 * sizeof(real_t)); + real_t* X_est = (real_t*)faad_malloc(2048 * sizeof(real_t)); + if (ics->window_sequence != EIGHT_SHORT_SEQUENCE) { + if (ltp->data_present) { + num_samples = frame_len << 1; + for (i = 0; i < num_samples; i++) { + /* The extra lookback M (N/2 for LD, 0 for LTP) is handled + in the buffer updating */ + #if 0 + #define MUL_R_C(A, B) ((A) * (B)) + x_est[i] = MUL_R_C(lt_pred_stat[num_samples + i - ltp->lag], + codebook[ltp->coef]); + #else + /* lt_pred_stat is a 16 bit int, multiplied with the fixed point real + this gives a real for x_est + */ + x_est[i] = (real_t)lt_pred_stat[num_samples + i - ltp->lag] * codebook[ltp->coef]; + #endif + } + filter_bank_ltp(fb, ics->window_sequence, win_shape, win_shape_prev, x_est, X_est, object_type, frame_len); + tns_encode_frame(ics, &(ics->tns), sr_index, object_type, X_est, frame_len); + for (sfb = 0; sfb < ltp->last_band; sfb++) { + if (ltp->long_used[sfb]) { + uint16_t low = ics->swb_offset[sfb]; + uint16_t high = min(ics->swb_offset[sfb + 1], ics->swb_offset_max); + for (bin = low; bin < high; bin++) { spec[bin] += X_est[bin]; } + } + } + } + } + if (x_est) free(x_est); + if (X_est) free(X_est); +} +#endif // LPT_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC + #ifdef FIXED_POINT +int16_t NeaacDecoder::real_to_int16(real_t sig_in) { + if (sig_in >= 0) { + sig_in += (1 << (REAL_BITS - 1)); + if (sig_in >= REAL_CONST(32768)) return 32767; + } else { + sig_in += -(1 << (REAL_BITS - 1)); + if (sig_in <= REAL_CONST(-32768)) return -32768; + } + return (sig_in >> REAL_BITS); +} + #else +int16_t NeaacDecoder::real_to_int16(real_t sig_in) { + if (sig_in >= 0) { + #ifndef HAS_LRINTF + sig_in += 0.5f; + #endif + if (sig_in >= 32768.0f) return 32767; + } else { + #ifndef HAS_LRINTF + sig_in += -0.5f; + #endif + if (sig_in <= -32768.0f) return -32768; + } + + return (int16_t)lrintf(sig_in); +} + #endif // FIXED_POINT +#endif // LPT_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef LTP_DEC +void NeaacDecoder::lt_update_state(int16_t* lt_pred_stat, real_t* time, real_t* overlap, uint16_t frame_len, uint8_t object_type) { + uint16_t i; + /* + * The reference point for index i and the content of the buffer + * lt_pred_stat are arranged so that lt_pred_stat(0 ... N/2 - 1) contains the + * last aliased half window from the IMDCT, and lt_pred_stat(N/2 ... N-1) + * is always all zeros. The rest of lt_pred_stat (i<0) contains the previous + * fully reconstructed time domain samples, i.e., output of the decoder. + * + * These values are shifted up by N*2 to avoid (i<0) + * + * For the LD object type an extra 512 samples lookback is accomodated here. + */ + #ifdef LD_DEC + if (object_type == LD) { + for (i = 0; i < frame_len; i++) { + lt_pred_stat[i] /* extra 512 */ = lt_pred_stat[i + frame_len]; + lt_pred_stat[frame_len + i] = lt_pred_stat[i + (frame_len * 2)]; + lt_pred_stat[(frame_len * 2) + i] = real_to_int16(time[i]); + lt_pred_stat[(frame_len * 3) + i] = real_to_int16(overlap[i]); + } + } else { + #endif + for (i = 0; i < frame_len; i++) { + lt_pred_stat[i] = lt_pred_stat[i + frame_len]; + lt_pred_stat[frame_len + i] = real_to_int16(time[i]); + lt_pred_stat[(frame_len * 2) + i] = real_to_int16(overlap[i]); + #if 0 /* set to zero once upon initialisation */ + lt_pred_stat[(frame_len * 3) + i] = 0; + #endif + } + #ifdef LD_DEC + } + #endif +} +#endif // LPT_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +hyb_info* NeaacDecoder::hybrid_init(uint8_t numTimeSlotsRate) { + uint8_t i; + hyb_info* hyb = (hyb_info*)faad_malloc(sizeof(hyb_info)); + hyb->resolution34[0] = 12; + hyb->resolution34[1] = 8; + hyb->resolution34[2] = 4; + hyb->resolution34[3] = 4; + hyb->resolution34[4] = 4; + hyb->resolution20[0] = 8; + hyb->resolution20[1] = 2; + hyb->resolution20[2] = 2; + hyb->frame_len = numTimeSlotsRate; + hyb->work = (qmf_t*)faad_malloc((hyb->frame_len + 12) * sizeof(qmf_t)); + memset(hyb->work, 0, (hyb->frame_len + 12) * sizeof(qmf_t)); + hyb->buffer = (qmf_t**)faad_malloc(5 * sizeof(qmf_t*)); + for (i = 0; i < 5; i++) { + hyb->buffer[i] = (qmf_t*)faad_malloc(hyb->frame_len * sizeof(qmf_t)); + memset(hyb->buffer[i], 0, hyb->frame_len * sizeof(qmf_t)); + } + hyb->temp = (qmf_t**)faad_malloc(hyb->frame_len * sizeof(qmf_t*)); + for (i = 0; i < hyb->frame_len; i++) { hyb->temp[i] = (qmf_t*)faad_malloc(12 /*max*/ * sizeof(qmf_t)); } + return hyb; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::hybrid_free(hyb_info* hyb) { + uint8_t i; + if (!hyb) return; + if (hyb->work) faad_free(&hyb->work); + for (i = 0; i < 5; i++) { + if (hyb->buffer[i]) faad_free(&hyb->buffer[i]); + } + if (hyb->buffer) faad_free((void**)&hyb->buffer); + for (i = 0; i < hyb->frame_len; i++) { + if (hyb->temp[i]) faad_free(&hyb->temp[i]); + } + if (hyb->temp) { faad_free((void**)&hyb->temp); } + faad_free(&hyb); +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* real filter, size 2 */ +void NeaacDecoder::channel_filter2(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid) { + uint8_t i; + for (i = 0; i < frame_len; i++) { + real_t r0 = MUL_F(filter[0], (QMF_RE(buffer[0 + i]) + QMF_RE(buffer[12 + i]))); + real_t r1 = MUL_F(filter[1], (QMF_RE(buffer[1 + i]) + QMF_RE(buffer[11 + i]))); + real_t r2 = MUL_F(filter[2], (QMF_RE(buffer[2 + i]) + QMF_RE(buffer[10 + i]))); + real_t r3 = MUL_F(filter[3], (QMF_RE(buffer[3 + i]) + QMF_RE(buffer[9 + i]))); + real_t r4 = MUL_F(filter[4], (QMF_RE(buffer[4 + i]) + QMF_RE(buffer[8 + i]))); + real_t r5 = MUL_F(filter[5], (QMF_RE(buffer[5 + i]) + QMF_RE(buffer[7 + i]))); + real_t r6 = MUL_F(filter[6], QMF_RE(buffer[6 + i])); + real_t i0 = MUL_F(filter[0], (QMF_IM(buffer[0 + i]) + QMF_IM(buffer[12 + i]))); + real_t i1 = MUL_F(filter[1], (QMF_IM(buffer[1 + i]) + QMF_IM(buffer[11 + i]))); + real_t i2 = MUL_F(filter[2], (QMF_IM(buffer[2 + i]) + QMF_IM(buffer[10 + i]))); + real_t i3 = MUL_F(filter[3], (QMF_IM(buffer[3 + i]) + QMF_IM(buffer[9 + i]))); + real_t i4 = MUL_F(filter[4], (QMF_IM(buffer[4 + i]) + QMF_IM(buffer[8 + i]))); + real_t i5 = MUL_F(filter[5], (QMF_IM(buffer[5 + i]) + QMF_IM(buffer[7 + i]))); + real_t i6 = MUL_F(filter[6], QMF_IM(buffer[6 + i])); + /* q = 0 */ + QMF_RE(X_hybrid[i][0]) = r0 + r1 + r2 + r3 + r4 + r5 + r6; + QMF_IM(X_hybrid[i][0]) = i0 + i1 + i2 + i3 + i4 + i5 + i6; + /* q = 1 */ + QMF_RE(X_hybrid[i][1]) = r0 - r1 + r2 - r3 + r4 - r5 + r6; + QMF_IM(X_hybrid[i][1]) = i0 - i1 + i2 - i3 + i4 - i5 + i6; + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* complex filter, size 4 */ +void NeaacDecoder::channel_filter4(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid) { + uint8_t i; + real_t input_re1[2], input_re2[2], input_im1[2], input_im2[2]; + for (i = 0; i < frame_len; i++) { + input_re1[0] = -MUL_F(filter[2], (QMF_RE(buffer[i + 2]) + QMF_RE(buffer[i + 10]))) + MUL_F(filter[6], QMF_RE(buffer[i + 6])); + input_re1[1] = MUL_F(FRAC_CONST(-0.70710678118655), (MUL_F(filter[1], (QMF_RE(buffer[i + 1]) + QMF_RE(buffer[i + 11]))) + MUL_F(filter[3], (QMF_RE(buffer[i + 3]) + QMF_RE(buffer[i + 9]))) - + MUL_F(filter[5], (QMF_RE(buffer[i + 5]) + QMF_RE(buffer[i + 7]))))); + input_im1[0] = MUL_F(filter[0], (QMF_IM(buffer[i + 0]) - QMF_IM(buffer[i + 12]))) - MUL_F(filter[4], (QMF_IM(buffer[i + 4]) - QMF_IM(buffer[i + 8]))); + input_im1[1] = MUL_F(FRAC_CONST(0.70710678118655), (MUL_F(filter[1], (QMF_IM(buffer[i + 1]) - QMF_IM(buffer[i + 11]))) - MUL_F(filter[3], (QMF_IM(buffer[i + 3]) - QMF_IM(buffer[i + 9]))) - + MUL_F(filter[5], (QMF_IM(buffer[i + 5]) - QMF_IM(buffer[i + 7]))))); + input_re2[0] = MUL_F(filter[0], (QMF_RE(buffer[i + 0]) - QMF_RE(buffer[i + 12]))) - MUL_F(filter[4], (QMF_RE(buffer[i + 4]) - QMF_RE(buffer[i + 8]))); + input_re2[1] = MUL_F(FRAC_CONST(0.70710678118655), (MUL_F(filter[1], (QMF_RE(buffer[i + 1]) - QMF_RE(buffer[i + 11]))) - MUL_F(filter[3], (QMF_RE(buffer[i + 3]) - QMF_RE(buffer[i + 9]))) - + MUL_F(filter[5], (QMF_RE(buffer[i + 5]) - QMF_RE(buffer[i + 7]))))); + input_im2[0] = -MUL_F(filter[2], (QMF_IM(buffer[i + 2]) + QMF_IM(buffer[i + 10]))) + MUL_F(filter[6], QMF_IM(buffer[i + 6])); + input_im2[1] = MUL_F(FRAC_CONST(-0.70710678118655), (MUL_F(filter[1], (QMF_IM(buffer[i + 1]) + QMF_IM(buffer[i + 11]))) + MUL_F(filter[3], (QMF_IM(buffer[i + 3]) + QMF_IM(buffer[i + 9]))) - + MUL_F(filter[5], (QMF_IM(buffer[i + 5]) + QMF_IM(buffer[i + 7]))))); + /* q == 0 */ + QMF_RE(X_hybrid[i][0]) = input_re1[0] + input_re1[1] + input_im1[0] + input_im1[1]; + QMF_IM(X_hybrid[i][0]) = -input_re2[0] - input_re2[1] + input_im2[0] + input_im2[1]; + /* q == 1 */ + QMF_RE(X_hybrid[i][1]) = input_re1[0] - input_re1[1] - input_im1[0] + input_im1[1]; + QMF_IM(X_hybrid[i][1]) = input_re2[0] - input_re2[1] + input_im2[0] - input_im2[1]; + /* q == 2 */ + QMF_RE(X_hybrid[i][2]) = input_re1[0] - input_re1[1] + input_im1[0] - input_im1[1]; + QMF_IM(X_hybrid[i][2]) = -input_re2[0] + input_re2[1] + input_im2[0] - input_im2[1]; + /* q == 3 */ + QMF_RE(X_hybrid[i][3]) = input_re1[0] + input_re1[1] - input_im1[0] - input_im1[1]; + QMF_IM(X_hybrid[i][3]) = input_re2[0] + input_re2[1] + input_im2[0] + input_im2[1]; + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::DCT3_4_unscaled(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7, f8; + f0 = MUL_F(x[2], FRAC_CONST(0.7071067811865476)); + f1 = x[0] - f0; + f2 = x[0] + f0; + f3 = x[1] + x[3]; + f4 = MUL_C(x[1], COEF_CONST(1.3065629648763766)); + f5 = MUL_F(f3, FRAC_CONST(-0.9238795325112866)); + f6 = MUL_F(x[3], FRAC_CONST(-0.5411961001461967)); + f7 = f4 + f5; + f8 = f6 - f5; + y[3] = f2 - f8; + y[0] = f2 + f8; + y[2] = f1 - f7; + y[1] = f1 + f7; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* complex filter, size 8 */ +void NeaacDecoder::channel_filter8(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid) { + uint8_t i, n; + real_t input_re1[4], input_re2[4], input_im1[4], input_im2[4]; + real_t x[4]; + for (i = 0; i < frame_len; i++) { + input_re1[0] = MUL_F(filter[6], QMF_RE(buffer[6 + i])); + input_re1[1] = MUL_F(filter[5], (QMF_RE(buffer[5 + i]) + QMF_RE(buffer[7 + i]))); + input_re1[2] = -MUL_F(filter[0], (QMF_RE(buffer[0 + i]) + QMF_RE(buffer[12 + i]))) + MUL_F(filter[4], (QMF_RE(buffer[4 + i]) + QMF_RE(buffer[8 + i]))); + input_re1[3] = -MUL_F(filter[1], (QMF_RE(buffer[1 + i]) + QMF_RE(buffer[11 + i]))) + MUL_F(filter[3], (QMF_RE(buffer[3 + i]) + QMF_RE(buffer[9 + i]))); + input_im1[0] = MUL_F(filter[5], (QMF_IM(buffer[7 + i]) - QMF_IM(buffer[5 + i]))); + input_im1[1] = MUL_F(filter[0], (QMF_IM(buffer[12 + i]) - QMF_IM(buffer[0 + i]))) + MUL_F(filter[4], (QMF_IM(buffer[8 + i]) - QMF_IM(buffer[4 + i]))); + input_im1[2] = MUL_F(filter[1], (QMF_IM(buffer[11 + i]) - QMF_IM(buffer[1 + i]))) + MUL_F(filter[3], (QMF_IM(buffer[9 + i]) - QMF_IM(buffer[3 + i]))); + input_im1[3] = MUL_F(filter[2], (QMF_IM(buffer[10 + i]) - QMF_IM(buffer[2 + i]))); + for (n = 0; n < 4; n++) { x[n] = input_re1[n] - input_im1[3 - n]; } + DCT3_4_unscaled(x, x); + QMF_RE(X_hybrid[i][7]) = x[0]; + QMF_RE(X_hybrid[i][5]) = x[2]; + QMF_RE(X_hybrid[i][3]) = x[3]; + QMF_RE(X_hybrid[i][1]) = x[1]; + for (n = 0; n < 4; n++) { x[n] = input_re1[n] + input_im1[3 - n]; } + DCT3_4_unscaled(x, x); + QMF_RE(X_hybrid[i][6]) = x[1]; + QMF_RE(X_hybrid[i][4]) = x[3]; + QMF_RE(X_hybrid[i][2]) = x[2]; + QMF_RE(X_hybrid[i][0]) = x[0]; + input_im2[0] = MUL_F(filter[6], QMF_IM(buffer[6 + i])); + input_im2[1] = MUL_F(filter[5], (QMF_IM(buffer[5 + i]) + QMF_IM(buffer[7 + i]))); + input_im2[2] = -MUL_F(filter[0], (QMF_IM(buffer[0 + i]) + QMF_IM(buffer[12 + i]))) + MUL_F(filter[4], (QMF_IM(buffer[4 + i]) + QMF_IM(buffer[8 + i]))); + input_im2[3] = -MUL_F(filter[1], (QMF_IM(buffer[1 + i]) + QMF_IM(buffer[11 + i]))) + MUL_F(filter[3], (QMF_IM(buffer[3 + i]) + QMF_IM(buffer[9 + i]))); + input_re2[0] = MUL_F(filter[5], (QMF_RE(buffer[7 + i]) - QMF_RE(buffer[5 + i]))); + input_re2[1] = MUL_F(filter[0], (QMF_RE(buffer[12 + i]) - QMF_RE(buffer[0 + i]))) + MUL_F(filter[4], (QMF_RE(buffer[8 + i]) - QMF_RE(buffer[4 + i]))); + input_re2[2] = MUL_F(filter[1], (QMF_RE(buffer[11 + i]) - QMF_RE(buffer[1 + i]))) + MUL_F(filter[3], (QMF_RE(buffer[9 + i]) - QMF_RE(buffer[3 + i]))); + input_re2[3] = MUL_F(filter[2], (QMF_RE(buffer[10 + i]) - QMF_RE(buffer[2 + i]))); + for (n = 0; n < 4; n++) { x[n] = input_im2[n] + input_re2[3 - n]; } + DCT3_4_unscaled(x, x); + QMF_IM(X_hybrid[i][7]) = x[0]; + QMF_IM(X_hybrid[i][5]) = x[2]; + QMF_IM(X_hybrid[i][3]) = x[3]; + QMF_IM(X_hybrid[i][1]) = x[1]; + for (n = 0; n < 4; n++) { x[n] = input_im2[n] - input_re2[3 - n]; } + DCT3_4_unscaled(x, x); + QMF_IM(X_hybrid[i][6]) = x[1]; + QMF_IM(X_hybrid[i][4]) = x[3]; + QMF_IM(X_hybrid[i][2]) = x[2]; + QMF_IM(X_hybrid[i][0]) = x[0]; + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::DCT3_6_unscaled(real_t* y, real_t* x) { + real_t f0, f1, f2, f3, f4, f5, f6, f7; + f0 = MUL_F(x[3], FRAC_CONST(0.70710678118655)); + f1 = x[0] + f0; + f2 = x[0] - f0; + f3 = MUL_F((x[1] - x[5]), FRAC_CONST(0.70710678118655)); + f4 = MUL_F(x[2], FRAC_CONST(0.86602540378444)) + MUL_F(x[4], FRAC_CONST(0.5)); + f5 = f4 - x[4]; + f6 = MUL_F(x[1], FRAC_CONST(0.96592582628907)) + MUL_F(x[5], FRAC_CONST(0.25881904510252)); + f7 = f6 - f3; + y[0] = f1 + f6 + f4; + y[1] = f2 + f3 - x[4]; + y[2] = f7 + f2 - f5; + y[3] = f1 - f7 - f5; + y[4] = f1 - f3 - x[4]; + y[5] = f2 - f6 + f4; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* complex filter, size 12 */ +void NeaacDecoder::channel_filter12(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid) { + uint8_t i, n; + real_t input_re1[6], input_re2[6], input_im1[6], input_im2[6]; + real_t out_re1[6], out_re2[6], out_im1[6], out_im2[6]; + for (i = 0; i < frame_len; i++) { + for (n = 0; n < 6; n++) { + if (n == 0) { + input_re1[0] = MUL_F(QMF_RE(buffer[6 + i]), filter[6]); + input_re2[0] = MUL_F(QMF_IM(buffer[6 + i]), filter[6]); + } else { + input_re1[6 - n] = MUL_F((QMF_RE(buffer[n + i]) + QMF_RE(buffer[12 - n + i])), filter[n]); + input_re2[6 - n] = MUL_F((QMF_IM(buffer[n + i]) + QMF_IM(buffer[12 - n + i])), filter[n]); + } + input_im2[n] = MUL_F((QMF_RE(buffer[n + i]) - QMF_RE(buffer[12 - n + i])), filter[n]); + input_im1[n] = MUL_F((QMF_IM(buffer[n + i]) - QMF_IM(buffer[12 - n + i])), filter[n]); + } + DCT3_6_unscaled(out_re1, input_re1); + DCT3_6_unscaled(out_re2, input_re2); + DCT3_6_unscaled(out_im1, input_im1); + DCT3_6_unscaled(out_im2, input_im2); + for (n = 0; n < 6; n += 2) { + QMF_RE(X_hybrid[i][n]) = out_re1[n] - out_im1[n]; + QMF_IM(X_hybrid[i][n]) = out_re2[n] + out_im2[n]; + QMF_RE(X_hybrid[i][n + 1]) = out_re1[n + 1] + out_im1[n + 1]; + QMF_IM(X_hybrid[i][n + 1]) = out_re2[n + 1] - out_im2[n + 1]; + QMF_RE(X_hybrid[i][10 - n]) = out_re1[n + 1] - out_im1[n + 1]; + QMF_IM(X_hybrid[i][10 - n]) = out_re2[n + 1] + out_im2[n + 1]; + QMF_RE(X_hybrid[i][11 - n]) = out_re1[n] + out_im1[n]; + QMF_IM(X_hybrid[i][11 - n]) = out_re2[n] - out_im2[n]; + } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* Hybrid analysis: further split up QMF subbands to improve frequency resolution */ +void NeaacDecoder::hybrid_analysis(hyb_info* hyb, qmf_t X[32][64], qmf_t X_hybrid[32][32], uint8_t use34, uint8_t numTimeSlotsRate) { + uint8_t k, n, band; + uint8_t offset = 0; + uint8_t qmf_bands = (use34) ? 5 : 3; + uint8_t* resolution = (use34) ? hyb->resolution34 : hyb->resolution20; + for (band = 0; band < qmf_bands; band++) { + /* build working buffer */ + memcpy(hyb->work, hyb->buffer[band], 12 * sizeof(qmf_t)); + /* add new samples */ + for (n = 0; n < hyb->frame_len; n++) { + QMF_RE(hyb->work[12 + n]) = QMF_RE(X[n + 6 /*delay*/][band]); + QMF_IM(hyb->work[12 + n]) = QMF_IM(X[n + 6 /*delay*/][band]); + } + /* store samples */ + memcpy(hyb->buffer[band], hyb->work + hyb->frame_len, 12 * sizeof(qmf_t)); + switch (resolution[band]) { + case 2: + /* Type B real filter, Q[p] = 2 */ + channel_filter2(hyb, hyb->frame_len, p2_13_20, hyb->work, hyb->temp); + break; + case 4: + /* Type A complex filter, Q[p] = 4 */ + channel_filter4(hyb, hyb->frame_len, p4_13_34, hyb->work, hyb->temp); + break; + case 8: + /* Type A complex filter, Q[p] = 8 */ + channel_filter8(hyb, hyb->frame_len, (use34) ? p8_13_34 : p8_13_20, hyb->work, hyb->temp); + break; + case 12: + /* Type A complex filter, Q[p] = 12 */ + channel_filter12(hyb, hyb->frame_len, p12_13_34, hyb->work, hyb->temp); + break; + } + for (n = 0; n < hyb->frame_len; n++) { + for (k = 0; k < resolution[band]; k++) { + QMF_RE(X_hybrid[n][offset + k]) = QMF_RE(hyb->temp[n][k]); + QMF_IM(X_hybrid[n][offset + k]) = QMF_IM(hyb->temp[n][k]); + } + } + offset += resolution[band]; + } + /* group hybrid channels */ + if (!use34) { + for (n = 0; n < numTimeSlotsRate; n++) { + QMF_RE(X_hybrid[n][3]) += QMF_RE(X_hybrid[n][4]); + QMF_IM(X_hybrid[n][3]) += QMF_IM(X_hybrid[n][4]); + QMF_RE(X_hybrid[n][4]) = 0; + QMF_IM(X_hybrid[n][4]) = 0; + QMF_RE(X_hybrid[n][2]) += QMF_RE(X_hybrid[n][5]); + QMF_IM(X_hybrid[n][2]) += QMF_IM(X_hybrid[n][5]); + QMF_RE(X_hybrid[n][5]) = 0; + QMF_IM(X_hybrid[n][5]) = 0; + } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::hybrid_synthesis(hyb_info* hyb, qmf_t X[32][64], qmf_t X_hybrid[32][32], uint8_t use34, uint8_t numTimeSlotsRate) { + uint8_t k, n, band; + uint8_t offset = 0; + uint8_t qmf_bands = (use34) ? 5 : 3; + uint8_t* resolution = (use34) ? hyb->resolution34 : hyb->resolution20; + for (band = 0; band < qmf_bands; band++) { + for (n = 0; n < hyb->frame_len; n++) { + QMF_RE(X[n][band]) = 0; + QMF_IM(X[n][band]) = 0; + for (k = 0; k < resolution[band]; k++) { + QMF_RE(X[n][band]) += QMF_RE(X_hybrid[n][offset + k]); + QMF_IM(X[n][band]) += QMF_IM(X_hybrid[n][offset + k]); + } + } + offset += resolution[band]; + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* limits the value i to the range [min,max] */ +int8_t NeaacDecoder::delta_clip(int8_t i, int8_t min, int8_t max) { + if (i < min) + return min; + else if (i > max) + return max; + else + return i; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* delta decode array */ +void NeaacDecoder::delta_decode(uint8_t enable, int8_t* index, int8_t* index_prev, uint8_t dt_flag, uint8_t nr_par, uint8_t stride, int8_t min_index, int8_t max_index) { + int8_t i; + if (enable == 1) { + if (dt_flag == 0) { + /* delta coded in frequency direction */ + index[0] = 0 + index[0]; + index[0] = delta_clip(index[0], min_index, max_index); + for (i = 1; i < nr_par; i++) { + index[i] = index[i - 1] + index[i]; + index[i] = delta_clip(index[i], min_index, max_index); + } + } else { + /* delta coded in time direction */ + for (i = 0; i < nr_par; i++) { + // int8_t tmp2; + // int8_t tmp = index[i]; + // printf("%d %d\n", index_prev[i*stride], index[i]); + // printf("%d\n", index[i]); + index[i] = index_prev[i * stride] + index[i]; + // tmp2 = index[i]; + index[i] = delta_clip(index[i], min_index, max_index); + // if (iid) + //{ + // if (index[i] == 7) + // { + // printf("%d %d %d\n", index_prev[i*stride], tmp, tmp2); + // } + // } + } + } + } else { + /* set indices to zero */ + for (i = 0; i < nr_par; i++) { index[i] = 0; } + } + /* coarse */ + if (stride == 2) { + for (i = (nr_par << 1) - 1; i > 0; i--) { index[i] = index[i >> 1]; } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* delta modulo decode array */ +/* in: log2 value of the modulo value to allow using AND instead of MOD */ +void NeaacDecoder::delta_modulo_decode(uint8_t enable, int8_t* index, int8_t* index_prev, uint8_t dt_flag, uint8_t nr_par, uint8_t stride, int8_t and_modulo) { + int8_t i; + if (enable == 1) { + if (dt_flag == 0) { + /* delta coded in frequency direction */ + index[0] = 0 + index[0]; + index[0] &= and_modulo; + for (i = 1; i < nr_par; i++) { + index[i] = index[i - 1] + index[i]; + index[i] &= and_modulo; + } + } else { + /* delta coded in time direction */ + for (i = 0; i < nr_par; i++) { + index[i] = index_prev[i * stride] + index[i]; + index[i] &= and_modulo; + } + } + } else { + /* set indices to zero */ + for (i = 0; i < nr_par; i++) { index[i] = 0; } + } + /* coarse */ + if (stride == 2) { + index[0] = 0; + for (i = (nr_par << 1) - 1; i > 0; i--) { index[i] = index[i >> 1]; } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC + #ifdef PS_LOW_POWER +void NeaacDecoder::map34indexto20(int8_t* index, uint8_t bins) { + index[0] = (2 * index[0] + index[1]) / 3; + index[1] = (index[1] + 2 * index[2]) / 3; + index[2] = (2 * index[3] + index[4]) / 3; + index[3] = (index[4] + 2 * index[5]) / 3; + index[4] = (index[6] + index[7]) / 2; + index[5] = (index[8] + index[9]) / 2; + index[6] = index[10]; + index[7] = index[11]; + index[8] = (index[12] + index[13]) / 2; + index[9] = (index[14] + index[15]) / 2; + index[10] = index[16]; + if (bins == 34) { + index[11] = index[17]; + index[12] = index[18]; + index[13] = index[19]; + index[14] = (index[20] + index[21]) / 2; + index[15] = (index[22] + index[23]) / 2; + index[16] = (index[24] + index[25]) / 2; + index[17] = (index[26] + index[27]) / 2; + index[18] = (index[28] + index[29] + index[30] + index[31]) / 4; + index[19] = (index[32] + index[33]) / 2; + } +} + #endif // PS_LOW_POWER +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::map20indexto34(int8_t* index, uint8_t bins) { + index[0] = index[0]; + index[1] = (index[0] + index[1]) / 2; + index[2] = index[1]; + index[3] = index[2]; + index[4] = (index[2] + index[3]) / 2; + index[5] = index[3]; + index[6] = index[4]; + index[7] = index[4]; + index[8] = index[5]; + index[9] = index[5]; + index[10] = index[6]; + index[11] = index[7]; + index[12] = index[8]; + index[13] = index[8]; + index[14] = index[9]; + index[15] = index[9]; + index[16] = index[10]; + if (bins == 34) { + index[17] = index[11]; + index[18] = index[12]; + index[19] = index[13]; + index[20] = index[14]; + index[21] = index[14]; + index[22] = index[15]; + index[23] = index[15]; + index[24] = index[16]; + index[25] = index[16]; + index[26] = index[17]; + index[27] = index[17]; + index[28] = index[18]; + index[29] = index[18]; + index[30] = index[18]; + index[31] = index[18]; + index[32] = index[19]; + index[33] = index[19]; + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* parse the bitstream data decoded in ps_data() */ +void NeaacDecoder::ps_data_decode(ps_info* ps) { + uint8_t env, bin; + /* ps data not available, use data from previous frame */ + if (ps->ps_data_available == 0) { ps->num_env = 0; } + for (env = 0; env < ps->num_env; env++) { + int8_t* iid_index_prev; + int8_t* icc_index_prev; + int8_t* ipd_index_prev; + int8_t* opd_index_prev; + int8_t num_iid_steps = (ps->iid_mode < 3) ? 7 : 15 /*fine quant*/; + if (env == 0) { + /* take last envelope from previous frame */ + iid_index_prev = ps->iid_index_prev; + icc_index_prev = ps->icc_index_prev; + ipd_index_prev = ps->ipd_index_prev; + opd_index_prev = ps->opd_index_prev; + } else { + /* take index values from previous envelope */ + iid_index_prev = ps->iid_index[env - 1]; + icc_index_prev = ps->icc_index[env - 1]; + ipd_index_prev = ps->ipd_index[env - 1]; + opd_index_prev = ps->opd_index[env - 1]; + } + // iid = 1; + /* delta decode iid parameters */ + delta_decode(ps->enable_iid, ps->iid_index[env], iid_index_prev, ps->iid_dt[env], ps->nr_iid_par, (ps->iid_mode == 0 || ps->iid_mode == 3) ? 2 : 1, -num_iid_steps, num_iid_steps); + // iid = 0; + /* delta decode icc parameters */ + delta_decode(ps->enable_icc, ps->icc_index[env], icc_index_prev, ps->icc_dt[env], ps->nr_icc_par, (ps->icc_mode == 0 || ps->icc_mode == 3) ? 2 : 1, 0, 7); + /* delta modulo decode ipd parameters */ + delta_modulo_decode(ps->enable_ipdopd, ps->ipd_index[env], ipd_index_prev, ps->ipd_dt[env], ps->nr_ipdopd_par, 1, 7); + /* delta modulo decode opd parameters */ + delta_modulo_decode(ps->enable_ipdopd, ps->opd_index[env], opd_index_prev, ps->opd_dt[env], ps->nr_ipdopd_par, 1, 7); + } + /* handle error case */ + if (ps->num_env == 0) { + /* force to 1 */ + ps->num_env = 1; + if (ps->enable_iid) { + for (bin = 0; bin < 34; bin++) ps->iid_index[0][bin] = ps->iid_index_prev[bin]; + } else { + for (bin = 0; bin < 34; bin++) ps->iid_index[0][bin] = 0; + } + if (ps->enable_icc) { + for (bin = 0; bin < 34; bin++) ps->icc_index[0][bin] = ps->icc_index_prev[bin]; + } else { + for (bin = 0; bin < 34; bin++) ps->icc_index[0][bin] = 0; + } + if (ps->enable_ipdopd) { + for (bin = 0; bin < 17; bin++) { + ps->ipd_index[0][bin] = ps->ipd_index_prev[bin]; + ps->opd_index[0][bin] = ps->opd_index_prev[bin]; + } + } else { + for (bin = 0; bin < 17; bin++) { + ps->ipd_index[0][bin] = 0; + ps->opd_index[0][bin] = 0; + } + } + } + /* update previous indices */ + for (bin = 0; bin < 34; bin++) ps->iid_index_prev[bin] = ps->iid_index[ps->num_env - 1][bin]; + for (bin = 0; bin < 34; bin++) ps->icc_index_prev[bin] = ps->icc_index[ps->num_env - 1][bin]; + for (bin = 0; bin < 17; bin++) { + ps->ipd_index_prev[bin] = ps->ipd_index[ps->num_env - 1][bin]; + ps->opd_index_prev[bin] = ps->opd_index[ps->num_env - 1][bin]; + } + ps->ps_data_available = 0; + if (ps->frame_class == 0) { + ps->border_position[0] = 0; + for (env = 1; env < ps->num_env; env++) { ps->border_position[env] = (env * ps->numTimeSlotsRate) / ps->num_env; } + ps->border_position[ps->num_env] = ps->numTimeSlotsRate; + } else { + ps->border_position[0] = 0; + if (ps->border_position[ps->num_env] < ps->numTimeSlotsRate) { + for (bin = 0; bin < 34; bin++) { + ps->iid_index[ps->num_env][bin] = ps->iid_index[ps->num_env - 1][bin]; + ps->icc_index[ps->num_env][bin] = ps->icc_index[ps->num_env - 1][bin]; + } + for (bin = 0; bin < 17; bin++) { + ps->ipd_index[ps->num_env][bin] = ps->ipd_index[ps->num_env - 1][bin]; + ps->opd_index[ps->num_env][bin] = ps->opd_index[ps->num_env - 1][bin]; + } + ps->num_env++; + ps->border_position[ps->num_env] = ps->numTimeSlotsRate; + } + for (env = 1; env < ps->num_env; env++) { + int8_t thr = ps->numTimeSlotsRate - (ps->num_env - env); + if (ps->border_position[env] > thr) { + ps->border_position[env] = thr; + } else { + thr = ps->border_position[env - 1] + 1; + if (ps->border_position[env] < thr) { ps->border_position[env] = thr; } + } + } + } + /* make sure that the indices of all parameters can be mapped to the same hybrid synthesis filterbank */ + #ifdef PS_LOW_POWER + for (env = 0; env < ps->num_env; env++) { + if (ps->iid_mode == 2 || ps->iid_mode == 5) map34indexto20(ps->iid_index[env], 34); + if (ps->icc_mode == 2 || ps->icc_mode == 5) map34indexto20(ps->icc_index[env], 34); + /* disable ipd/opd */ + for (bin = 0; bin < 17; bin++) { + ps->aaIpdIndex[env][bin] = 0; + ps->aaOpdIndex[env][bin] = 0; + } + } + #else + if (ps->use34hybrid_bands) { + for (env = 0; env < ps->num_env; env++) { + if (ps->iid_mode != 2 && ps->iid_mode != 5) map20indexto34(ps->iid_index[env], 34); + if (ps->icc_mode != 2 && ps->icc_mode != 5) map20indexto34(ps->icc_index[env], 34); + if (ps->ipd_mode != 2 && ps->ipd_mode != 5) { + map20indexto34(ps->ipd_index[env], 17); + map20indexto34(ps->opd_index[env], 17); + } + } + } + #endif + #if 0 + for (env = 0; env < ps->num_env; env++) + { + printf("iid[env:%d]:", env); + for (bin = 0; bin < 34; bin++) + { + printf(" %d", ps->iid_index[env][bin]); + } + printf("\n"); + } + for (env = 0; env < ps->num_env; env++) + { + printf("icc[env:%d]:", env); + for (bin = 0; bin < 34; bin++) + { + printf(" %d", ps->icc_index[env][bin]); + } + printf("\n"); + } + for (env = 0; env < ps->num_env; env++) + { + printf("ipd[env:%d]:", env); + for (bin = 0; bin < 17; bin++) + { + printf(" %d", ps->ipd_index[env][bin]); + } + printf("\n"); + } + for (env = 0; env < ps->num_env; env++) + { + printf("opd[env:%d]:", env); + for (bin = 0; bin < 17; bin++) + { + printf(" %d", ps->opd_index[env][bin]); + } + printf("\n"); + } + printf("\n"); + #endif +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +extern const complex_t Phi_Fract_Qmf[]; +/* decorrelate the mono signal using an allpass filter */ +void NeaacDecoder::ps_decorrelate(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64], qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32]) { + uint8_t gr, n, m, bk; + uint8_t temp_delay = 0; + (void)temp_delay; + uint8_t sb, maxsb; + const complex_t* Phi_Fract_SubQmf; + uint8_t temp_delay_ser[NO_ALLPASS_LINKS] = {0}; + real_t P_SmoothPeakDecayDiffNrg, nrg; + // real_t P[32][34]; + real_t(*P)[34] = (real_t(*)[34])faad_malloc(32 * sizeof(real_t[34])); + // real_t G_TransientRatio[32][34] = {{0}}; + real_t(*G_TransientRatio)[34] = (real_t(*)[34])faad_calloc(32, sizeof(real_t[34])); + complex_t inputLeft; + /* chose hybrid filterbank: 20 or 34 band case */ + if (ps->use34hybrid_bands) { + Phi_Fract_SubQmf = Phi_Fract_SubQmf34; + } else { + Phi_Fract_SubQmf = Phi_Fract_SubQmf20; + } + /* clear the energy values */ + for (n = 0; n < 32; n++) { + for (bk = 0; bk < 34; bk++) { P[n][bk] = 0; } + } + /* calculate the energy in each parameter band b(k) */ + for (gr = 0; gr < ps->num_groups; gr++) { + /* select the parameter index b(k) to which this group belongs */ + bk = (~NEGATE_IPD_MASK) & ps->map_group2bk[gr]; + /* select the upper subband border for this group */ + maxsb = (gr < ps->num_hybrid_groups) ? ps->group_border[gr] + 1 : ps->group_border[gr + 1]; + for (sb = ps->group_border[gr]; sb < maxsb; sb++) { + for (n = ps->border_position[0]; n < ps->border_position[ps->num_env]; n++) { + #ifdef FIXED_POINT + uint32_t in_re, in_im; + #endif + /* input from hybrid subbands or QMF subbands */ + if (gr < ps->num_hybrid_groups) { + RE(inputLeft) = QMF_RE(X_hybrid_left[n][sb]); + IM(inputLeft) = QMF_IM(X_hybrid_left[n][sb]); + } else { + RE(inputLeft) = QMF_RE(X_left[n][sb]); + IM(inputLeft) = QMF_IM(X_left[n][sb]); + } + /* accumulate energy */ + #ifdef FIXED_POINT + /* NOTE: all input is scaled by 2^(-5) because of fixed point QMF + * meaning that P will be scaled by 2^(-10) compared to floating point version + */ + in_re = ((abs(RE(inputLeft)) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + in_im = ((abs(IM(inputLeft)) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + P[n][bk] += in_re * in_re + in_im * in_im; + #else + P[n][bk] += MUL_R(RE(inputLeft), RE(inputLeft)) + MUL_R(IM(inputLeft), IM(inputLeft)); + #endif + } + } + } + #if 0 + for (n = 0; n < 32; n++) + { + for (bk = 0; bk < 34; bk++) + { + #ifdef FIXED_POINT + printf("%d %d: %d\n", n, bk, P[n][bk] /*/(float)REAL_PRECISION*/); + #else + printf("%d %d: %f\n", n, bk, P[n][bk]/1024.0); + #endif + } + } + #endif + /* calculate transient reduction ratio for each parameter band b(k) */ + for (bk = 0; bk < ps->nr_par_bands; bk++) { + for (n = ps->border_position[0]; n < ps->border_position[ps->num_env]; n++) { + const real_t gamma = COEF_CONST(1.5); + ps->P_PeakDecayNrg[bk] = MUL_F(ps->P_PeakDecayNrg[bk], ps->alpha_decay); + if (ps->P_PeakDecayNrg[bk] < P[n][bk]) ps->P_PeakDecayNrg[bk] = P[n][bk]; + /* apply smoothing filter to peak decay energy */ + P_SmoothPeakDecayDiffNrg = ps->P_SmoothPeakDecayDiffNrg_prev[bk]; + P_SmoothPeakDecayDiffNrg += MUL_F((ps->P_PeakDecayNrg[bk] - P[n][bk] - ps->P_SmoothPeakDecayDiffNrg_prev[bk]), ps->alpha_smooth); + ps->P_SmoothPeakDecayDiffNrg_prev[bk] = P_SmoothPeakDecayDiffNrg; + /* apply smoothing filter to energy */ + nrg = ps->P_prev[bk]; + nrg += MUL_F((P[n][bk] - ps->P_prev[bk]), ps->alpha_smooth); + ps->P_prev[bk] = nrg; + /* calculate transient ratio */ + if (MUL_C(P_SmoothPeakDecayDiffNrg, gamma) <= nrg) { + G_TransientRatio[n][bk] = REAL_CONST(1.0); + } else { + G_TransientRatio[n][bk] = DIV_R(nrg, (MUL_C(P_SmoothPeakDecayDiffNrg, gamma))); + } + } + } + #if 0 + for (n = 0; n < 32; n++) + { + for (bk = 0; bk < 34; bk++) + { + #ifdef FIXED_POINT + printf("%d %d: %f\n", n, bk, G_TransientRatio[n][bk]/(float)REAL_PRECISION); + #else + printf("%d %d: %f\n", n, bk, G_TransientRatio[n][bk]); + #endif + } + } + #endif + /* apply stereo decorrelation filter to the signal */ + for (gr = 0; gr < ps->num_groups; gr++) { + if (gr < ps->num_hybrid_groups) + maxsb = ps->group_border[gr] + 1; + else + maxsb = ps->group_border[gr + 1]; + /* QMF channel */ + for (sb = ps->group_border[gr]; sb < maxsb; sb++) { + real_t g_DecaySlope; + real_t g_DecaySlope_filt[NO_ALLPASS_LINKS]; + /* g_DecaySlope: [0..1] */ + if (gr < ps->num_hybrid_groups || sb <= ps->decay_cutoff) { + g_DecaySlope = FRAC_CONST(1.0); + } else { + int8_t decay = ps->decay_cutoff - sb; + if (decay <= -20 /* -1/DECAY_SLOPE */) { + g_DecaySlope = 0; + } else { + /* decay(int)*decay_slope(frac) = g_DecaySlope(frac) */ + g_DecaySlope = FRAC_CONST(1.0) + DECAY_SLOPE * decay; + } + } + /* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */ + for (m = 0; m < NO_ALLPASS_LINKS; m++) { g_DecaySlope_filt[m] = MUL_F(g_DecaySlope, filter_a[m]); } + /* set delay indices */ + temp_delay = ps->saved_delay; + for (n = 0; n < NO_ALLPASS_LINKS; n++) temp_delay_ser[n] = ps->delay_buf_index_ser[n]; + for (n = ps->border_position[0]; n < ps->border_position[ps->num_env]; n++) { + complex_t tmp, tmp0, R0; + if (gr < ps->num_hybrid_groups) { + /* hybrid filterbank input */ + RE(inputLeft) = QMF_RE(X_hybrid_left[n][sb]); + IM(inputLeft) = QMF_IM(X_hybrid_left[n][sb]); + } else { + /* QMF filterbank input */ + RE(inputLeft) = QMF_RE(X_left[n][sb]); + IM(inputLeft) = QMF_IM(X_left[n][sb]); + } + if (sb > ps->nr_allpass_bands && gr >= ps->num_hybrid_groups) { + /* delay */ + /* never hybrid subbands here, always QMF subbands */ + RE(tmp) = RE(ps->delay_Qmf[ps->delay_buf_index_delay[sb]][sb]); + IM(tmp) = IM(ps->delay_Qmf[ps->delay_buf_index_delay[sb]][sb]); + RE(R0) = RE(tmp); + IM(R0) = IM(tmp); + RE(ps->delay_Qmf[ps->delay_buf_index_delay[sb]][sb]) = RE(inputLeft); + IM(ps->delay_Qmf[ps->delay_buf_index_delay[sb]][sb]) = IM(inputLeft); + } else { + /* allpass filter */ + uint8_t m; + complex_t Phi_Fract; + /* fetch parameters */ + if (gr < ps->num_hybrid_groups) { + /* select data from the hybrid subbands */ + RE(tmp0) = RE(ps->delay_SubQmf[temp_delay][sb]); + IM(tmp0) = IM(ps->delay_SubQmf[temp_delay][sb]); + RE(ps->delay_SubQmf[temp_delay][sb]) = RE(inputLeft); + IM(ps->delay_SubQmf[temp_delay][sb]) = IM(inputLeft); + RE(Phi_Fract) = RE(Phi_Fract_SubQmf[sb]); + IM(Phi_Fract) = IM(Phi_Fract_SubQmf[sb]); + } else { + /* select data from the QMF subbands */ + RE(tmp0) = RE(ps->delay_Qmf[temp_delay][sb]); + IM(tmp0) = IM(ps->delay_Qmf[temp_delay][sb]); + RE(ps->delay_Qmf[temp_delay][sb]) = RE(inputLeft); + IM(ps->delay_Qmf[temp_delay][sb]) = IM(inputLeft); + RE(Phi_Fract) = RE(Phi_Fract_Qmf[sb]); + IM(Phi_Fract) = IM(Phi_Fract_Qmf[sb]); + } + /* z^(-2) * Phi_Fract[k] */ + ComplexMult(&RE(tmp), &IM(tmp), RE(tmp0), IM(tmp0), RE(Phi_Fract), IM(Phi_Fract)); + RE(R0) = RE(tmp); + IM(R0) = IM(tmp); + for (m = 0; m < NO_ALLPASS_LINKS; m++) { + complex_t Q_Fract_allpass, tmp2; + /* fetch parameters */ + if (gr < ps->num_hybrid_groups) { + /* select data from the hybrid subbands */ + RE(tmp0) = RE(ps->delay_SubQmf_ser[m][temp_delay_ser[m]][sb]); + IM(tmp0) = IM(ps->delay_SubQmf_ser[m][temp_delay_ser[m]][sb]); + if (ps->use34hybrid_bands) { + RE(Q_Fract_allpass) = RE(Q_Fract_allpass_SubQmf34[sb][m]); + IM(Q_Fract_allpass) = IM(Q_Fract_allpass_SubQmf34[sb][m]); + } else { + RE(Q_Fract_allpass) = RE(Q_Fract_allpass_SubQmf20[sb][m]); + IM(Q_Fract_allpass) = IM(Q_Fract_allpass_SubQmf20[sb][m]); + } + } else { + /* select data from the QMF subbands */ + RE(tmp0) = RE(ps->delay_Qmf_ser[m][temp_delay_ser[m]][sb]); + IM(tmp0) = IM(ps->delay_Qmf_ser[m][temp_delay_ser[m]][sb]); + RE(Q_Fract_allpass) = RE(Q_Fract_allpass_Qmf[sb][m]); + IM(Q_Fract_allpass) = IM(Q_Fract_allpass_Qmf[sb][m]); + } + /* delay by a fraction */ + /* z^(-d(m)) * Q_Fract_allpass[k,m] */ + ComplexMult(&RE(tmp), &IM(tmp), RE(tmp0), IM(tmp0), RE(Q_Fract_allpass), IM(Q_Fract_allpass)); + /* -a(m) * g_DecaySlope[k] */ + RE(tmp) += -MUL_F(g_DecaySlope_filt[m], RE(R0)); + IM(tmp) += -MUL_F(g_DecaySlope_filt[m], IM(R0)); + /* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */ + RE(tmp2) = RE(R0) + MUL_F(g_DecaySlope_filt[m], RE(tmp)); + IM(tmp2) = IM(R0) + MUL_F(g_DecaySlope_filt[m], IM(tmp)); + /* store sample */ + if (gr < ps->num_hybrid_groups) { + RE(ps->delay_SubQmf_ser[m][temp_delay_ser[m]][sb]) = RE(tmp2); + IM(ps->delay_SubQmf_ser[m][temp_delay_ser[m]][sb]) = IM(tmp2); + } else { + RE(ps->delay_Qmf_ser[m][temp_delay_ser[m]][sb]) = RE(tmp2); + IM(ps->delay_Qmf_ser[m][temp_delay_ser[m]][sb]) = IM(tmp2); + } + /* store for next iteration (or as output value if last iteration) */ + RE(R0) = RE(tmp); + IM(R0) = IM(tmp); + } + } + /* select b(k) for reading the transient ratio */ + bk = (~NEGATE_IPD_MASK) & ps->map_group2bk[gr]; + /* duck if a past transient is found */ + RE(R0) = MUL_R(G_TransientRatio[n][bk], RE(R0)); + IM(R0) = MUL_R(G_TransientRatio[n][bk], IM(R0)); + if (gr < ps->num_hybrid_groups) { + /* hybrid */ + QMF_RE(X_hybrid_right[n][sb]) = RE(R0); + QMF_IM(X_hybrid_right[n][sb]) = IM(R0); + } else { + /* QMF */ + QMF_RE(X_right[n][sb]) = RE(R0); + QMF_IM(X_right[n][sb]) = IM(R0); + } + /* Update delay buffer index */ + if (++temp_delay >= 2) { temp_delay = 0; } + /* update delay indices */ + if (sb > ps->nr_allpass_bands && gr >= ps->num_hybrid_groups) { + /* delay_D depends on the samplerate, it can hold the values 14 and 1 */ + if (++ps->delay_buf_index_delay[sb] >= ps->delay_D[sb]) { ps->delay_buf_index_delay[sb] = 0; } + } + for (m = 0; m < NO_ALLPASS_LINKS; m++) { + if (++temp_delay_ser[m] >= ps->num_sample_delay_ser[m]) { temp_delay_ser[m] = 0; } + } + } + } + } + /* update delay indices */ + ps->saved_delay = temp_delay; + for (m = 0; m < NO_ALLPASS_LINKS; m++) ps->delay_buf_index_ser[m] = temp_delay_ser[m]; + if (P) free(P); + if (G_TransientRatio) free(G_TransientRatio); +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +real_t NeaacDecoder::magnitude_c(complex_t c) { + #ifdef FIXED_POINT + #define ps_abs(A) (((A) > 0) ? (A) : (-(A))) + #define ALPHA FRAC_CONST(0.948059448969) + #define BETA FRAC_CONST(0.392699081699) + real_t abs_inphase = ps_abs(RE(c)); + real_t abs_quadrature = ps_abs(IM(c)); + if (abs_inphase > abs_quadrature) { + return MUL_F(abs_inphase, ALPHA) + MUL_F(abs_quadrature, BETA); + } else { + return MUL_F(abs_quadrature, ALPHA) + MUL_F(abs_inphase, BETA); + } + #else + return sqrt(RE(c) * RE(c) + IM(c) * IM(c)); + #endif +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::ps_mix_phase(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64], qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32]) { + uint8_t n; + uint8_t gr; + uint8_t bk = 0; + uint8_t sb, maxsb; + uint8_t env; + uint8_t nr_ipdopd_par; + complex_t h11 = {0}, h12 = {0}, h21 = {0}, h22 = {0}; + complex_t H11 = {0}, H12 = {0}, H21 = {0}, H22 = {0}; + complex_t deltaH11 = {0}, deltaH12 = {0}, deltaH21 = {0}, deltaH22 = {0}; + complex_t tempLeft; + complex_t tempRight; + complex_t phaseLeft; + complex_t phaseRight; + real_t L; + const real_t* sf_iid; + uint8_t no_iid_steps; + if (ps->iid_mode >= 3) { + no_iid_steps = 15; + sf_iid = sf_iid_fine; + } else { + no_iid_steps = 7; + sf_iid = sf_iid_normal; + } + if (ps->ipd_mode == 0 || ps->ipd_mode == 3) { + nr_ipdopd_par = 11; /* resolution */ + } else { + nr_ipdopd_par = ps->nr_ipdopd_par; + } + for (gr = 0; gr < ps->num_groups; gr++) { + bk = (~NEGATE_IPD_MASK) & ps->map_group2bk[gr]; + /* use one channel per group in the subqmf domain */ + maxsb = (gr < ps->num_hybrid_groups) ? ps->group_border[gr] + 1 : ps->group_border[gr + 1]; + for (env = 0; env < ps->num_env; env++) { + if (ps->icc_mode < 3) { + /* type 'A' mixing as described in 8.6.4.6.2.1 */ + real_t c_1, c_2; + real_t cosa, sina; + real_t cosb, sinb; + real_t ab1, ab2; + real_t ab3, ab4; + /* + c_1 = sqrt(2.0 / (1.0 + pow(10.0, quant_iid[no_iid_steps + iid_index] / 10.0))); + c_2 = sqrt(2.0 / (1.0 + pow(10.0, quant_iid[no_iid_steps - iid_index] / 10.0))); + alpha = 0.5 * acos(quant_rho[icc_index]); + beta = alpha * ( c_1 - c_2 ) / sqrt(2.0); + */ + // printf("%d\n", ps->iid_index[env][bk]); + /* index range is supposed to be -7...7 or -15...15 depending on iid_mode + (Table 8.24, ISO/IEC 14496-3:2005). + if it is outside these boundaries, this is most likely an error. sanitize + it and try to process further. */ + if (ps->iid_index[env][bk] < -no_iid_steps) { + fprintf(stderr, "Warning: invalid iid_index: %d < %d\n", ps->iid_index[env][bk], -no_iid_steps); + ps->iid_index[env][bk] = -no_iid_steps; + } else if (ps->iid_index[env][bk] > no_iid_steps) { + fprintf(stderr, "Warning: invalid iid_index: %d > %d\n", ps->iid_index[env][bk], no_iid_steps); + ps->iid_index[env][bk] = no_iid_steps; + } + /* calculate the scalefactors c_1 and c_2 from the intensity differences */ + c_1 = sf_iid[no_iid_steps + ps->iid_index[env][bk]]; + c_2 = sf_iid[no_iid_steps - ps->iid_index[env][bk]]; + /* calculate alpha and beta using the ICC parameters */ + cosa = cos_alphas[ps->icc_index[env][bk]]; + sina = sin_alphas[ps->icc_index[env][bk]]; + if (ps->iid_mode >= 3) { + if (ps->iid_index[env][bk] < 0) { + cosb = cos_betas_fine[-ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sinb = -sin_betas_fine[-ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + } else { + cosb = cos_betas_fine[ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sinb = sin_betas_fine[ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + } + } else { + if (ps->iid_index[env][bk] < 0) { + cosb = cos_betas_normal[-ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sinb = -sin_betas_normal[-ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + } else { + cosb = cos_betas_normal[ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sinb = sin_betas_normal[ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + } + } + ab1 = MUL_C(cosb, cosa); + ab2 = MUL_C(sinb, sina); + ab3 = MUL_C(sinb, cosa); + ab4 = MUL_C(cosb, sina); + /* h_xy: COEF */ + RE(h11) = MUL_C(c_2, (ab1 - ab2)); + RE(h12) = MUL_C(c_1, (ab1 + ab2)); + RE(h21) = MUL_C(c_2, (ab3 + ab4)); + RE(h22) = MUL_C(c_1, (ab3 - ab4)); + } else { + /* type 'B' mixing as described in 8.6.4.6.2.2 */ + real_t sina, cosa; + real_t cosg, sing; + /* + real_t c, rho, mu, alpha, gamma; + uint8_t i; + i = ps->iid_index[env][bk]; + c = (real_t)pow(10.0, ((i)?(((i>0)?1:-1)*quant_iid[((i>0)?i:-i)-1]):0.)/20.0); + rho = quant_rho[ps->icc_index[env][bk]]; + if (rho == 0.0f && c == 1.) + { + alpha = (real_t)M_PI/4.0f; + rho = 0.05f; + } else { + if (rho <= 0.05f) + { + rho = 0.05f; + } + alpha = 0.5f*(real_t)atan( (2.0f*c*rho) / (c*c-1.0f) ); + if (alpha < 0.) + { + alpha += (real_t)M_PI/2.0f; + } + if (rho < 0.) + { + alpha += (real_t)M_PI; + } + } + mu = c+1.0f/c; + mu = 1+(4.0f*rho*rho-4.0f)/(mu*mu); + gamma = (real_t)atan(sqrt((1.0f-sqrt(mu))/(1.0f+sqrt(mu)))); + */ + if (ps->iid_mode >= 3) { + uint8_t abs_iid = abs(ps->iid_index[env][bk]); + cosa = sincos_alphas_B_fine[no_iid_steps + ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sina = sincos_alphas_B_fine[30 - (no_iid_steps + ps->iid_index[env][bk])][ps->icc_index[env][bk]]; + cosg = cos_gammas_fine[abs_iid][ps->icc_index[env][bk]]; + sing = sin_gammas_fine[abs_iid][ps->icc_index[env][bk]]; + } else { + uint8_t abs_iid = abs(ps->iid_index[env][bk]); + cosa = sincos_alphas_B_normal[no_iid_steps + ps->iid_index[env][bk]][ps->icc_index[env][bk]]; + sina = sincos_alphas_B_normal[14 - (no_iid_steps + ps->iid_index[env][bk])][ps->icc_index[env][bk]]; + cosg = cos_gammas_normal[abs_iid][ps->icc_index[env][bk]]; + sing = sin_gammas_normal[abs_iid][ps->icc_index[env][bk]]; + } + RE(h11) = MUL_C(COEF_SQRT2, MUL_C(cosa, cosg)); + RE(h12) = MUL_C(COEF_SQRT2, MUL_C(sina, cosg)); + RE(h21) = MUL_C(COEF_SQRT2, MUL_C(-cosa, sing)); + RE(h22) = MUL_C(COEF_SQRT2, MUL_C(sina, sing)); + } + /* calculate phase rotation parameters H_xy note that the imaginary part of these parameters are only calculated when IPD and OPD are enabled */ + if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par)) { + int8_t i; + real_t xy, pq, xypq; + /* ringbuffer index */ + i = ps->phase_hist; + /* previous value */ + #ifdef FIXED_POINT + /* divide by 4, shift right 2 bits */ + RE(tempLeft) = RE(ps->ipd_prev[bk][i]) >> 2; + IM(tempLeft) = IM(ps->ipd_prev[bk][i]) >> 2; + RE(tempRight) = RE(ps->opd_prev[bk][i]) >> 2; + IM(tempRight) = IM(ps->opd_prev[bk][i]) >> 2; + #else + RE(tempLeft) = MUL_F(RE(ps->ipd_prev[bk][i]), FRAC_CONST(0.25)); + IM(tempLeft) = MUL_F(IM(ps->ipd_prev[bk][i]), FRAC_CONST(0.25)); + RE(tempRight) = MUL_F(RE(ps->opd_prev[bk][i]), FRAC_CONST(0.25)); + IM(tempRight) = MUL_F(IM(ps->opd_prev[bk][i]), FRAC_CONST(0.25)); + #endif + /* save current value */ + RE(ps->ipd_prev[bk][i]) = ipdopd_cos_tab[abs(ps->ipd_index[env][bk])]; + IM(ps->ipd_prev[bk][i]) = ipdopd_sin_tab[abs(ps->ipd_index[env][bk])]; + RE(ps->opd_prev[bk][i]) = ipdopd_cos_tab[abs(ps->opd_index[env][bk])]; + IM(ps->opd_prev[bk][i]) = ipdopd_sin_tab[abs(ps->opd_index[env][bk])]; + /* add current value */ + RE(tempLeft) += RE(ps->ipd_prev[bk][i]); + IM(tempLeft) += IM(ps->ipd_prev[bk][i]); + RE(tempRight) += RE(ps->opd_prev[bk][i]); + IM(tempRight) += IM(ps->opd_prev[bk][i]); + /* ringbuffer index */ + if (i == 0) { i = 2; } + i--; + /* get value before previous */ + #ifdef FIXED_POINT + /* dividing by 2, shift right 1 bit */ + RE(tempLeft) += (RE(ps->ipd_prev[bk][i]) >> 1); + IM(tempLeft) += (IM(ps->ipd_prev[bk][i]) >> 1); + RE(tempRight) += (RE(ps->opd_prev[bk][i]) >> 1); + IM(tempRight) += (IM(ps->opd_prev[bk][i]) >> 1); + #else + RE(tempLeft) += MUL_F(RE(ps->ipd_prev[bk][i]), FRAC_CONST(0.5)); + IM(tempLeft) += MUL_F(IM(ps->ipd_prev[bk][i]), FRAC_CONST(0.5)); + RE(tempRight) += MUL_F(RE(ps->opd_prev[bk][i]), FRAC_CONST(0.5)); + IM(tempRight) += MUL_F(IM(ps->opd_prev[bk][i]), FRAC_CONST(0.5)); + #endif + #if 0 /* original code */ + ipd = (float)atan2(IM(tempLeft), RE(tempLeft)); + opd = (float)atan2(IM(tempRight), RE(tempRight)); + /* phase rotation */ + RE(phaseLeft) = (float)cos(opd); + IM(phaseLeft) = (float)sin(opd); + opd -= ipd; + RE(phaseRight) = (float)cos(opd); + IM(phaseRight) = (float)sin(opd); + #else + // x = IM(tempLeft) + // y = RE(tempLeft) + // p = IM(tempRight) + // q = RE(tempRight) + // cos(atan2(x,y)) = y/sqrt((x*x) + (y*y)) + // sin(atan2(x,y)) = x/sqrt((x*x) + (y*y)) + // cos(atan2(x,y)-atan2(p,q)) = (y*q + x*p) / ( sqrt((x*x) + (y*y)) * sqrt((p*p) + (q*q)) ); + // sin(atan2(x,y)-atan2(p,q)) = (x*q - y*p) / ( sqrt((x*x) + (y*y)) * sqrt((p*p) + (q*q)) ); + xy = magnitude_c(tempRight); + pq = magnitude_c(tempLeft); + if (xy != 0) { + RE(phaseLeft) = DIV_R(RE(tempRight), xy); + IM(phaseLeft) = DIV_R(IM(tempRight), xy); + } else { + RE(phaseLeft) = 0; + IM(phaseLeft) = 0; + } + xypq = MUL_R(xy, pq); + if (xypq != 0) { + real_t tmp1 = MUL_R(RE(tempRight), RE(tempLeft)) + MUL_R(IM(tempRight), IM(tempLeft)); + real_t tmp2 = MUL_R(IM(tempRight), RE(tempLeft)) - MUL_R(RE(tempRight), IM(tempLeft)); + RE(phaseRight) = DIV_R(tmp1, xypq); + IM(phaseRight) = DIV_R(tmp2, xypq); + } else { + RE(phaseRight) = 0; + IM(phaseRight) = 0; + } + #endif + /* MUL_F(COEF, REAL) = COEF */ + IM(h11) = MUL_R(RE(h11), IM(phaseLeft)); + IM(h12) = MUL_R(RE(h12), IM(phaseRight)); + IM(h21) = MUL_R(RE(h21), IM(phaseLeft)); + IM(h22) = MUL_R(RE(h22), IM(phaseRight)); + RE(h11) = MUL_R(RE(h11), RE(phaseLeft)); + RE(h12) = MUL_R(RE(h12), RE(phaseRight)); + RE(h21) = MUL_R(RE(h21), RE(phaseLeft)); + RE(h22) = MUL_R(RE(h22), RE(phaseRight)); + } + /* length of the envelope n_e+1 - n_e (in time samples) */ + /* 0 < L <= 32: integer */ + L = (real_t)(ps->border_position[env + 1] - ps->border_position[env]); + /* obtain final H_xy by means of linear interpolation */ + RE(deltaH11) = (RE(h11) - RE(ps->h11_prev[gr])) / L; + RE(deltaH12) = (RE(h12) - RE(ps->h12_prev[gr])) / L; + RE(deltaH21) = (RE(h21) - RE(ps->h21_prev[gr])) / L; + RE(deltaH22) = (RE(h22) - RE(ps->h22_prev[gr])) / L; + RE(H11) = RE(ps->h11_prev[gr]); + RE(H12) = RE(ps->h12_prev[gr]); + RE(H21) = RE(ps->h21_prev[gr]); + RE(H22) = RE(ps->h22_prev[gr]); + RE(ps->h11_prev[gr]) = RE(h11); + RE(ps->h12_prev[gr]) = RE(h12); + RE(ps->h21_prev[gr]) = RE(h21); + RE(ps->h22_prev[gr]) = RE(h22); + /* only calculate imaginary part when needed */ + if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par)) { + /* obtain final H_xy by means of linear interpolation */ + IM(deltaH11) = (IM(h11) - IM(ps->h11_prev[gr])) / L; + IM(deltaH12) = (IM(h12) - IM(ps->h12_prev[gr])) / L; + IM(deltaH21) = (IM(h21) - IM(ps->h21_prev[gr])) / L; + IM(deltaH22) = (IM(h22) - IM(ps->h22_prev[gr])) / L; + IM(H11) = IM(ps->h11_prev[gr]); + IM(H12) = IM(ps->h12_prev[gr]); + IM(H21) = IM(ps->h21_prev[gr]); + IM(H22) = IM(ps->h22_prev[gr]); + if ((NEGATE_IPD_MASK & ps->map_group2bk[gr]) != 0) { + IM(deltaH11) = -IM(deltaH11); + IM(deltaH12) = -IM(deltaH12); + IM(deltaH21) = -IM(deltaH21); + IM(deltaH22) = -IM(deltaH22); + IM(H11) = -IM(H11); + IM(H12) = -IM(H12); + IM(H21) = -IM(H21); + IM(H22) = -IM(H22); + } + IM(ps->h11_prev[gr]) = IM(h11); + IM(ps->h12_prev[gr]) = IM(h12); + IM(ps->h21_prev[gr]) = IM(h21); + IM(ps->h22_prev[gr]) = IM(h22); + } + /* apply H_xy to the current envelope band of the decorrelated subband */ + for (n = ps->border_position[env]; n < ps->border_position[env + 1]; n++) { + /* addition finalises the interpolation over every n */ + RE(H11) += RE(deltaH11); + RE(H12) += RE(deltaH12); + RE(H21) += RE(deltaH21); + RE(H22) += RE(deltaH22); + if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par)) { + IM(H11) += IM(deltaH11); + IM(H12) += IM(deltaH12); + IM(H21) += IM(deltaH21); + IM(H22) += IM(deltaH22); + } + /* channel is an alias to the subband */ + for (sb = ps->group_border[gr]; sb < maxsb; sb++) { + complex_t inLeft, inRight; + /* load decorrelated samples */ + if (gr < ps->num_hybrid_groups) { + RE(inLeft) = RE(X_hybrid_left[n][sb]); + IM(inLeft) = IM(X_hybrid_left[n][sb]); + RE(inRight) = RE(X_hybrid_right[n][sb]); + IM(inRight) = IM(X_hybrid_right[n][sb]); + } else { + RE(inLeft) = RE(X_left[n][sb]); + IM(inLeft) = IM(X_left[n][sb]); + RE(inRight) = RE(X_right[n][sb]); + IM(inRight) = IM(X_right[n][sb]); + } + /* apply mixing */ + RE(tempLeft) = MUL_C(RE(H11), RE(inLeft)) + MUL_C(RE(H21), RE(inRight)); + IM(tempLeft) = MUL_C(RE(H11), IM(inLeft)) + MUL_C(RE(H21), IM(inRight)); + RE(tempRight) = MUL_C(RE(H12), RE(inLeft)) + MUL_C(RE(H22), RE(inRight)); + IM(tempRight) = MUL_C(RE(H12), IM(inLeft)) + MUL_C(RE(H22), IM(inRight)); + /* only perform imaginary operations when needed */ + if ((ps->enable_ipdopd) && (bk < nr_ipdopd_par)) { + /* apply rotation */ + RE(tempLeft) -= MUL_C(IM(H11), IM(inLeft)) + MUL_C(IM(H21), IM(inRight)); + IM(tempLeft) += MUL_C(IM(H11), RE(inLeft)) + MUL_C(IM(H21), RE(inRight)); + RE(tempRight) -= MUL_C(IM(H12), IM(inLeft)) + MUL_C(IM(H22), IM(inRight)); + IM(tempRight) += MUL_C(IM(H12), RE(inLeft)) + MUL_C(IM(H22), RE(inRight)); + } + /* store final samples */ + if (gr < ps->num_hybrid_groups) { + RE(X_hybrid_left[n][sb]) = RE(tempLeft); + IM(X_hybrid_left[n][sb]) = IM(tempLeft); + RE(X_hybrid_right[n][sb]) = RE(tempRight); + IM(X_hybrid_right[n][sb]) = IM(tempRight); + } else { + RE(X_left[n][sb]) = RE(tempLeft); + IM(X_left[n][sb]) = IM(tempLeft); + RE(X_right[n][sb]) = RE(tempRight); + IM(X_right[n][sb]) = IM(tempRight); + } + } + } + /* shift phase smoother's circular buffer index */ + ps->phase_hist++; + if (ps->phase_hist == 2) { ps->phase_hist = 0; } + } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +void NeaacDecoder::ps_free(ps_info* ps) { + /* free hybrid filterbank structures */ + hybrid_free((hyb_info*)ps->hyb); + faad_free(&ps); +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +ps_info* NeaacDecoder::ps_init(uint8_t sr_index, uint8_t numTimeSlotsRate) { + uint8_t i; + uint8_t short_delay_band; + ps_info* ps = (ps_info*)faad_malloc(sizeof(ps_info)); + memset(ps, 0, sizeof(ps_info)); + ps->hyb = hybrid_init(numTimeSlotsRate); + ps->numTimeSlotsRate = numTimeSlotsRate; + ps->ps_data_available = 0; + /* delay stuff*/ + ps->saved_delay = 0; + for (i = 0; i < 64; i++) { ps->delay_buf_index_delay[i] = 0; } + for (i = 0; i < NO_ALLPASS_LINKS; i++) { + ps->delay_buf_index_ser[i] = 0; + #ifdef PARAM_32KHZ + if (sr_index <= 5) /* >= 32 kHz*/ + { + ps->num_sample_delay_ser[i] = delay_length_d[1][i]; + } else { + ps->num_sample_delay_ser[i] = delay_length_d[0][i]; + } + #else + /* THESE ARE CONSTANTS NOW */ + ps->num_sample_delay_ser[i] = delay_length_d[i]; + #endif + } + #ifdef PARAM_32KHZ + if (sr_index <= 5) /* >= 32 kHz*/ + { + short_delay_band = 35; + ps->nr_allpass_bands = 22; + ps->alpha_decay = FRAC_CONST(0.76592833836465); + ps->alpha_smooth = FRAC_CONST(0.25); + } else { + short_delay_band = 64; + ps->nr_allpass_bands = 45; + ps->alpha_decay = FRAC_CONST(0.58664621951003); + ps->alpha_smooth = FRAC_CONST(0.6); + } + #else + /* THESE ARE CONSTANTS NOW */ + short_delay_band = 35; + ps->nr_allpass_bands = 22; + ps->alpha_decay = FRAC_CONST(0.76592833836465); + ps->alpha_smooth = FRAC_CONST(0.25); + #endif + /* THESE ARE CONSTANT NOW IF PS IS INDEPENDANT OF SAMPLERATE */ + for (i = 0; i < short_delay_band; i++) { ps->delay_D[i] = 14; } + for (i = short_delay_band; i < 64; i++) { ps->delay_D[i] = 1; } + /* mixing and phase */ + for (i = 0; i < 50; i++) { + RE(ps->h11_prev[i]) = 1; + IM(ps->h12_prev[i]) = 1; + RE(ps->h11_prev[i]) = 1; + IM(ps->h12_prev[i]) = 1; + } + ps->phase_hist = 0; + for (i = 0; i < 20; i++) { + RE(ps->ipd_prev[i][0]) = 0; + IM(ps->ipd_prev[i][0]) = 0; + RE(ps->ipd_prev[i][1]) = 0; + IM(ps->ipd_prev[i][1]) = 0; + RE(ps->opd_prev[i][0]) = 0; + IM(ps->opd_prev[i][0]) = 0; + RE(ps->opd_prev[i][1]) = 0; + IM(ps->opd_prev[i][1]) = 0; + } + return ps; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* main Parametric Stereo decoding function */ +uint8_t NeaacDecoder::ps_decode(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64]) { + // qmf_t X_hybrid_left[32][32] = {{{0}}}; + // qmf_t X_hybrid_right[32][32] = {{{0}}}; + qmf_t(*X_hybrid_left)[32] = (qmf_t(*)[32])faad_calloc(32, 32 * sizeof(qmf_t)); + qmf_t(*X_hybrid_right)[32] = (qmf_t(*)[32])faad_calloc(32, 32 * sizeof(qmf_t)); + /* delta decoding of the bitstream data */ + ps_data_decode(ps); + /* set up some parameters depending on filterbank type */ + if (ps->use34hybrid_bands) { + ps->group_border = (uint8_t*)group_border34; + ps->map_group2bk = (uint16_t*)map_group2bk34; + ps->num_groups = 32 + 18; + ps->num_hybrid_groups = 32; + ps->nr_par_bands = 34; + ps->decay_cutoff = 5; + } else { + ps->group_border = (uint8_t*)group_border20; + ps->map_group2bk = (uint16_t*)map_group2bk20; + ps->num_groups = 10 + 12; + ps->num_hybrid_groups = 10; + ps->nr_par_bands = 20; + ps->decay_cutoff = 3; + } + /* Perform further analysis on the lowest subbands to get a higher frequency resolution */ + hybrid_analysis((hyb_info*)ps->hyb, X_left, X_hybrid_left, ps->use34hybrid_bands, ps->numTimeSlotsRate); + /* decorrelate mono signal */ + ps_decorrelate(ps, X_left, X_right, X_hybrid_left, X_hybrid_right); + /* apply mixing and phase parameters */ + ps_mix_phase(ps, X_left, X_right, X_hybrid_left, X_hybrid_right); + /* hybrid synthesis, to rebuild the SBR QMF matrices */ + hybrid_synthesis((hyb_info*)ps->hyb, X_left, X_hybrid_left, ps->use34hybrid_bands, ps->numTimeSlotsRate); + hybrid_synthesis((hyb_info*)ps->hyb, X_right, X_hybrid_right, ps->use34hybrid_bands, ps->numTimeSlotsRate); + faad_free((void**)&X_hybrid_left); + faad_free((void**)&X_hybrid_right); + return 0; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +uint16_t NeaacDecoder::ps_data(ps_info* ps, bitfile* ld, uint8_t* header) { + uint8_t tmp, n; + uint16_t bits = (uint16_t)faad_get_processed_bits(ld); + *header = 0; + /* check for new PS header */ + if (faad_get1bit(ld)) { + *header = 1; + ps->header_read = 1; + ps->use34hybrid_bands = 0; + /* Inter-channel Intensity Difference (IID) parameters enabled */ + ps->enable_iid = (uint8_t)faad_get1bit(ld); + if (ps->enable_iid) { + ps->iid_mode = (uint8_t)faad_getbits(ld, 3); + ps->nr_iid_par = nr_iid_par_tab[ps->iid_mode]; + ps->nr_ipdopd_par = nr_ipdopd_par_tab[ps->iid_mode]; + if (ps->iid_mode == 2 || ps->iid_mode == 5) ps->use34hybrid_bands = 1; + /* IPD freq res equal to IID freq res */ + ps->ipd_mode = ps->iid_mode; + } + /* Inter-channel Coherence (ICC) parameters enabled */ + ps->enable_icc = (uint8_t)faad_get1bit(ld); + if (ps->enable_icc) { + ps->icc_mode = (uint8_t)faad_getbits(ld, 3); + ps->nr_icc_par = nr_icc_par_tab[ps->icc_mode]; + if (ps->icc_mode == 2 || ps->icc_mode == 5) ps->use34hybrid_bands = 1; + } + /* PS extension layer enabled */ + ps->enable_ext = (uint8_t)faad_get1bit(ld); + } + /* we are here, but no header has been read yet */ + if (ps->header_read == 0) { + ps->ps_data_available = 0; + return 1; + } + ps->frame_class = (uint8_t)faad_get1bit(ld); + tmp = (uint8_t)faad_getbits(ld, 2); + ps->num_env = num_env_tab[ps->frame_class][tmp]; + if (ps->frame_class) { + for (n = 1; n < ps->num_env + 1; n++) { ps->border_position[n] = (uint8_t)faad_getbits(ld, 5) + 1; } + } + if (ps->enable_iid) { + for (n = 0; n < ps->num_env; n++) { + ps->iid_dt[n] = (uint8_t)faad_get1bit(ld); + /* iid_data */ + if (ps->iid_mode < 3) { + huff_data(ld, ps->iid_dt[n], ps->nr_iid_par, t_huff_iid_def, f_huff_iid_def, ps->iid_index[n]); + } else { + huff_data(ld, ps->iid_dt[n], ps->nr_iid_par, t_huff_iid_fine, f_huff_iid_fine, ps->iid_index[n]); + } + } + } + if (ps->enable_icc) { + for (n = 0; n < ps->num_env; n++) { + ps->icc_dt[n] = (uint8_t)faad_get1bit(ld); + /* icc_data */ + huff_data(ld, ps->icc_dt[n], ps->nr_icc_par, t_huff_icc, f_huff_icc, ps->icc_index[n]); + } + } + if (ps->enable_ext) { + uint16_t num_bits_left; + uint16_t cnt = (uint16_t)faad_getbits(ld, 4); + if (cnt == 15) { cnt += (uint16_t)faad_getbits(ld, 8); } + num_bits_left = 8 * cnt; + while (num_bits_left > 7) { + uint8_t ps_extension_id = (uint8_t)faad_getbits(ld, 2); + num_bits_left -= 2; + num_bits_left -= ps_extension(ps, ld, ps_extension_id, num_bits_left); + } + faad_getbits(ld, num_bits_left); + } + bits = (uint16_t)faad_get_processed_bits(ld) - bits; + ps->ps_data_available = 1; + return bits; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +uint16_t NeaacDecoder::ps_extension(ps_info* ps, bitfile* ld, const uint8_t ps_extension_id, const uint16_t num_bits_left) { + uint8_t n; + uint16_t bits = (uint16_t)faad_get_processed_bits(ld); + if (ps_extension_id == 0) { + ps->enable_ipdopd = (uint8_t)faad_get1bit(ld); + if (ps->enable_ipdopd) { + for (n = 0; n < ps->num_env; n++) { + ps->ipd_dt[n] = (uint8_t)faad_get1bit(ld); + /* ipd_data */ + huff_data(ld, ps->ipd_dt[n], ps->nr_ipdopd_par, t_huff_ipd, f_huff_ipd, ps->ipd_index[n]); + ps->opd_dt[n] = (uint8_t)faad_get1bit(ld); + /* opd_data */ + huff_data(ld, ps->opd_dt[n], ps->nr_ipdopd_par, t_huff_opd, f_huff_opd, ps->opd_index[n]); + } + } + faad_get1bit(ld); + } + /* return number of bits read */ + bits = (uint16_t)faad_get_processed_bits(ld) - bits; + return bits; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* binary search huffman decoding */ +int8_t NeaacDecoder::ps_huff_dec(bitfile* ld, ps_huff_tab t_huff) { + uint8_t bit; + int16_t index = 0; + while (index >= 0) { + bit = (uint8_t)faad_get1bit(ld); + index = t_huff[index][bit]; + } + return index + 31; +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef PS_DEC +/* read huffman data coded in either the frequency or the time direction */ +void NeaacDecoder::huff_data(bitfile* ld, const uint8_t dt, const uint8_t nr_par, ps_huff_tab t_huff, ps_huff_tab f_huff, int8_t* par) { + uint8_t n; + if (dt) { + /* coded in time direction */ + for (n = 0; n < nr_par; n++) { par[n] = ps_huff_dec(ld, t_huff); } + } else { + /* coded in frequency direction */ + par[0] = ps_huff_dec(ld, f_huff); + for (n = 1; n < nr_par; n++) { par[n] = ps_huff_dec(ld, f_huff); } + } +} +#endif // PS_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::ssr_ipqf(ssr_info* ssr, real_t* in_data, real_t* out_data, real_t buffer[SSR_BANDS][96 / 4], uint16_t frame_len, uint8_t bands) { + + real_t **pp_q0 = NULL, **pp_t0 = NULL, **pp_t1 = NULL; + real_t a_pqfproto[PQFTAPS]; + int i; + if (m_initFlag == 0) { + gc_set_protopqf(a_pqfproto); + gc_setcoef_eff_pqfsyn(SSR_BANDS, PQFTAPS / (2 * SSR_BANDS), a_pqfproto, &pp_q0, &pp_t0, &pp_t1); + m_initFlag = 1; + } + for (i = 0; i < frame_len / SSR_BANDS; i++) { + int l, n, k; + int mm = SSR_BANDS; + int kk = PQFTAPS / (2 * SSR_BANDS); + for (n = 0; n < mm; n++) { + for (k = 0; k < 2 * kk - 1; k++) { buffer[n][k] = buffer[n][k + 1]; } + } + for (n = 0; n < mm; n++) { + real_t acc = 0.0; + for (l = 0; l < mm; l++) { acc += pp_q0[n][l] * in_data[l * frame_len / SSR_BANDS + i]; } + buffer[n][2 * kk - 1] = acc; + } + for (n = 0; n < mm / 2; n++) { + real_t acc = 0.0; + for (k = 0; k < kk; k++) { acc += pp_t0[n][k] * buffer[n][2 * kk - 1 - 2 * k]; } + for (k = 0; k < kk; ++k) { acc += pp_t1[n][k] * buffer[n + mm / 2][2 * kk - 2 - 2 * k]; } + out_data[i * SSR_BANDS + n] = acc; + acc = 0.0; + for (k = 0; k < kk; k++) { acc += pp_t0[mm - 1 - n][k] * buffer[n][2 * kk - 1 - 2 * k]; } + for (k = 0; k < kk; k++) { acc -= pp_t1[mm - 1 - n][k] * buffer[n + mm / 2][2 * kk - 2 - 2 * k]; } + out_data[i * SSR_BANDS + mm - 1 - n] = acc; + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::gc_setcoef_eff_pqfsyn(int mm, int kk, real_t* p_proto, real_t*** ppp_q0, real_t*** ppp_t0, real_t*** ppp_t1) { + int i, k, n; + real_t w; + + /* Set 1st Mul&Acc Coef's */ + *ppp_q0 = (real_t**)calloc(mm, sizeof(real_t*)); + for (n = 0; n < mm; ++n) { (*ppp_q0)[n] = (real_t*)calloc(mm, sizeof(real_t)); } + for (n = 0; n < mm / 2; ++n) { + for (i = 0; i < mm; ++i) { + w = (2 * i + 1) * (2 * n + 1 - mm) * M_PI / (4 * mm); + (*ppp_q0)[n][i] = 2.0 * cos((real_t)w); + + w = (2 * i + 1) * (2 * (mm + n) + 1 - mm) * M_PI / (4 * mm); + (*ppp_q0)[n + mm / 2][i] = 2.0 * cos((real_t)w); + } + } + + /* Set 2nd Mul&Acc Coef's */ + *ppp_t0 = (real_t**)calloc(mm, sizeof(real_t*)); + *ppp_t1 = (real_t**)calloc(mm, sizeof(real_t*)); + for (n = 0; n < mm; ++n) { + (*ppp_t0)[n] = (real_t*)calloc(kk, sizeof(real_t)); + (*ppp_t1)[n] = (real_t*)calloc(kk, sizeof(real_t)); + } + for (n = 0; n < mm; ++n) { + for (k = 0; k < kk; ++k) { + (*ppp_t0)[n][k] = mm * p_proto[2 * k * mm + n]; + (*ppp_t1)[n][k] = mm * p_proto[(2 * k + 1) * mm + n]; + + if (k % 2 != 0) { + (*ppp_t0)[n][k] = -(*ppp_t0)[n][k]; + (*ppp_t1)[n][k] = -(*ppp_t1)[n][k]; + } + } + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +sbr_info* NeaacDecoder::sbrDecodeInit(uint16_t framelength, uint8_t id_aac, uint32_t sample_rate, uint8_t downSampledSBR, uint8_t IsDRM) { + sbr_info* sbr = (sbr_info*)faad_malloc(sizeof(sbr_info)); + memset(sbr, 0, sizeof(sbr_info)); + /* save id of the parent element */ + sbr->id_aac = id_aac; + sbr->sample_rate = sample_rate; + sbr->bs_freq_scale = 2; + sbr->bs_alter_scale = 1; + sbr->bs_noise_bands = 2; + sbr->bs_limiter_bands = 2; + sbr->bs_limiter_gains = 2; + sbr->bs_interpol_freq = 1; + sbr->bs_smoothing_mode = 1; + sbr->bs_start_freq = 5; + sbr->bs_amp_res = 1; + sbr->bs_samplerate_mode = 1; + sbr->prevEnvIsShort[0] = -1; + sbr->prevEnvIsShort[1] = -1; + sbr->header_count = 0; + sbr->Reset = 1; + #ifdef DRM + sbr->Is_DRM_SBR = IsDRM; + #endif + sbr->tHFGen = T_HFGEN; + sbr->tHFAdj = T_HFADJ; + sbr->bsco = 0; + sbr->bsco_prev = 0; + sbr->M_prev = 0; + sbr->frame_len = framelength; + /* force sbr reset */ + sbr->bs_start_freq_prev = -1; + if (framelength == 960) { + sbr->numTimeSlotsRate = RATE * NO_TIME_SLOTS_960; + sbr->numTimeSlots = NO_TIME_SLOTS_960; + } else if (framelength == 1024) { + sbr->numTimeSlotsRate = RATE * NO_TIME_SLOTS; + sbr->numTimeSlots = NO_TIME_SLOTS; + } else { + faad_free(&sbr); + return NULL; + } + sbr->GQ_ringbuf_index[0] = 0; + sbr->GQ_ringbuf_index[1] = 0; + if (id_aac == ID_CPE) { + /* stereo */ + uint8_t j; + sbr->qmfa[0] = qmfa_init(32); + sbr->qmfa[1] = qmfa_init(32); + sbr->qmfs[0] = qmfs_init((downSampledSBR) ? 32 : 64); + sbr->qmfs[1] = qmfs_init((downSampledSBR) ? 32 : 64); + for (j = 0; j < 5; j++) { + m_G_temp_prev[id_aac][0][j].alloc_array(64, "m_G_temp_prev[0]"); + sbr->G_temp_prev[0][j] = m_G_temp_prev[id_aac][0][j].get(); + m_G_temp_prev[id_aac][1][j].alloc_array(64, "m_G_temp_prev[1]"); + sbr->G_temp_prev[1][j] = m_G_temp_prev[id_aac][1][j].get(); + m_Q_temp_prev[id_aac][0][j].alloc_array(64, "m_Q_temp_prev[0]"); + sbr->Q_temp_prev[0][j] = m_Q_temp_prev[id_aac][0][j].get(); + m_Q_temp_prev[id_aac][1][j].alloc_array(64, "m_Q_temp_prev[1]"); + sbr->Q_temp_prev[1][j] = m_Q_temp_prev[id_aac][1][j].get(); + } + memset(sbr->Xsbr[0], 0, (sbr->numTimeSlotsRate + sbr->tHFGen) * 64 * sizeof(qmf_t)); + memset(sbr->Xsbr[1], 0, (sbr->numTimeSlotsRate + sbr->tHFGen) * 64 * sizeof(qmf_t)); + } else { + /* mono */ + uint8_t j; + sbr->qmfa[0] = qmfa_init(32); + sbr->qmfs[0] = qmfs_init((downSampledSBR) ? 32 : 64); + sbr->qmfs[1] = NULL; + for (j = 0; j < 5; j++) { + m_G_temp_prev[id_aac][0][j].alloc_array(64, "m_G_temp_prev"); + sbr->G_temp_prev[0][j] = m_G_temp_prev[id_aac][0][j].get(); + m_Q_temp_prev[id_aac][0][j].alloc_array(64, "m_Q_temp_prev"); + sbr->Q_temp_prev[0][j] = m_Q_temp_prev[id_aac][0][j].get(); + } + memset(sbr->Xsbr[0], 0, (sbr->numTimeSlotsRate + sbr->tHFGen) * 64 * sizeof(qmf_t)); + } + return sbr; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::sbrDecodeEnd(sbr_info* sbr, uint8_t i) { + uint8_t j; + if (sbr) { + qmfa_end(sbr->qmfa[0]); + qmfs_end(sbr->qmfs[0]); + if (sbr->qmfs[1] != NULL) { + qmfa_end(sbr->qmfa[1]); + qmfs_end(sbr->qmfs[1]); + } + for (j = 0; j < 5; j++) { + m_G_temp_prev[i][0][j].reset(); + sbr->G_temp_prev[0][j] = NULL; + m_Q_temp_prev[i][0][j].reset(); + sbr->Q_temp_prev[0][j] = NULL; + m_G_temp_prev[i][1][j].reset(); + sbr->G_temp_prev[1][j] = NULL; + m_Q_temp_prev[i][1][j].reset(); + sbr->Q_temp_prev[1][j] = NULL; + } + #ifdef PS_DEC + if (sbr->ps != NULL) ps_free(sbr->ps); + #endif + #ifdef DRM_PS + if (sbr->drm_ps != NULL) drm_ps_free(sbr->drm_ps); + #endif + faad_free(&sbr); + } +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::sbrReset(sbr_info* sbr, uint8_t i) { + uint8_t j; + if (sbr->qmfa[0] != NULL) memset(sbr->qmfa[0]->x, 0, 2 * sbr->qmfa[0]->channels * 10 * sizeof(real_t)); + if (sbr->qmfa[1] != NULL) memset(sbr->qmfa[1]->x, 0, 2 * sbr->qmfa[1]->channels * 10 * sizeof(real_t)); + if (sbr->qmfs[0] != NULL) memset(sbr->qmfs[0]->v, 0, 2 * sbr->qmfs[0]->channels * 20 * sizeof(real_t)); + if (sbr->qmfs[1] != NULL) memset(sbr->qmfs[1]->v, 0, 2 * sbr->qmfs[1]->channels * 20 * sizeof(real_t)); + for (j = 0; j < 5; j++) { + m_G_temp_prev[i][0][j].clear(); + m_G_temp_prev[i][1][j].clear(); + if (sbr->Q_temp_prev[0][j] != NULL) memset(sbr->Q_temp_prev[0][j], 0, 64 * sizeof(real_t)); + if (sbr->Q_temp_prev[1][j] != NULL) memset(sbr->Q_temp_prev[1][j], 0, 64 * sizeof(real_t)); + } + memset(sbr->Xsbr[0], 0, (sbr->numTimeSlotsRate + sbr->tHFGen) * 64 * sizeof(qmf_t)); + memset(sbr->Xsbr[1], 0, (sbr->numTimeSlotsRate + sbr->tHFGen) * 64 * sizeof(qmf_t)); + sbr->GQ_ringbuf_index[0] = 0; + sbr->GQ_ringbuf_index[1] = 0; + sbr->header_count = 0; + sbr->Reset = 1; + sbr->L_E_prev[0] = 0; + sbr->L_E_prev[1] = 0; + sbr->bs_freq_scale = 2; + sbr->bs_alter_scale = 1; + sbr->bs_noise_bands = 2; + sbr->bs_limiter_bands = 2; + sbr->bs_limiter_gains = 2; + sbr->bs_interpol_freq = 1; + sbr->bs_smoothing_mode = 1; + sbr->bs_start_freq = 5; + sbr->bs_amp_res = 1; + sbr->bs_samplerate_mode = 1; + sbr->prevEnvIsShort[0] = -1; + sbr->prevEnvIsShort[1] = -1; + sbr->bsco = 0; + sbr->bsco_prev = 0; + sbr->M_prev = 0; + sbr->bs_start_freq_prev = -1; + sbr->f_prev[0] = 0; + sbr->f_prev[1] = 0; + for (j = 0; j < MAX_M; j++) { + sbr->E_prev[0][j] = 0; + sbr->Q_prev[0][j] = 0; + sbr->E_prev[1][j] = 0; + sbr->Q_prev[1][j] = 0; + sbr->bs_add_harmonic_prev[0][j] = 0; + sbr->bs_add_harmonic_prev[1][j] = 0; + } + sbr->bs_add_harmonic_flag_prev[0] = 0; + sbr->bs_add_harmonic_flag_prev[1] = 0; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::sbr_save_prev_data(sbr_info* sbr, uint8_t ch) { + uint8_t i; + /* save data for next frame */ + sbr->kx_prev = sbr->kx; + sbr->M_prev = sbr->M; + sbr->bsco_prev = sbr->bsco; + sbr->L_E_prev[ch] = sbr->L_E[ch]; + /* sbr->L_E[ch] can become 0 on files with bit errors */ + if (sbr->L_E[ch] <= 0) return 19; + sbr->f_prev[ch] = sbr->f[ch][sbr->L_E[ch] - 1]; + for (i = 0; i < MAX_M; i++) { + sbr->E_prev[ch][i] = sbr->E[ch][i][sbr->L_E[ch] - 1]; + sbr->Q_prev[ch][i] = sbr->Q[ch][i][sbr->L_Q[ch] - 1]; + } + for (i = 0; i < MAX_M; i++) { sbr->bs_add_harmonic_prev[ch][i] = sbr->bs_add_harmonic[ch][i]; } + sbr->bs_add_harmonic_flag_prev[ch] = sbr->bs_add_harmonic_flag[ch]; + if (sbr->l_A[ch] == sbr->L_E[ch]) + sbr->prevEnvIsShort[ch] = 0; + else + sbr->prevEnvIsShort[ch] = -1; + return 0; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::sbr_save_matrix(sbr_info* sbr, uint8_t ch) { + uint8_t i; + for (i = 0; i < sbr->tHFGen; i++) { memmove(sbr->Xsbr[ch][i], sbr->Xsbr[ch][i + sbr->numTimeSlotsRate], 64 * sizeof(qmf_t)); } + for (i = sbr->tHFGen; i < MAX_NTSRHFG; i++) { memset(sbr->Xsbr[ch][i], 0, 64 * sizeof(qmf_t)); } +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::sbr_process_channel(sbr_info* sbr, real_t* channel_buf, qmf_t X[MAX_NTSR][64], uint8_t ch, uint8_t dont_process, const uint8_t downSampledSBR) { + int16_t k, l; + uint8_t ret = 0; + real_t deg[64]; + #ifdef DRM + if (sbr->Is_DRM_SBR) { + sbr->bsco = max((int32_t)sbr->maxAACLine * 32 / (int32_t)sbr->frame_len - (int32_t)sbr->kx, (int32_t)0); + } else { + #endif + sbr->bsco = 0; + #ifdef DRM + } + #endif + // #define PRE_QMF_PRINT + #ifdef PRE_QMF_PRINT + { + int i; + for (i = 0; i < 1024; i++) { printf("%d\n", channel_buf[i]); } + } + #endif + /* subband analysis */ + if (dont_process) + sbr_qmf_analysis_32(sbr, sbr->qmfa[ch], channel_buf, sbr->Xsbr[ch], sbr->tHFGen, 32); + else + sbr_qmf_analysis_32(sbr, sbr->qmfa[ch], channel_buf, sbr->Xsbr[ch], sbr->tHFGen, sbr->kx); + if (!dont_process) { + #if 1 + /* insert high frequencies here */ + /* hf generation using patching */ + hf_generation(sbr, sbr->Xsbr[ch], sbr->Xsbr[ch], deg, ch); + #endif + #if 0 // def SBR_LOW_POWER + for (l = sbr->t_E[ch][0]; l < sbr->t_E[ch][sbr->L_E[ch]]; l++) + { + for (k = 0; k < sbr->kx; k++) + { + QMF_RE(sbr->Xsbr[ch][sbr->tHFAdj + l][k]) = 0; + } + } + #endif + #if 1 + /* hf adjustment */ + ret = hf_adjustment(sbr, sbr->Xsbr[ch], deg, ch); + #endif + if (ret > 0) { dont_process = 1; } + } + if ((sbr->just_seeked != 0) || dont_process) { + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + for (k = 0; k < 32; k++) { + QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + #ifndef SBR_LOW_POWER + QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + #endif + } + for (k = 32; k < 64; k++) { + QMF_RE(X[l][k]) = 0; + #ifndef SBR_LOW_POWER + QMF_IM(X[l][k]) = 0; + #endif + } + } + } else { + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + uint8_t kx_band, M_band, bsco_band; + if (l < sbr->t_E[ch][0]) { + kx_band = sbr->kx_prev; + M_band = sbr->M_prev; + bsco_band = sbr->bsco_prev; + } else { + kx_band = sbr->kx; + M_band = sbr->M; + bsco_band = sbr->bsco; + } + #ifndef SBR_LOW_POWER + for (k = 0; k < kx_band + bsco_band; k++) { + QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + } + for (k = kx_band + bsco_band; k < kx_band + M_band; k++) { + QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); + } + for (k = max(kx_band + bsco_band, kx_band + M_band); k < 64; k++) { + QMF_RE(X[l][k]) = 0; + QMF_IM(X[l][k]) = 0; + } + #else + for (k = 0; k < kx_band + bsco_band; k++) { QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); } + for (k = kx_band + bsco_band; k < min(kx_band + M_band, 63); k++) { QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]); } + for (k = max(kx_band + bsco_band, kx_band + M_band); k < 64; k++) { QMF_RE(X[l][k]) = 0; } + /* kx_band can be 0 (kx_prev on the first frame's leading slots), which would make kx_band - 1 + bsco_band index X[l][-1]. There is no band below 0 to add in that case, so skip the overlap. */ + if (kx_band + bsco_band > 0) { QMF_RE(X[l][kx_band - 1 + bsco_band]) += QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][kx_band - 1 + bsco_band]); } + #endif + } + } + return ret; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::sbrDecodeCoupleFrame(sbr_info* sbr, real_t* left_chan, real_t* right_chan, const uint8_t just_seeked, const uint8_t downSampledSBR) { + uint8_t dont_process = 0; + uint8_t ret = 0; + // qmf_t X[MAX_NTSR][64]; + qmf_t(*X)[64] = (qmf_t(*)[64])faad_malloc(MAX_NTSR * 64 * sizeof(qmf_t)); + if (sbr == NULL) { + ret = 20; + goto exit; + } + /* case can occur due to bit errors */ + if (sbr->id_aac != ID_CPE) { + ret = 21; + goto exit; + } + if (sbr->ret || (sbr->header_count == 0)) { + /* don't process just upsample */ + dont_process = 1; + /* Re-activate reset for next frame */ + if (sbr->ret && sbr->Reset) sbr->bs_start_freq_prev = -1; + } + if (just_seeked) { + sbr->just_seeked = 1; + } else { + sbr->just_seeked = 0; + } + sbr->ret += sbr_process_channel(sbr, left_chan, X, 0, dont_process, downSampledSBR); + /* subband synthesis */ + if (downSampledSBR) { + sbr_qmf_synthesis_32(sbr, sbr->qmfs[0], X, left_chan); + } else { + sbr_qmf_synthesis_64(sbr, sbr->qmfs[0], X, left_chan); + } + sbr->ret += sbr_process_channel(sbr, right_chan, X, 1, dont_process, downSampledSBR); + /* subband synthesis */ + if (downSampledSBR) { + sbr_qmf_synthesis_32(sbr, sbr->qmfs[1], X, right_chan); + } else { + sbr_qmf_synthesis_64(sbr, sbr->qmfs[1], X, right_chan); + } + if (sbr->bs_header_flag) sbr->just_seeked = 0; + if (sbr->header_count != 0 && sbr->ret == 0) { + ret = sbr_save_prev_data(sbr, 0); + if (ret) goto exit; + ret = sbr_save_prev_data(sbr, 1); + if (ret) goto exit; + } + sbr_save_matrix(sbr, 0); + sbr_save_matrix(sbr, 1); + sbr->frame++; + // #define POST_QMF_PRINT + #ifdef POST_QMF_PRINT + { + int i; + for (i = 0; i < 2048; i++) { printf("%d\n", left_chan[i]); } + for (i = 0; i < 2048; i++) { printf("%d\n", right_chan[i]); } + } + #endif + ret = 0; +exit: + faad_free((void**)&(X)); + return ret; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::sbrDecodeSingleFrame(sbr_info* sbr, real_t* channel, const uint8_t just_seeked, const uint8_t downSampledSBR) { + uint8_t dont_process = 0; + uint8_t ret = 0; + // qmf_t X[MAX_NTSR][64]; + qmf_t(*X)[64] = (qmf_t(*)[64])faad_malloc(MAX_NTSR * 64 * sizeof(qmf_t)); + if (sbr == NULL) { + ret = 20; + goto exit; + } + /* case can occur due to bit errors */ + if (sbr->id_aac != ID_SCE && sbr->id_aac != ID_LFE) { + ret = 21; + goto exit; + } + if (sbr->ret || (sbr->header_count == 0)) { + /* don't process just upsample */ + dont_process = 1; + /* Re-activate reset for next frame */ + if (sbr->ret && sbr->Reset) sbr->bs_start_freq_prev = -1; + } + if (just_seeked) { + sbr->just_seeked = 1; + } else { + sbr->just_seeked = 0; + } + sbr->ret += sbr_process_channel(sbr, channel, X, 0, dont_process, downSampledSBR); + /* subband synthesis */ + if (downSampledSBR) { + sbr_qmf_synthesis_32(sbr, sbr->qmfs[0], X, channel); + } else { + sbr_qmf_synthesis_64(sbr, sbr->qmfs[0], X, channel); + } + if (sbr->bs_header_flag) sbr->just_seeked = 0; + if (sbr->header_count != 0 && sbr->ret == 0) { + ret = sbr_save_prev_data(sbr, 0); + if (ret) goto exit; + } + sbr_save_matrix(sbr, 0); + sbr->frame++; + // #define POST_QMF_PRINT + #ifdef POST_QMF_PRINT + { + int i; + for (i = 0; i < 2048; i++) { printf("%d\n", channel[i]); } + } + #endif + ret = 0; +exit: + faad_free((void**)&X); + return ret; +} +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #if (defined(PS_DEC) || defined(DRM_PS)) +uint8_t NeaacDecoder::sbrDecodeSingleFramePS(sbr_info* sbr, real_t* left_channel, real_t* right_channel, const uint8_t just_seeked, const uint8_t downSampledSBR) { + uint8_t l, k; + uint8_t dont_process = 0; + uint8_t ret = 0; + // qmf_t X_left[38][64] = {{{0}}}; + // qmf_t X_right[38][64] = {{{0}}}; /* must set this to 0 */ + qmf_t(*X_left)[64] = (qmf_t(*)[64])faad_calloc(38, 64 * sizeof(qmf_t)); + qmf_t(*X_right)[64] = (qmf_t(*)[64])faad_calloc(38, 64 * sizeof(qmf_t)); + if (sbr == NULL) { + ret = 20; + goto exit; + } + /* case can occur due to bit errors */ + if (sbr->id_aac != ID_SCE && sbr->id_aac != ID_LFE) { + ret = 21; + goto exit; + } + if (sbr->ret || (sbr->header_count == 0)) { + /* don't process just upsample */ + dont_process = 1; + /* Re-activate reset for next frame */ + if (sbr->ret && sbr->Reset) sbr->bs_start_freq_prev = -1; + } + if (just_seeked) { + sbr->just_seeked = 1; + } else { + sbr->just_seeked = 0; + } + if (sbr->qmfs[1] == NULL) { sbr->qmfs[1] = qmfs_init((downSampledSBR) ? 32 : 64); } + sbr->ret += sbr_process_channel(sbr, left_channel, X_left, 0, dont_process, downSampledSBR); + /* copy some extra data for PS */ + for (l = sbr->numTimeSlotsRate; l < sbr->numTimeSlotsRate + 6; l++) { + for (k = 0; k < 5; k++) { + QMF_RE(X_left[l][k]) = QMF_RE(sbr->Xsbr[0][sbr->tHFAdj + l][k]); + QMF_IM(X_left[l][k]) = QMF_IM(sbr->Xsbr[0][sbr->tHFAdj + l][k]); + } + } + /* perform parametric stereo */ + #ifdef DRM_PS + if (sbr->Is_DRM_SBR) { + drm_ps_decode(sbr->drm_ps, (sbr->ret > 0), X_left, X_right); + } else { + #endif + #ifdef PS_DEC + ps_decode(sbr->ps, X_left, X_right); + #endif + #ifdef DRM_PS + } + #endif + /* subband synthesis */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" + if (downSampledSBR) { + sbr_qmf_synthesis_32(sbr, sbr->qmfs[0], X_left, left_channel); + sbr_qmf_synthesis_32(sbr, sbr->qmfs[1], X_right, right_channel); + } else { + sbr_qmf_synthesis_64(sbr, sbr->qmfs[0], X_left, left_channel); + sbr_qmf_synthesis_64(sbr, sbr->qmfs[1], X_right, right_channel); + } + #pragma GCC diagnostic pop + if (sbr->bs_header_flag) sbr->just_seeked = 0; + if (sbr->header_count != 0 && sbr->ret == 0) { + ret = sbr_save_prev_data(sbr, 0); + if (ret) goto exit; + } + sbr_save_matrix(sbr, 0); + sbr->frame++; + ret = 0; +exit: + faad_free((void**)&X_left); + faad_free((void**)&X_right); + return ret; +} + #endif // (defined(PS_DEC) || defined(DRM_PS)) +#endif // #ifdef SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +/* size 64 only! */ +void NeaacDecoder::dct4_kernel(real_t* in_real, real_t* in_imag, real_t* out_real, real_t* out_imag) { + // Tables with bit reverse values for 5 bits, bit reverse of i at i-th position + const uint8_t bit_rev_tab[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; + uint32_t i, i_rev; + /* Step 2: modulate */ + // 3*32=96 multiplications + // 3*32=96 additions + for (i = 0; i < 32; i++) { + real_t x_re, x_im, tmp; + x_re = in_real[i]; + x_im = in_imag[i]; + tmp = MUL_C(x_re + x_im, dct4_64_tab[i]); + in_real[i] = MUL_C(x_im, dct4_64_tab[i + 64]) + tmp; + in_imag[i] = MUL_C(x_re, dct4_64_tab[i + 32]) + tmp; + } + /* Step 3: FFT, but with output in bit reverse order */ + fft_dif(in_real, in_imag); + /* Step 4: modulate + bitreverse reordering */ + // 3*31+2=95 multiplications + // 3*31+2=95 additions + for (i = 0; i < 16; i++) { + real_t x_re, x_im, tmp; + i_rev = bit_rev_tab[i]; + x_re = in_real[i_rev]; + x_im = in_imag[i_rev]; + tmp = MUL_C(x_re + x_im, dct4_64_tab[i + 3 * 32]); + out_real[i] = MUL_C(x_im, dct4_64_tab[i + 5 * 32]) + tmp; + out_imag[i] = MUL_C(x_re, dct4_64_tab[i + 4 * 32]) + tmp; + } + // i = 16, i_rev = 1 = rev(16); + out_imag[16] = MUL_C(in_imag[1] - in_real[1], dct4_64_tab[16 + 3 * 32]); + out_real[16] = MUL_C(in_real[1] + in_imag[1], dct4_64_tab[16 + 3 * 32]); + for (i = 17; i < 32; i++) { + real_t x_re, x_im, tmp; + i_rev = bit_rev_tab[i]; + x_re = in_real[i_rev]; + x_im = in_imag[i_rev]; + tmp = MUL_C(x_re + x_im, dct4_64_tab[i + 3 * 32]); + out_real[i] = MUL_C(x_im, dct4_64_tab[i + 5 * 32]) + tmp; + out_imag[i] = MUL_C(x_re, dct4_64_tab[i + 4 * 32]) + tmp; + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::extract_envelope_data(sbr_info* sbr, uint8_t ch) { + uint8_t l, k; + for (l = 0; l < sbr->L_E[ch]; l++) { + if (sbr->bs_df_env[ch][l] == 0) { + for (k = 1; k < sbr->n[sbr->f[ch][l]]; k++) { + sbr->E[ch][k][l] = sbr->E[ch][k - 1][l] + sbr->E[ch][k][l]; + if (sbr->E[ch][k][l] < 0) sbr->E[ch][k][l] = 0; + } + } else { /* bs_df_env == 1 */ + uint8_t g = (l == 0) ? sbr->f_prev[ch] : sbr->f[ch][l - 1]; + int16_t E_prev; + if (sbr->f[ch][l] == g) { + for (k = 0; k < sbr->n[sbr->f[ch][l]]; k++) { + if (l == 0) + E_prev = sbr->E_prev[ch][k]; + else + E_prev = sbr->E[ch][k][l - 1]; + sbr->E[ch][k][l] = E_prev + sbr->E[ch][k][l]; + } + } else if ((g == 1) && (sbr->f[ch][l] == 0)) { + uint8_t i; + for (k = 0; k < sbr->n[sbr->f[ch][l]]; k++) { + for (i = 0; i < sbr->N_high; i++) { + if (sbr->f_table_res[HI_RES][i] == sbr->f_table_res[LO_RES][k]) { + if (l == 0) + E_prev = sbr->E_prev[ch][i]; + else + E_prev = sbr->E[ch][i][l - 1]; + sbr->E[ch][k][l] = E_prev + sbr->E[ch][k][l]; + } + } + } + } else if ((g == 0) && (sbr->f[ch][l] == 1)) { + uint8_t i; + for (k = 0; k < sbr->n[sbr->f[ch][l]]; k++) { + for (i = 0; i < sbr->N_low; i++) { + if ((sbr->f_table_res[LO_RES][i] <= sbr->f_table_res[HI_RES][k]) && (sbr->f_table_res[HI_RES][k] < sbr->f_table_res[LO_RES][i + 1])) { + if (l == 0) + E_prev = sbr->E_prev[ch][i]; + else + E_prev = sbr->E[ch][i][l - 1]; + sbr->E[ch][k][l] = E_prev + sbr->E[ch][k][l]; + } + } + } + } + } + } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::extract_noise_floor_data(sbr_info* sbr, uint8_t ch) { + uint8_t l, k; + for (l = 0; l < sbr->L_Q[ch]; l++) { + if (sbr->bs_df_noise[ch][l] == 0) { + for (k = 1; k < sbr->N_Q; k++) { sbr->Q[ch][k][l] = sbr->Q[ch][k][l] + sbr->Q[ch][k - 1][l]; } + } else { + if (l == 0) { + for (k = 0; k < sbr->N_Q; k++) { sbr->Q[ch][k][l] = sbr->Q_prev[ch][k] + sbr->Q[ch][k][0]; } + } else { + for (k = 0; k < sbr->N_Q; k++) { sbr->Q[ch][k][l] = sbr->Q[ch][k][l - 1] + sbr->Q[ch][k][l]; } + } + } + } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +/* calculates 1/(1+Q) */ +/* [0..1] */ +real_t NeaacDecoder::calc_Q_div(sbr_info* sbr, uint8_t ch, uint8_t m, uint8_t l) { + if (sbr->bs_coupling) { + /* left channel */ + if ((sbr->Q[0][m][l] < 0 || sbr->Q[0][m][l] > 30) || (sbr->Q[1][m][l] < 0 || sbr->Q[1][m][l] > 24 /* 2*panOffset(1) */)) { + return 0; + } else { + /* the pan parameter is always even */ + if (ch == 0) { + return Q_div_tab_left[sbr->Q[0][m][l]][sbr->Q[1][m][l] >> 1]; + } else { + return Q_div_tab_right[sbr->Q[0][m][l]][sbr->Q[1][m][l] >> 1]; + } + } + } else { + /* no coupling */ + if (sbr->Q[ch][m][l] < 0 || sbr->Q[ch][m][l] > 30) { + return 0; + } else { + return Q_div_tab[sbr->Q[ch][m][l]]; + } + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +/* calculates Q/(1+Q) */ +/* [0..1] */ +real_t NeaacDecoder::calc_Q_div2(sbr_info* sbr, uint8_t ch, uint8_t m, uint8_t l) { + if (sbr->bs_coupling) { + if ((sbr->Q[0][m][l] < 0 || sbr->Q[0][m][l] > 30) || (sbr->Q[1][m][l] < 0 || sbr->Q[1][m][l] > 24 /* 2*panOffset(1) */)) { + return 0; + } else { + /* the pan parameter is always even */ + if (ch == 0) { + return Q_div2_tab_left[sbr->Q[0][m][l]][sbr->Q[1][m][l] >> 1]; + } else { + return Q_div2_tab_right[sbr->Q[0][m][l]][sbr->Q[1][m][l] >> 1]; + } + } + } else { + /* no coupling */ + if (sbr->Q[ch][m][l] < 0 || sbr->Q[ch][m][l] > 30) { + return 0; + } else { + return Q_div2_tab[sbr->Q[ch][m][l]]; + } + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +void NeaacDecoder::envelope_noise_dequantisation(sbr_info* sbr, uint8_t ch) { + if (sbr->bs_coupling == 0) { + int16_t exp; + uint8_t l, k; + uint8_t amp = (sbr->amp_res[ch]) ? 0 : 1; + for (l = 0; l < sbr->L_E[ch]; l++) { + for (k = 0; k < sbr->n[sbr->f[ch][l]]; k++) { + /* +6 for the *64 and -10 for the /32 in the synthesis QMF (fixed) + * since this is a energy value: (x/32)^2 = (x^2)/1024 + */ + /* exp = (sbr->E[ch][k][l] >> amp) + 6; */ + exp = (sbr->E[ch][k][l] >> amp); + if ((exp < 0) || (exp >= 64)) { + sbr->E_orig[ch][k][l] = 0; + } else { + sbr->E_orig[ch][k][l] = E_deq_tab[exp]; + /* save half the table size at the cost of 1 multiply */ + if (amp && (sbr->E[ch][k][l] & 1)) { sbr->E_orig[ch][k][l] = MUL_C(sbr->E_orig[ch][k][l], COEF_CONST(1.414213562)); } + } + } + } + for (l = 0; l < sbr->L_Q[ch]; l++) { + for (k = 0; k < sbr->N_Q; k++) { + sbr->Q_div[ch][k][l] = calc_Q_div(sbr, ch, k, l); + sbr->Q_div2[ch][k][l] = calc_Q_div2(sbr, ch, k, l); + } + } + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT +void NeaacDecoder::unmap_envelope_noise(sbr_info* sbr) { + real_t tmp; + int16_t exp0, exp1; + uint8_t l, k; + uint8_t amp0 = (sbr->amp_res[0]) ? 0 : 1; + uint8_t amp1 = (sbr->amp_res[1]) ? 0 : 1; + for (l = 0; l < sbr->L_E[0]; l++) { + for (k = 0; k < sbr->n[sbr->f[0][l]]; k++) { + /* +6: * 64 ; +1: * 2 ; */ + exp0 = (sbr->E[0][k][l] >> amp0) + 1; + /* UN_MAP removed: (x / 4096) same as (x >> 12) */ + /* E[1] is always even so no need for compensating the divide by 2 with + * an extra multiplication + */ + /* exp1 = (sbr->E[1][k][l] >> amp1) - 12; */ + exp1 = (sbr->E[1][k][l] >> amp1); + if ((exp0 < 0) || (exp0 >= 64) || (exp1 < 0) || (exp1 > 24)) { + sbr->E_orig[1][k][l] = 0; + sbr->E_orig[0][k][l] = 0; + } else { + tmp = E_deq_tab[exp0]; + if (amp0 && (sbr->E[0][k][l] & 1)) { tmp = MUL_C(tmp, COEF_CONST(1.414213562)); } + /* panning */ + sbr->E_orig[0][k][l] = MUL_F(tmp, E_pan_tab[exp1]); + sbr->E_orig[1][k][l] = MUL_F(tmp, E_pan_tab[24 - exp1]); + } + } + } + for (l = 0; l < sbr->L_Q[0]; l++) { + for (k = 0; k < sbr->N_Q; k++) { + sbr->Q_div[0][k][l] = calc_Q_div(sbr, 0, k, l); + sbr->Q_div[1][k][l] = calc_Q_div(sbr, 1, k, l); + sbr->Q_div2[0][k][l] = calc_Q_div2(sbr, 0, k, l); + sbr->Q_div2[1][k][l] = calc_Q_div2(sbr, 1, k, l); + } + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* calculate the start QMF channel for the master frequency band table parameter is also called k0 */ +uint8_t NeaacDecoder::qmf_start_channel(uint8_t bs_start_freq, uint8_t bs_samplerate_mode, uint32_t sample_rate) { + const uint8_t startMinTable[12] = {7, 7, 10, 11, 12, 16, 16, 17, 24, 32, 35, 48}; + const uint8_t offsetIndexTable[12] = {5, 5, 4, 4, 4, 3, 2, 1, 0, 6, 6, 6}; + const int8_t offset[7][16] = {{-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13}, + {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}, {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}, + {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20}, {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}, + {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33}}; + uint8_t startMin = startMinTable[get_sr_index(sample_rate)]; + uint8_t offsetIndex = offsetIndexTable[get_sr_index(sample_rate)]; + #if 0 /* replaced with table (startMinTable) */ + if (sample_rate >= 64000) + { + startMin = (uint8_t)((5000.*128.)/(float)sample_rate + 0.5); + } else if (sample_rate < 32000) { + startMin = (uint8_t)((3000.*128.)/(float)sample_rate + 0.5); + } else { + startMin = (uint8_t)((4000.*128.)/(float)sample_rate + 0.5); + } + #endif + if (bs_samplerate_mode) { + return startMin + offset[offsetIndex][bs_start_freq]; + #if 0 /* replaced by offsetIndexTable */ + switch (sample_rate) + { + case 16000: + return startMin + offset[0][bs_start_freq]; + case 22050: + return startMin + offset[1][bs_start_freq]; + case 24000: + return startMin + offset[2][bs_start_freq]; + case 32000: + return startMin + offset[3][bs_start_freq]; + default: + if (sample_rate > 64000) + { + return startMin + offset[5][bs_start_freq]; + } else { /* 44100 <= sample_rate <= 64000 */ + return startMin + offset[4][bs_start_freq]; + } + } + #endif + } else { + return startMin + offset[6][bs_start_freq]; + } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* calculate the stop QMF channel for the master frequency band table */ +/* parameter is also called k2 */ +uint8_t NeaacDecoder::qmf_stop_channel(uint8_t bs_stop_freq, uint32_t sample_rate, uint8_t k0) { + + if (bs_stop_freq == 15) { + return min(64, k0 * 3); + } else if (bs_stop_freq == 14) { + return min(64, k0 * 2); + } else { + const uint8_t stopMinTable[12] = {13, 15, 20, 21, 23, 32, 32, 35, 48, 64, 70, 96}; + const int8_t offset[12][14] = { + {0, 2, 4, 6, 8, 11, 14, 18, 22, 26, 31, 37, 44, 51}, {0, 2, 4, 6, 8, 11, 14, 18, 22, 26, 31, 36, 42, 49}, {0, 2, 4, 6, 8, 11, 14, 17, 21, 25, 29, 34, 39, 44}, + {0, 2, 4, 6, 8, 11, 14, 17, 20, 24, 28, 33, 38, 43}, {0, 2, 4, 6, 8, 11, 14, 17, 20, 24, 28, 32, 36, 41}, {0, 2, 4, 6, 8, 10, 12, 14, 17, 20, 23, 26, 29, 32}, + {0, 2, 4, 6, 8, 10, 12, 14, 17, 20, 23, 26, 29, 32}, {0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 20, 23, 26, 29}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, -1, -2, -3, -4, -5, -6, -6, -6, -6, -6, -6, -6, -6}, {0, -3, -6, -9, -12, -15, -18, -20, -22, -24, -26, -28, -30, -32}}; + #if 0 + uint8_t i; + int32_t stopDk[13], stopDk_t[14], k2; + #endif + uint8_t stopMin = stopMinTable[get_sr_index(sample_rate)]; + #if 0 /* replaced by table lookup */ + if (sample_rate >= 64000) + { + stopMin = (uint8_t)((10000.*128.)/(float)sample_rate + 0.5); + } else if (sample_rate < 32000) { + stopMin = (uint8_t)((6000.*128.)/(float)sample_rate + 0.5); + } else { + stopMin = (uint8_t)((8000.*128.)/(float)sample_rate + 0.5); + } + #endif + /* bs_stop_freq <= 13 */ + return min(64, stopMin + offset[get_sr_index(sample_rate)][min(bs_stop_freq, (uint8_t)13)]); + } + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* calculate the master frequency table from k0, k2, bs_freq_scale and bs_alter_scale version for bs_freq_scale = 0*/ +uint8_t NeaacDecoder::master_frequency_table_fs0(sbr_info* sbr, uint8_t k0, uint8_t k2, uint8_t bs_alter_scale) { + int8_t incr; + uint8_t k; + uint8_t dk; + uint32_t nrBands, k2Achieved; + int32_t k2Diff, vDk[64] = {0}; + /* mft only defined for k2 > k0 */ + if (k2 <= k0) { + sbr->N_master = 0; + return 1; + } + dk = bs_alter_scale ? 2 : 1; + #if 0 /* replaced by float-less design */ + nrBands = 2 * (int32_t)((float)(k2-k0)/(dk*2) + (-1+dk)/2.0f); + #else + if (bs_alter_scale) { + nrBands = (((k2 - k0 + 2) >> 2) << 1); + } else { + nrBands = (((k2 - k0) >> 1) << 1); + } + #endif + nrBands = min(nrBands, (uint32_t)63); + if (nrBands <= 0) return 1; + k2Achieved = k0 + nrBands * dk; + k2Diff = k2 - k2Achieved; + for (k = 0; k < nrBands; k++) vDk[k] = dk; + if (k2Diff) { + incr = (k2Diff > 0) ? -1 : 1; + k = (uint8_t)((k2Diff > 0) ? (nrBands - 1) : 0); + while (k2Diff != 0) { + vDk[k] -= incr; + k += incr; + k2Diff += incr; + } + } + sbr->f_master[0] = k0; + for (k = 1; k <= nrBands; k++) sbr->f_master[k] = (uint8_t)(sbr->f_master[k - 1] + vDk[k - 1]); + sbr->N_master = (uint8_t)nrBands; + sbr->N_master = (min(sbr->N_master, (uint8_t)64)); + #if 0 + printf("f_master[%d]: ", nrBands); + for (k = 0; k <= nrBands; k++) + { + printf("%d ", sbr->f_master[k]); + } + printf("\n"); + #endif + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* This function finds the number of bands using this formula: bands * log(a1/a0)/log(2.0) + 0.5*/ +int32_t NeaacDecoder::find_bands(uint8_t warp, uint8_t bands, uint8_t a0, uint8_t a1) { + #ifdef FIXED_POINT + /* table with log2() values */ + const real_t log2Table[65] = {COEF_CONST(0.0), COEF_CONST(0.0), COEF_CONST(1.0000000000), COEF_CONST(1.5849625007), COEF_CONST(2.0000000000), COEF_CONST(2.3219280949), + COEF_CONST(2.5849625007), COEF_CONST(2.8073549221), COEF_CONST(3.0000000000), COEF_CONST(3.1699250014), COEF_CONST(3.3219280949), COEF_CONST(3.4594316186), + COEF_CONST(3.5849625007), COEF_CONST(3.7004397181), COEF_CONST(3.8073549221), COEF_CONST(3.9068905956), COEF_CONST(4.0000000000), COEF_CONST(4.0874628413), + COEF_CONST(4.1699250014), COEF_CONST(4.2479275134), COEF_CONST(4.3219280949), COEF_CONST(4.3923174228), COEF_CONST(4.4594316186), COEF_CONST(4.5235619561), + COEF_CONST(4.5849625007), COEF_CONST(4.6438561898), COEF_CONST(4.7004397181), COEF_CONST(4.7548875022), COEF_CONST(4.8073549221), COEF_CONST(4.8579809951), + COEF_CONST(4.9068905956), COEF_CONST(4.9541963104), COEF_CONST(5.0000000000), COEF_CONST(5.0443941194), COEF_CONST(5.0874628413), COEF_CONST(5.1292830169), + COEF_CONST(5.1699250014), COEF_CONST(5.2094533656), COEF_CONST(5.2479275134), COEF_CONST(5.2854022189), COEF_CONST(5.3219280949), COEF_CONST(5.3575520046), + COEF_CONST(5.3923174228), COEF_CONST(5.4262647547), COEF_CONST(5.4594316186), COEF_CONST(5.4918530963), COEF_CONST(5.5235619561), COEF_CONST(5.5545888517), + COEF_CONST(5.5849625007), COEF_CONST(5.6147098441), COEF_CONST(5.6438561898), COEF_CONST(5.6724253420), COEF_CONST(5.7004397181), COEF_CONST(5.7279204546), + COEF_CONST(5.7548875022), COEF_CONST(5.7813597135), COEF_CONST(5.8073549221), COEF_CONST(5.8328900142), COEF_CONST(5.8579809951), COEF_CONST(5.8826430494), + COEF_CONST(5.9068905956), COEF_CONST(5.9307373376), COEF_CONST(5.9541963104), COEF_CONST(5.9772799235), COEF_CONST(6.0)}; + real_t r0 = log2Table[a0]; /* coef */ + real_t r1 = log2Table[a1]; /* coef */ + real_t r2 = (r1 - r0); /* coef */ + if (warp) r2 = MUL_C(r2, COEF_CONST(1.0 / 1.3)); + /* convert r2 to real and then multiply and round */ + r2 = (r2 >> (COEF_BITS - REAL_BITS)) * bands + (1 << (REAL_BITS - 1)); + return (r2 >> REAL_BITS); + #else + real_t div = (real_t)log(2.0); + if (warp) div *= (real_t)1.3; + return (int32_t)(bands * log((float)a1 / (float)a0) / div + 0.5); + #endif +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +real_t NeaacDecoder::find_initial_power(uint8_t bands, uint8_t a0, uint8_t a1) { + #ifdef FIXED_POINT + /* table with log() values */ + const real_t logTable[65] = {COEF_CONST(0.0), COEF_CONST(0.0), COEF_CONST(0.6931471806), COEF_CONST(1.0986122887), COEF_CONST(1.3862943611), COEF_CONST(1.6094379124), + COEF_CONST(1.7917594692), COEF_CONST(1.9459101491), COEF_CONST(2.0794415417), COEF_CONST(2.1972245773), COEF_CONST(2.3025850930), COEF_CONST(2.3978952728), + COEF_CONST(2.4849066498), COEF_CONST(2.5649493575), COEF_CONST(2.6390573296), COEF_CONST(2.7080502011), COEF_CONST(2.7725887222), COEF_CONST(2.8332133441), + COEF_CONST(2.8903717579), COEF_CONST(2.9444389792), COEF_CONST(2.9957322736), COEF_CONST(3.0445224377), COEF_CONST(3.0910424534), COEF_CONST(3.1354942159), + COEF_CONST(3.1780538303), COEF_CONST(3.2188758249), COEF_CONST(3.2580965380), COEF_CONST(3.2958368660), COEF_CONST(3.3322045102), COEF_CONST(3.3672958300), + COEF_CONST(3.4011973817), COEF_CONST(3.4339872045), COEF_CONST(3.4657359028), COEF_CONST(3.4965075615), COEF_CONST(3.5263605246), COEF_CONST(3.5553480615), + COEF_CONST(3.5835189385), COEF_CONST(3.6109179126), COEF_CONST(3.6375861597), COEF_CONST(3.6635616461), COEF_CONST(3.6888794541), COEF_CONST(3.7135720667), + COEF_CONST(3.7376696183), COEF_CONST(3.7612001157), COEF_CONST(3.7841896339), COEF_CONST(3.8066624898), COEF_CONST(3.8286413965), COEF_CONST(3.8501476017), + COEF_CONST(3.8712010109), COEF_CONST(3.8918202981), COEF_CONST(3.9120230054), COEF_CONST(3.9318256327), COEF_CONST(3.9512437186), COEF_CONST(3.9702919136), + COEF_CONST(3.9889840466), COEF_CONST(4.0073331852), COEF_CONST(4.0253516907), COEF_CONST(4.0430512678), COEF_CONST(4.0604430105), COEF_CONST(4.0775374439), + COEF_CONST(4.0943445622), COEF_CONST(4.1108738642), COEF_CONST(4.1271343850), COEF_CONST(4.1431347264), COEF_CONST(4.158883083)}; + /* standard Taylor polynomial coefficients for exp(x) around 0 */ + /* a polynomial around x=1 is more precise, as most values are around 1.07, + but this is just fine already */ + const real_t c1 = COEF_CONST(1.0); + const real_t c2 = COEF_CONST(1.0 / 2.0); + const real_t c3 = COEF_CONST(1.0 / 6.0); + const real_t c4 = COEF_CONST(1.0 / 24.0); + real_t r0 = logTable[a0]; /* coef */ + real_t r1 = logTable[a1]; /* coef */ + real_t r2 = (r1 - r0) / bands; /* coef */ + real_t rexp = c1 + MUL_C((c1 + MUL_C((c2 + MUL_C((c3 + MUL_C(c4, r2)), r2)), r2)), r2); + return (rexp >> (COEF_BITS - REAL_BITS)); /* real */ + #else + return (real_t)pow((real_t)a1 / (real_t)a0, 1.0 / (real_t)bands); + #endif +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* version for bs_freq_scale > 0*/ +uint8_t NeaacDecoder::master_frequency_table(sbr_info* sbr, uint8_t k0, uint8_t k2, uint8_t bs_freq_scale, uint8_t bs_alter_scale) { + + auto longcmp = [](const void* a, const void* b) -> int { return ((int)(*(int32_t*)a - *(int32_t*)b)); }; + + uint8_t k, bands, twoRegions; + uint8_t k1, ret = 0; + uint8_t nrBand0, nrBand1; + // int32_t vDk0[64] = {0}, vDk1[64] = {0}; + // int32_t vk0[64] = {0}, vk1[64] = {0}; + int32_t* vDk0 = (int32_t*)faad_calloc(64, sizeof(int32_t)); + int32_t* vDk1 = (int32_t*)faad_calloc(64, sizeof(int32_t)); + int32_t* vk0 = (int32_t*)faad_calloc(64, sizeof(int32_t)); + int32_t* vk1 = (int32_t*)faad_calloc(64, sizeof(int32_t)); + uint8_t temp1[] = {6, 5, 4}; + real_t q, qk; + int32_t A_1; + #ifdef FIXED_POINT + real_t rk2, rk0; + #endif + /* mft only defined for k2 > k0 */ + if (k2 <= k0) { + sbr->N_master = 0; + ret = 1; + goto exit; + } + bands = temp1[bs_freq_scale - 1]; + #ifdef FIXED_POINT + rk0 = (real_t)k0 << REAL_BITS; + rk2 = (real_t)k2 << REAL_BITS; + if (rk2 > MUL_C(rk0, COEF_CONST(2.2449))) + #else + if ((float)k2 / (float)k0 > 2.2449) + #endif + { + twoRegions = 1; + k1 = k0 << 1; + } else { + twoRegions = 0; + k1 = k2; + } + nrBand0 = (uint8_t)(2 * find_bands(0, bands, k0, k1)); + nrBand0 = min(nrBand0, (uint8_t)63); + if (nrBand0 <= 0) { + ret = 1; + goto exit; + } + q = find_initial_power(nrBand0, k0, k1); + #ifdef FIXED_POINT + qk = (real_t)k0 << REAL_BITS; + // A_1 = (int32_t)((qk + REAL_CONST(0.5)) >> REAL_BITS); + A_1 = k0; + #else + qk = REAL_CONST(k0); + A_1 = (int32_t)(qk + .5); + #endif + for (k = 0; k <= nrBand0; k++) { + int32_t A_0 = A_1; + #ifdef FIXED_POINT + qk = MUL_R(qk, q); + A_1 = (int32_t)((qk + REAL_CONST(0.5)) >> REAL_BITS); + #else + qk *= q; + A_1 = (int32_t)(qk + 0.5); + #endif + vDk0[k] = A_1 - A_0; + } + /* needed? */ + qsort(vDk0, nrBand0, sizeof(vDk0[0]), longcmp); + + // instead qsort and longcmp + // std::sort(vDk0, vDk0 + nrBand0, [](int32_t a, int32_t b) { + // return a < b; + // }); + + vk0[0] = k0; + for (k = 1; k <= nrBand0; k++) { + vk0[k] = vk0[k - 1] + vDk0[k - 1]; + if (vDk0[k - 1] == 0) { + ret = 1; + goto exit; + } + } + if (!twoRegions) { + for (k = 0; k <= nrBand0; k++) sbr->f_master[k] = (uint8_t)vk0[k]; + sbr->N_master = nrBand0; + sbr->N_master = min(sbr->N_master, (uint8_t)64); + ret = 0; + goto exit; + } + nrBand1 = (uint8_t)(2 * find_bands(1 /* warped */, bands, k1, k2)); + nrBand1 = min(nrBand1, (uint8_t)63); + q = find_initial_power(nrBand1, k1, k2); + #ifdef FIXED_POINT + qk = (real_t)k1 << REAL_BITS; + // A_1 = (int32_t)((qk + REAL_CONST(0.5)) >> REAL_BITS); + A_1 = k1; + #else + qk = REAL_CONST(k1); + A_1 = (int32_t)(qk + .5); + #endif + for (k = 0; k <= nrBand1 - 1; k++) { + int32_t A_0 = A_1; + #ifdef FIXED_POINT + qk = MUL_R(qk, q); + A_1 = (int32_t)((qk + REAL_CONST(0.5)) >> REAL_BITS); + #else + qk *= q; + A_1 = (int32_t)(qk + 0.5); + #endif + vDk1[k] = A_1 - A_0; + } + if (vDk1[0] < vDk0[nrBand0 - 1]) { + int32_t change; + /* needed? */ + qsort(vDk1, nrBand1 + 1, sizeof(vDk1[0]), longcmp); + change = vDk0[nrBand0 - 1] - vDk1[0]; + vDk1[0] = vDk0[nrBand0 - 1]; + vDk1[nrBand1 - 1] = vDk1[nrBand1 - 1] - change; + } + /* needed? */ + qsort(vDk1, nrBand1, sizeof(vDk1[0]), longcmp); + vk1[0] = k1; + for (k = 1; k <= nrBand1; k++) { + vk1[k] = vk1[k - 1] + vDk1[k - 1]; + if (vDk1[k - 1] == 0) { + ret = 1; + goto exit; + } + } + sbr->N_master = nrBand0 + nrBand1; + sbr->N_master = min(sbr->N_master, (uint8_t)64); + for (k = 0; k <= nrBand0; k++) { sbr->f_master[k] = (uint8_t)vk0[k]; } + for (k = nrBand0 + 1; k <= sbr->N_master; k++) { sbr->f_master[k] = (uint8_t)vk1[k - nrBand0]; } + #if 0 + printf("f_master[%d]: ", sbr->N_master); + for (k = 0; k <= sbr->N_master; k++) + { + printf("%d ", sbr->f_master[k]); + } + printf("\n"); + #endif + ret = 0; +exit: + faad_free(&vDk0); + faad_free(&vDk1); + faad_free(&vk0); + faad_free(&vk1); + return ret; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* calculate the derived frequency border tables from f_master */ +uint8_t NeaacDecoder::derived_frequency_table(sbr_info* sbr, uint8_t bs_xover_band, uint8_t k2) { + uint8_t k, i; + uint32_t minus; + /* The following relation shall be satisfied: bs_xover_band < N_Master */ + if (sbr->N_master <= bs_xover_band) return 1; + sbr->N_high = sbr->N_master - bs_xover_band; + sbr->N_low = (sbr->N_high >> 1) + (sbr->N_high - ((sbr->N_high >> 1) << 1)); + sbr->n[0] = sbr->N_low; + sbr->n[1] = sbr->N_high; + for (k = 0; k <= sbr->N_high; k++) { sbr->f_table_res[HI_RES][k] = sbr->f_master[k + bs_xover_band]; } + sbr->M = sbr->f_table_res[HI_RES][sbr->N_high] - sbr->f_table_res[HI_RES][0]; + if (sbr->M > MAX_M) return 1; + sbr->kx = sbr->f_table_res[HI_RES][0]; + if (sbr->kx > 32) return 1; + if (sbr->kx + sbr->M > 64) return 1; + minus = (sbr->N_high & 1) ? 1 : 0; + for (k = 0; k <= sbr->N_low; k++) { + if (k == 0) + i = 0; + else + i = (uint8_t)(2 * k - minus); + sbr->f_table_res[LO_RES][k] = sbr->f_table_res[HI_RES][i]; + } + #if 0 + printf("bs_freq_scale: %d\n", sbr->bs_freq_scale); + printf("bs_limiter_bands: %d\n", sbr->bs_limiter_bands); + printf("f_table_res[HI_RES][%d]: ", sbr->N_high); + for (k = 0; k <= sbr->N_high; k++) + { + printf("%d ", sbr->f_table_res[HI_RES][k]); + } + printf("\n"); + #endif + #if 0 + printf("f_table_res[LO_RES][%d]: ", sbr->N_low); + for (k = 0; k <= sbr->N_low; k++) + { + printf("%d ", sbr->f_table_res[LO_RES][k]); + } + printf("\n"); + #endif + sbr->N_Q = 0; + if (sbr->bs_noise_bands == 0) { + sbr->N_Q = 1; + } else { + #if 0 + sbr->N_Q = max(1, (int32_t)(sbr->bs_noise_bands*(log(k2/(float)sbr->kx)/log(2.0)) + 0.5)); + #else + sbr->N_Q = (uint8_t)(max((int32_t)1, find_bands(0, sbr->bs_noise_bands, sbr->kx, k2))); + #endif + sbr->N_Q = min((uint8_t)5, sbr->N_Q); + } + for (k = 0; k <= sbr->N_Q; k++) { + if (k == 0) { + i = 0; + } else { + /* i = i + (int32_t)((sbr->N_low - i)/(sbr->N_Q + 1 - k)); */ + i = i + (sbr->N_low - i) / (sbr->N_Q + 1 - k); + } + sbr->f_table_noise[k] = sbr->f_table_res[LO_RES][i]; + } + /* build table for mapping k to g in hf patching */ + for (k = 0; k < 64; k++) { + uint8_t g; + for (g = 0; g < sbr->N_Q; g++) { + if ((sbr->f_table_noise[g] <= k) && (k < sbr->f_table_noise[g + 1])) { + sbr->table_map_k_to_g[k] = g; + break; + } + } + } + #if 0 + printf("f_table_noise[%d]: ", sbr->N_Q); + for (k = 0; k <= sbr->N_Q; k++) + { + printf("%d ", sbr->f_table_noise[k] - sbr->kx); + } + printf("\n"); + #endif + return 0; +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* TODO: blegh, ugly */ +/* Modified to calculate for all possible bs_limiter_bands always + * This reduces the number calls to this functions needed (now only on header reset) */ +void NeaacDecoder::limiter_frequency_table(sbr_info* sbr) { + + auto longcmp = [](const void* a, const void* b) -> int { return ((int)(*(int32_t*)a - *(int32_t*)b)); }; + + const real_t limiterBandsCompare[] = {REAL_CONST(1.327152), REAL_CONST(1.185093), REAL_CONST(1.119872)}; + + uint8_t k, s; + int8_t nrLim; + #if 0 + real_t limBands; + #endif + sbr->f_table_lim[0][0] = sbr->f_table_res[LO_RES][0] - sbr->kx; + sbr->f_table_lim[0][1] = sbr->f_table_res[LO_RES][sbr->N_low] - sbr->kx; + sbr->N_L[0] = 1; + #if 0 + printf("f_table_lim[%d][%d]: ", 0, sbr->N_L[0]); + for (k = 0; k <= sbr->N_L[0]; k++) + { + printf("%d ", sbr->f_table_lim[0][k]); + } + printf("\n"); + #endif + int32_t* limTable = (int32_t*)faad_malloc(100 * sizeof(int32_t)); + uint8_t* patchBorders = (uint8_t*)faad_malloc(64 * sizeof(uint8_t)); + for (s = 1; s < 4; s++) { + memset(limTable, 0, 100 * sizeof(int32_t)); + memset(patchBorders, 0, 64 * sizeof(uint8_t)); + #if 0 + limBands = limiterBandsPerOctave[s - 1]; + #endif + patchBorders[0] = sbr->kx; + for (k = 1; k <= sbr->noPatches; k++) { patchBorders[k] = patchBorders[k - 1] + sbr->patchNoSubbands[k - 1]; } + for (k = 0; k <= sbr->N_low; k++) { limTable[k] = sbr->f_table_res[LO_RES][k]; } + for (k = 1; k < sbr->noPatches; k++) { limTable[k + sbr->N_low] = patchBorders[k]; } + /* needed */ + qsort(limTable, sbr->noPatches + sbr->N_low, sizeof(limTable[0]), longcmp); + k = 1; + nrLim = sbr->noPatches + sbr->N_low - 1; + if (nrLim < 0) // TODO: BIG FAT PROBLEM + goto exit; + restart: + if (k <= nrLim) { + real_t nOctaves; + if (limTable[k - 1] != 0) + #if 0 + nOctaves = REAL_CONST(log((float)limTable[k]/(float)limTable[k-1])/log(2.0)); + #else + #ifdef FIXED_POINT + nOctaves = DIV_R((limTable[k] << REAL_BITS), REAL_CONST(limTable[k - 1])); + #else + nOctaves = (real_t)limTable[k] / (real_t)limTable[k - 1]; + #endif + #endif + else + nOctaves = 0; + #if 0 + if ((MUL_R(nOctaves,limBands)) < REAL_CONST(0.49)) + #else + if (nOctaves < limiterBandsCompare[s - 1]) + #endif + { + uint8_t i; + if (limTable[k] != limTable[k - 1]) { + uint8_t found = 0, found2 = 0; + for (i = 0; i <= sbr->noPatches; i++) { + if (limTable[k] == patchBorders[i]) found = 1; + } + if (found) { + found2 = 0; + for (i = 0; i <= sbr->noPatches; i++) { + if (limTable[k - 1] == patchBorders[i]) found2 = 1; + } + if (found2) { + k++; + goto restart; + } else { + /* remove (k-1)th element */ + limTable[k - 1] = sbr->f_table_res[LO_RES][sbr->N_low]; + qsort(limTable, sbr->noPatches + sbr->N_low, sizeof(limTable[0]), longcmp); + nrLim--; + goto restart; + } + } + } + /* remove kth element */ + limTable[k] = sbr->f_table_res[LO_RES][sbr->N_low]; + qsort(limTable, nrLim, sizeof(limTable[0]), longcmp); + nrLim--; + goto restart; + } else { + k++; + goto restart; + } + } + sbr->N_L[s] = nrLim; + for (k = 0; k <= nrLim; k++) { sbr->f_table_lim[s][k] = limTable[k] - sbr->kx; } + #if 0 + printf("f_table_lim[%d][%d]: ", s, sbr->N_L[s]); + for (k = 0; k <= sbr->N_L[s]; k++) + { + printf("%d ", sbr->f_table_lim[s][k]); + } + printf("\n"); + #endif + } +exit: + faad_free(&limTable); + faad_free(&patchBorders); +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +real_t NeaacDecoder::find_log2_Qplus1(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + if ((sbr->Q[0][k][l] >= 0) && (sbr->Q[0][k][l] <= 30) && (sbr->Q[1][k][l] >= 0) && (sbr->Q[1][k][l] <= 24)) { + if (ch == 0) { + return QUANTISE2REAL(log_Qplus1_pan[sbr->Q[0][k][l]][sbr->Q[1][k][l] >> 1]); + } else { + return QUANTISE2REAL(log_Qplus1_pan[sbr->Q[0][k][l]][12 - (sbr->Q[1][k][l] >> 1)]); + } + } else { + return 0; + } + } else { + if (sbr->Q[ch][k][l] >= 0 && sbr->Q[ch][k][l] <= 30) { + return QUANTISE2REAL(log_Qplus1[sbr->Q[ch][k][l]]); + } else { + return 0; + } + } +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +void NeaacDecoder::calculate_gain(sbr_info* sbr, sbr_hfadj_info* adj, uint8_t ch) { + /* log2 values of limiter gains */ + real_t limGain[] = {-1.0, 0.0, 1.0, 33.219}; + uint8_t m, l, k; + uint8_t current_t_noise_band = 0; + uint8_t S_mapped; + real_t Q_M_lim[MAX_M]; + real_t G_lim[MAX_M]; + real_t G_boost; + real_t S_M[MAX_M]; + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t current_f_noise_band = 0; + uint8_t current_res_band = 0; + uint8_t current_res_band2 = 0; + uint8_t current_hi_res_band = 0; + real_t delta = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 0 : 1; + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + if (sbr->t_E[ch][l + 1] > sbr->t_Q[ch][current_t_noise_band + 1]) { current_t_noise_band++; } + for (k = 0; k < sbr->N_L[sbr->bs_limiter_bands]; k++) { + real_t Q_M = 0; + real_t G_max; + real_t den = 0; + real_t acc1 = 0; + real_t acc2 = 0; + uint8_t current_res_band_size = 0; + uint8_t Q_M_size = 0; + uint8_t ml1, ml2; + /* bounds of current limiter bands */ + ml1 = sbr->f_table_lim[sbr->bs_limiter_bands][k]; + ml2 = sbr->f_table_lim[sbr->bs_limiter_bands][k + 1]; + if (ml1 > MAX_M) ml1 = MAX_M; + if (ml2 > MAX_M) ml2 = MAX_M; + /* calculate the accumulated E_orig and E_curr over the limiter band */ + for (m = ml1; m < ml2; m++) { + if ((m + sbr->kx) < sbr->f_table_res[sbr->f[ch][l]][current_res_band + 1]) { + current_res_band_size++; + } else { + acc1 += QUANTISE2INT(pow2(-10 + log2_int_tab[current_res_band_size] + find_log2_E(sbr, current_res_band, l, ch))); + current_res_band++; + current_res_band_size = 1; + } + acc2 += QUANTISE2INT(sbr->E_curr[ch][m][l] / 1024.0); + } + acc1 += QUANTISE2INT(pow2(-10 + log2_int_tab[current_res_band_size] + find_log2_E(sbr, current_res_band, l, ch))); + acc1 = QUANTISE2REAL(log2(_EPS + acc1)); + /* calculate the maximum gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + G_max = acc1 - QUANTISE2REAL(log2(_EPS + acc2)) + QUANTISE2REAL(limGain[sbr->bs_limiter_gains]); + G_max = min(G_max, QUANTISE2REAL(limGain[3])); + for (m = ml1; m < ml2; m++) { + real_t G; + real_t E_curr, E_orig; + real_t Q_orig, Q_orig_plus1; + uint8_t S_index_mapped; + /* check if m is on a noise band border */ + if ((m + sbr->kx) == sbr->f_table_noise[current_f_noise_band + 1]) { + /* step to next noise band */ + current_f_noise_band++; + } + /* check if m is on a resolution band border */ + if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band2 + 1]) { + /* accumulate a whole range of equal Q_Ms */ + if (Q_M_size > 0) den += QUANTISE2INT(pow2(log2_int_tab[Q_M_size] + Q_M)); + Q_M_size = 0; + /* step to next resolution band */ + current_res_band2++; + /* if we move to a new resolution band, we should check if we are + * going to add a sinusoid in this band + */ + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + } + /* check if m is on a HI_RES band border */ + if ((m + sbr->kx) == sbr->f_table_res[HI_RES][current_hi_res_band + 1]) { + /* step to next HI_RES band */ + current_hi_res_band++; + } + /* find S_index_mapped + * S_index_mapped can only be 1 for the m in the middle of the + * current HI_RES band + */ + S_index_mapped = 0; + if ((l >= sbr->l_A[ch]) || (sbr->bs_add_harmonic_prev[ch][current_hi_res_band] && sbr->bs_add_harmonic_flag_prev[ch])) { + /* find the middle subband of the HI_RES frequency band */ + if ((m + sbr->kx) == (sbr->f_table_res[HI_RES][current_hi_res_band + 1] + sbr->f_table_res[HI_RES][current_hi_res_band]) >> 1) + S_index_mapped = sbr->bs_add_harmonic[ch][current_hi_res_band]; + } + /* find bitstream parameters */ + if (sbr->E_curr[ch][m][l] == 0) + E_curr = LOG2_MIN_INF; + else + E_curr = -10 + log2(sbr->E_curr[ch][m][l]); + E_orig = -10 + find_log2_E(sbr, current_res_band2, l, ch); + Q_orig = find_log2_Q(sbr, current_f_noise_band, current_t_noise_band, ch); + Q_orig_plus1 = find_log2_Qplus1(sbr, current_f_noise_band, current_t_noise_band, ch); + /* Q_M only depends on E_orig and Q_div2: + * since N_Q <= N_Low <= N_High we only need to recalculate Q_M on + * a change of current res band (HI or LO) + */ + Q_M = E_orig + Q_orig - Q_orig_plus1; + /* S_M only depends on E_orig, Q_div and S_index_mapped: + * S_index_mapped can only be non-zero once per HI_RES band + */ + if (S_index_mapped == 0) { + S_M[m] = LOG2_MIN_INF; /* -inf */ + } else { + S_M[m] = E_orig - Q_orig_plus1; + /* accumulate sinusoid part of the total energy */ + den += pow2(S_M[m]); + } + /* calculate gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + /* E_curr here is officially E_curr+1 so the log2() of that can never be < 0 */ + /* scaled by -10 */ + G = E_orig - max(-10, E_curr); + if ((S_mapped == 0) && (delta == 1)) { + /* G = G * 1/(1+Q) */ + G -= Q_orig_plus1; + } else if (S_mapped == 1) { + /* G = G * Q/(1+Q) */ + G += Q_orig - Q_orig_plus1; + } + /* limit the additional noise energy level */ + /* and apply the limiter */ + if (G_max > G) { + Q_M_lim[m] = QUANTISE2REAL(Q_M); + G_lim[m] = QUANTISE2REAL(G); + if ((S_index_mapped == 0) && (l != sbr->l_A[ch])) { Q_M_size++; } + } else { + /* G > G_max */ + Q_M_lim[m] = QUANTISE2REAL(Q_M) + G_max - QUANTISE2REAL(G); + G_lim[m] = G_max; + /* accumulate limited Q_M */ + if ((S_index_mapped == 0) && (l != sbr->l_A[ch])) { den += QUANTISE2INT(pow2(Q_M_lim[m])); } + } + /* accumulate the total energy */ + /* E_curr changes for every m so we do need to accumulate every m */ + den += QUANTISE2INT(pow2(E_curr + G_lim[m])); + } + /* accumulate last range of equal Q_Ms */ + if (Q_M_size > 0) { den += QUANTISE2INT(pow2(log2_int_tab[Q_M_size] + Q_M)); } + /* calculate the final gain */ + /* G_boost: [0..2.51188643] */ + G_boost = acc1 - QUANTISE2REAL(log2(den + _EPS)); + G_boost = min(G_boost, QUANTISE2REAL(1.328771237) /* log2(1.584893192 ^ 2) */); + for (m = ml1; m < ml2; m++) { + /* apply compensation to gain, noise floor sf's and sinusoid levels */ + #ifndef SBR_LOW_POWER + adj->G_lim_boost[l][m] = QUANTISE2REAL(pow2((G_lim[m] + G_boost) / 2.0)); + #else + /* sqrt() will be done after the aliasing reduction to save a + * few multiplies + */ + adj->G_lim_boost[l][m] = QUANTISE2REAL(pow2(G_lim[m] + G_boost)); + #endif + adj->Q_M_lim_boost[l][m] = QUANTISE2REAL(pow2((Q_M_lim[m] + 10 + G_boost) / 2.0)); + if (S_M[m] != LOG2_MIN_INF) { + adj->S_M_boost[l][m] = QUANTISE2REAL(pow2((S_M[m] + 10 + G_boost) / 2.0)); + } else { + adj->S_M_boost[l][m] = 0; + } + } + } + } +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifndef LOG2_TEST +void NeaacDecoder::calculate_gain(sbr_info* sbr, sbr_hfadj_info* adj, uint8_t ch) { + real_t limGain[] = {0.5, 1.0, 2.0, 1e10}; + uint8_t m, l, k; + uint8_t current_t_noise_band = 0; + uint8_t S_mapped; + real_t Q_M_lim[MAX_M]; + real_t G_lim[MAX_M]; + real_t G_boost; + real_t S_M[MAX_M]; + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t current_f_noise_band = 0; + uint8_t current_res_band = 0; + uint8_t current_res_band2 = 0; + uint8_t current_hi_res_band = 0; + real_t delta = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 0 : 1; + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + if (sbr->t_E[ch][l + 1] > sbr->t_Q[ch][current_t_noise_band + 1]) { current_t_noise_band++; } + for (k = 0; k < sbr->N_L[sbr->bs_limiter_bands]; k++) { + real_t G_max; + real_t den = 0; + real_t acc1 = 0; + real_t acc2 = 0; + uint8_t current_res_band_size = 0; + (void)current_res_band_size; + uint8_t ml1, ml2; + ml1 = sbr->f_table_lim[sbr->bs_limiter_bands][k]; + ml2 = sbr->f_table_lim[sbr->bs_limiter_bands][k + 1]; + if (ml1 > MAX_M) ml1 = MAX_M; + if (ml2 > MAX_M) ml2 = MAX_M; + /* calculate the accumulated E_orig and E_curr over the limiter band */ + for (m = ml1; m < ml2; m++) { + if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band + 1]) { current_res_band++; } + acc1 += sbr->E_orig[ch][current_res_band][l]; + acc2 += sbr->E_curr[ch][m][l]; + } + /* calculate the maximum gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + G_max = ((_EPS + acc1) / (_EPS + acc2)) * limGain[sbr->bs_limiter_gains]; + G_max = min(G_max, (real_t)1e10); + for (m = ml1; m < ml2; m++) { + real_t Q_M, G; + real_t Q_div, Q_div2; + uint8_t S_index_mapped; + /* check if m is on a noise band border */ + if ((m + sbr->kx) == sbr->f_table_noise[current_f_noise_band + 1]) { + /* step to next noise band */ + current_f_noise_band++; + } + /* check if m is on a resolution band border */ + if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band2 + 1]) { + /* step to next resolution band */ + current_res_band2++; + /* if we move to a new resolution band, we should check if we are + * going to add a sinusoid in this band + */ + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + } + /* check if m is on a HI_RES band border */ + if ((m + sbr->kx) == sbr->f_table_res[HI_RES][current_hi_res_band + 1]) { + /* step to next HI_RES band */ + current_hi_res_band++; + } + /* find S_index_mapped + * S_index_mapped can only be 1 for the m in the middle of the + * current HI_RES band + */ + S_index_mapped = 0; + if ((l >= sbr->l_A[ch]) || (sbr->bs_add_harmonic_prev[ch][current_hi_res_band] && sbr->bs_add_harmonic_flag_prev[ch])) { + /* find the middle subband of the HI_RES frequency band */ + if ((m + sbr->kx) == (sbr->f_table_res[HI_RES][current_hi_res_band + 1] + sbr->f_table_res[HI_RES][current_hi_res_band]) >> 1) + S_index_mapped = sbr->bs_add_harmonic[ch][current_hi_res_band]; + } + /* Q_div: [0..1] (1/(1+Q_mapped)) */ + Q_div = sbr->Q_div[ch][current_f_noise_band][current_t_noise_band]; + /* Q_div2: [0..1] (Q_mapped/(1+Q_mapped)) */ + Q_div2 = sbr->Q_div2[ch][current_f_noise_band][current_t_noise_band]; + /* Q_M only depends on E_orig and Q_div2: + * since N_Q <= N_Low <= N_High we only need to recalculate Q_M on + * a change of current noise band + */ + Q_M = sbr->E_orig[ch][current_res_band2][l] * Q_div2; + /* S_M only depends on E_orig, Q_div and S_index_mapped: + * S_index_mapped can only be non-zero once per HI_RES band + */ + if (S_index_mapped == 0) { + S_M[m] = 0; + } else { + S_M[m] = sbr->E_orig[ch][current_res_band2][l] * Q_div; + /* accumulate sinusoid part of the total energy */ + den += S_M[m]; + } + /* calculate gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + G = sbr->E_orig[ch][current_res_band2][l] / (1.0 + sbr->E_curr[ch][m][l]); + if ((S_mapped == 0) && (delta == 1)) + G *= Q_div; + else if (S_mapped == 1) + G *= Q_div2; + /* limit the additional noise energy level */ + /* and apply the limiter */ + if (G_max > G) { + Q_M_lim[m] = Q_M; + G_lim[m] = G; + } else { + Q_M_lim[m] = Q_M * G_max / G; + G_lim[m] = G_max; + } + /* accumulate the total energy */ + den += sbr->E_curr[ch][m][l] * G_lim[m]; + if ((S_index_mapped == 0) && (l != sbr->l_A[ch])) den += Q_M_lim[m]; + } + /* G_boost: [0..2.51188643] */ + G_boost = (acc1 + _EPS) / (den + _EPS); + G_boost = min(G_boost, (real_t)2.51188643 /* 1.584893192 ^ 2 */); + for (m = ml1; m < ml2; m++) { + /* apply compensation to gain, noise floor sf's and sinusoid levels */ + #ifndef SBR_LOW_POWER + adj->G_lim_boost[l][m] = sqrt(G_lim[m] * G_boost); + #else + /* sqrt() will be done after the aliasing reduction to save a + * few multiplies + */ + adj->G_lim_boost[l][m] = G_lim[m] * G_boost; + #endif + adj->Q_M_lim_boost[l][m] = sqrt(Q_M_lim[m] * G_boost); + if (S_M[m] != 0) { + adj->S_M_boost[l][m] = sqrt(S_M[m] * G_boost); + } else { + adj->S_M_boost[l][m] = 0; + } + } + } + } +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::calc_gain_groups(sbr_info* sbr, sbr_hfadj_info* adj, real_t* deg, uint8_t ch) { + uint8_t l, k, i; + uint8_t grouping; + uint8_t S_mapped; + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t current_res_band = 0; + i = 0; + grouping = 0; + S_mapped = get_S_mapped(sbr, ch, l, current_res_band); + for (k = sbr->kx; k < sbr->kx + sbr->M - 1; k++) { + if (k == sbr->f_table_res[sbr->f[ch][l]][current_res_band + 1]) { + /* step to next resolution band */ + current_res_band++; + S_mapped = get_S_mapped(sbr, ch, l, current_res_band); + } + if (deg[k + 1] && S_mapped == 0) { + if (grouping == 0) { + sbr->f_group[l][i] = k; + grouping = 1; + i++; + } + } else { + if (grouping) { + if (S_mapped) { + sbr->f_group[l][i] = k; + } else { + sbr->f_group[l][i] = k + 1; + } + grouping = 0; + i++; + } + } + } + if (grouping) { + sbr->f_group[l][i] = sbr->kx + sbr->M; + i++; + } + sbr->N_G[l] = (uint8_t)(i >> 1); + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::aliasing_reduction(sbr_info* sbr, sbr_hfadj_info* adj, real_t* deg, uint8_t ch) { + uint8_t l, k, m; + real_t E_total, E_total_est, G_target, acc; + for (l = 0; l < sbr->L_E[ch]; l++) { + for (k = 0; k < sbr->N_G[l]; k++) { + E_total_est = E_total = 0; + for (m = sbr->f_group[l][k << 1]; m < sbr->f_group[l][(k << 1) + 1]; m++) { + /* E_curr: integer */ + /* G_lim_boost: fixed point */ + /* E_total_est: integer */ + /* E_total: integer */ + E_total_est += sbr->E_curr[ch][m - sbr->kx][l]; + #ifdef FIXED_POINT + E_total += MUL_Q2(sbr->E_curr[ch][m - sbr->kx][l], adj->G_lim_boost[l][m - sbr->kx]); + #else + E_total += sbr->E_curr[ch][m - sbr->kx][l] * adj->G_lim_boost[l][m - sbr->kx]; + #endif + } + /* G_target: fixed point */ + if ((E_total_est + _EPS) == 0) { + G_target = 0; + } else { + #ifdef FIXED_POINT + G_target = (((int64_t)(E_total)) << Q2_BITS) / (E_total_est + _EPS); + #else + G_target = E_total / (E_total_est + _EPS); + #endif + } + acc = 0; + for (m = sbr->f_group[l][(k << 1)]; m < sbr->f_group[l][(k << 1) + 1]; m++) { + real_t alpha; + /* alpha: (COEF) fixed point */ + if (m < sbr->kx + sbr->M - 1) { + alpha = max(deg[m], deg[m + 1]); + } else { + alpha = deg[m]; + } + adj->G_lim_boost[l][m - sbr->kx] = MUL_C(alpha, G_target) + MUL_C((COEF_CONST(1) - alpha), adj->G_lim_boost[l][m - sbr->kx]); + /* acc: integer */ + #ifdef FIXED_POINT + acc += MUL_Q2(adj->G_lim_boost[l][m - sbr->kx], sbr->E_curr[ch][m - sbr->kx][l]); + #else + acc += adj->G_lim_boost[l][m - sbr->kx] * sbr->E_curr[ch][m - sbr->kx][l]; + #endif + } + /* acc: fixed point */ + if (acc + _EPS == 0) { + acc = 0; + } else { + #ifdef FIXED_POINT + acc = (((int64_t)(E_total)) << Q2_BITS) / (acc + _EPS); + #else + acc = E_total / (acc + _EPS); + #endif + } + for (m = sbr->f_group[l][(k << 1)]; m < sbr->f_group[l][(k << 1) + 1]; m++) { + #ifdef FIXED_POINT + adj->G_lim_boost[l][m - sbr->kx] = MUL_Q2(acc, adj->G_lim_boost[l][m - sbr->kx]); + #else + adj->G_lim_boost[l][m - sbr->kx] = acc * adj->G_lim_boost[l][m - sbr->kx]; + #endif + } + } + } + for (l = 0; l < sbr->L_E[ch]; l++) { + for (k = 0; k < sbr->N_L[sbr->bs_limiter_bands]; k++) { + for (m = sbr->f_table_lim[sbr->bs_limiter_bands][k]; m < sbr->f_table_lim[sbr->bs_limiter_bands][k + 1]; m++) { + #ifdef FIXED_POINT + adj->G_lim_boost[l][m] = sqrt(adj->G_lim_boost[l][m]); + #else + adj->G_lim_boost[l][m] = sqrt(adj->G_lim_boost[l][m]); + #endif + } + } + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::hf_assembly(sbr_info* sbr, sbr_hfadj_info* adj, qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch) { + real_t h_smooth[] = {FRAC_CONST(0.03183050093751), FRAC_CONST(0.11516383427084), FRAC_CONST(0.21816949906249), FRAC_CONST(0.30150283239582), FRAC_CONST(0.33333333333333)}; + int8_t phi_re[] = {1, 0, -1, 0}; + (void)h_smooth; + int8_t phi_im[] = {0, 1, 0, -1}; + (void)phi_im; + uint8_t m, l, i, n; + uint16_t fIndexNoise = 0; + uint8_t fIndexSine = 0; + uint8_t assembly_reset = 0; + real_t G_filt, Q_filt; + uint8_t h_SL; + (void)h_SL; + if (sbr->Reset == 1) { + assembly_reset = 1; + fIndexNoise = 0; + } else { + fIndexNoise = sbr->index_noise_prev[ch]; + } + fIndexSine = sbr->psi_is_prev[ch]; + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t no_noise = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 1 : 0; + #ifdef SBR_LOW_POWER + h_SL = 0; + #else + h_SL = (sbr->bs_smoothing_mode == 1) ? 0 : 4; + h_SL = (no_noise ? 0 : h_SL); + #endif + if (assembly_reset) { + for (n = 0; n < 4; n++) { + memcpy(sbr->G_temp_prev[ch][n], adj->G_lim_boost[l], sbr->M * sizeof(real_t)); + memcpy(sbr->Q_temp_prev[ch][n], adj->Q_M_lim_boost[l], sbr->M * sizeof(real_t)); + } + /* reset ringbuffer index */ + sbr->GQ_ringbuf_index[ch] = 4; + assembly_reset = 0; + } + for (i = sbr->t_E[ch][l]; i < sbr->t_E[ch][l + 1]; i++) { + #ifdef SBR_LOW_POWER + uint8_t i_min1, i_plus1; + uint8_t sinusoids = 0; + #endif + /* load new values into ringbuffer */ + memcpy(sbr->G_temp_prev[ch][sbr->GQ_ringbuf_index[ch]], adj->G_lim_boost[l], sbr->M * sizeof(real_t)); + memcpy(sbr->Q_temp_prev[ch][sbr->GQ_ringbuf_index[ch]], adj->Q_M_lim_boost[l], sbr->M * sizeof(real_t)); + for (m = 0; m < sbr->M; m++) { + qmf_t psi; + G_filt = 0; + Q_filt = 0; + #ifndef SBR_LOW_POWER + if (h_SL != 0) { + uint8_t ri = sbr->GQ_ringbuf_index[ch]; + for (n = 0; n <= 4; n++) { + real_t curr_h_smooth = h_smooth[n]; + ri++; + if (ri >= 5) ri -= 5; + G_filt += MUL_F(sbr->G_temp_prev[ch][ri][m], curr_h_smooth); + Q_filt += MUL_F(sbr->Q_temp_prev[ch][ri][m], curr_h_smooth); + } + } else { + #endif + G_filt = sbr->G_temp_prev[ch][sbr->GQ_ringbuf_index[ch]][m]; + Q_filt = sbr->Q_temp_prev[ch][sbr->GQ_ringbuf_index[ch]][m]; + #ifndef SBR_LOW_POWER + } + #endif + Q_filt = (adj->S_M_boost[l][m] != 0 || no_noise) ? 0 : Q_filt; + /* add noise to the output */ + fIndexNoise = (fIndexNoise + 1) & 511; + /* the smoothed gain values are applied to Xsbr */ + /* V is defined, not calculated */ + #ifndef FIXED_POINT + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) = G_filt * QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) + MUL_F(Q_filt, RE(V[fIndexNoise])); + #else + // QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) = MUL_Q2(G_filt, QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx])) + // + MUL_F(Q_filt, RE(V[fIndexNoise])); + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) = MUL_R(G_filt, QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx])) + MUL_F(Q_filt, RE(V[fIndexNoise])); + #endif + if (sbr->bs_extension_id == 3 && sbr->bs_extension_data == 42) QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) = 16428320; + #ifndef SBR_LOW_POWER + #ifndef FIXED_POINT + QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) = G_filt * QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) + MUL_F(Q_filt, IM(V[fIndexNoise])); + #else + // QMF_IM(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) = MUL_Q2(G_filt, QMF_IM(Xsbr[i + sbr->tHFAdj][m+sbr->kx])) + // + MUL_F(Q_filt, IM(V[fIndexNoise])); + QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) = MUL_R(G_filt, QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx])) + MUL_F(Q_filt, IM(V[fIndexNoise])); + #endif + #endif + { + int8_t rev = (((m + sbr->kx) & 1) ? -1 : 1); + QMF_RE(psi) = adj->S_M_boost[l][m] * phi_re[fIndexSine]; + #ifdef FIXED_POINT + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) += (QMF_RE(psi) << REAL_BITS); + #else + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) += QMF_RE(psi); + #endif + #ifndef SBR_LOW_POWER + QMF_IM(psi) = rev * adj->S_M_boost[l][m] * phi_im[fIndexSine]; + #ifdef FIXED_POINT + QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) += (QMF_IM(psi) << REAL_BITS); + #else + QMF_IM(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) += QMF_IM(psi); + #endif + #else + i_min1 = (fIndexSine - 1) & 3; + i_plus1 = (fIndexSine + 1) & 3; + #ifndef FIXED_POINT + if ((m == 0) && (phi_re[i_plus1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx - 1]) += (rev * phi_re[i_plus1] * MUL_F(adj->S_M_boost[l][0], FRAC_CONST(0.00815))); + if (sbr->M != 0) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_plus1] * MUL_F(adj->S_M_boost[l][1], FRAC_CONST(0.00815))); } + } + if ((m > 0) && (m < sbr->M - 1) && (sinusoids < 16) && (phi_re[i_min1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_min1] * MUL_F(adj->S_M_boost[l][m - 1], FRAC_CONST(0.00815))); + } + if ((m > 0) && (m < sbr->M - 1) && (sinusoids < 16) && (phi_re[i_plus1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_plus1] * MUL_F(adj->S_M_boost[l][m + 1], FRAC_CONST(0.00815))); + } + if ((m == sbr->M - 1) && (sinusoids < 16) && (phi_re[i_min1] != 0)) { + if (m > 0) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_min1] * MUL_F(adj->S_M_boost[l][m - 1], FRAC_CONST(0.00815))); } + if (m + sbr->kx < 64) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx + 1]) += (rev * phi_re[i_min1] * MUL_F(adj->S_M_boost[l][m], FRAC_CONST(0.00815))); } + } + #else + if ((m == 0) && (phi_re[i_plus1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx - 1]) += (rev * phi_re[i_plus1] * MUL_F((adj->S_M_boost[l][0] << REAL_BITS), FRAC_CONST(0.00815))); + if (sbr->M != 0) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_plus1] * MUL_F((adj->S_M_boost[l][1] << REAL_BITS), FRAC_CONST(0.00815))); } + } + if ((m > 0) && (m < sbr->M - 1) && (sinusoids < 16) && (phi_re[i_min1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_min1] * MUL_F((adj->S_M_boost[l][m - 1] << REAL_BITS), FRAC_CONST(0.00815))); + } + if ((m > 0) && (m < sbr->M - 1) && (sinusoids < 16) && (phi_re[i_plus1] != 0)) { + QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_plus1] * MUL_F((adj->S_M_boost[l][m + 1] << REAL_BITS), FRAC_CONST(0.00815))); + } + if ((m == sbr->M - 1) && (sinusoids < 16) && (phi_re[i_min1] != 0)) { + if (m > 0) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx]) -= (rev * phi_re[i_min1] * MUL_F((adj->S_M_boost[l][m - 1] << REAL_BITS), FRAC_CONST(0.00815))); } + if (m + sbr->kx < 64) { QMF_RE(Xsbr[i + sbr->tHFAdj][m + sbr->kx + 1]) += (rev * phi_re[i_min1] * MUL_F((adj->S_M_boost[l][m] << REAL_BITS), FRAC_CONST(0.00815))); } + } + #endif + if (adj->S_M_boost[l][m] != 0) sinusoids++; + #endif + } + } + fIndexSine = (fIndexSine + 1) & 3; + /* update the ringbuffer index used for filtering G and Q with h_smooth */ + sbr->GQ_ringbuf_index[ch]++; + if (sbr->GQ_ringbuf_index[ch] >= 5) sbr->GQ_ringbuf_index[ch] = 0; + } + } + sbr->index_noise_prev[ch] = fIndexNoise; + sbr->psi_is_prev[ch] = fIndexSine; +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +real_t NeaacDecoder::find_log2_E(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + real_t amp0 = (sbr->amp_res[0]) ? 1.0 : 0.5; + real_t amp1 = (sbr->amp_res[1]) ? 1.0 : 0.5; + float tmp = QUANTISE2REAL(7.0 + (real_t)sbr->E[0][k][l] * amp0); + float pan; + int E = (int)(sbr->E[1][k][l] * amp1); + if (ch == 0) { + if (E > 12) { + /* negative */ + pan = QUANTISE2REAL(pan_log2_tab[-12 + E]); + } else { + /* positive */ + pan = QUANTISE2REAL(pan_log2_tab[12 - E] + (12 - E)); + } + } else { + if (E < 12) { + /* negative */ + pan = QUANTISE2REAL(pan_log2_tab[-E + 12]); + } else { + /* positive */ + pan = QUANTISE2REAL(pan_log2_tab[E - 12] + (E - 12)); + } + } + /* tmp / pan in log2 */ + return QUANTISE2REAL(tmp - pan); + } else { + real_t amp = (sbr->amp_res[ch]) ? 1.0 : 0.5; + return QUANTISE2REAL(6.0 + (real_t)sbr->E[ch][k][l] * amp); + } +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST +real_t NeaacDecoder::find_log2_Q(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + float tmp = QUANTISE2REAL(7.0 - (real_t)sbr->Q[0][k][l]); + float pan; + int Q = (int)(sbr->Q[1][k][l]); + if (ch == 0) { + if (Q > 12) { + /* negative */ + pan = QUANTISE2REAL(pan_log2_tab[-12 + Q]); + } else { + /* positive */ + pan = QUANTISE2REAL(pan_log2_tab[12 - Q] + (12 - Q)); + } + } else { + if (Q < 12) { + /* negative */ + pan = QUANTISE2REAL(pan_log2_tab[-Q + 12]); + } else { + /* positive */ + pan = QUANTISE2REAL(pan_log2_tab[Q - 12] + (Q - 12)); + } + } + /* tmp / pan in log2 */ + return QUANTISE2REAL(tmp - pan); + } else { + return QUANTISE2REAL(6.0 - (real_t)sbr->Q[ch][k][l]); + } +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +int16_t NeaacDecoder::sbr_huff_dec(bitfile* ld, sbr_huff_tab t_huff) { + uint8_t bit; + int16_t index = 0; + while (index >= 0) { + bit = (uint8_t)faad_get1bit(ld); + index = t_huff[index][bit]; + } + return index + 64; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 10 */ +void NeaacDecoder::sbr_envelope(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t env, band; + int8_t delta = 0; + sbr_huff_tab t_huff, f_huff; + if ((sbr->L_E[ch] == 1) && (sbr->bs_frame_class[ch] == FIXFIX)) + sbr->amp_res[ch] = 0; + else + sbr->amp_res[ch] = sbr->bs_amp_res; + if ((sbr->bs_coupling) && (ch == 1)) { + delta = 1; + if (sbr->amp_res[ch]) { + t_huff = t_huffman_env_bal_3_0dB; + f_huff = f_huffman_env_bal_3_0dB; + } else { + t_huff = t_huffman_env_bal_1_5dB; + f_huff = f_huffman_env_bal_1_5dB; + } + } else { + delta = 0; + if (sbr->amp_res[ch]) { + t_huff = t_huffman_env_3_0dB; + f_huff = f_huffman_env_3_0dB; + } else { + t_huff = t_huffman_env_1_5dB; + f_huff = f_huffman_env_1_5dB; + } + } + for (env = 0; env < sbr->L_E[ch]; env++) { + if (sbr->bs_df_env[ch][env] == 0) { + if ((sbr->bs_coupling == 1) && (ch == 1)) { + if (sbr->amp_res[ch]) { + sbr->E[ch][0][env] = (uint16_t)(faad_getbits(ld, 5) << delta); + } else { + sbr->E[ch][0][env] = (uint16_t)(faad_getbits(ld, 6) << delta); + } + } else { + if (sbr->amp_res[ch]) { + sbr->E[ch][0][env] = (uint16_t)(faad_getbits(ld, 6) << delta); + } else { + sbr->E[ch][0][env] = (uint16_t)(faad_getbits(ld, 7) << delta); + } + } + for (band = 1; band < sbr->n[sbr->f[ch][env]]; band++) { sbr->E[ch][band][env] = (sbr_huff_dec(ld, f_huff) << delta); } + } else { + for (band = 0; band < sbr->n[sbr->f[ch][env]]; band++) { sbr->E[ch][band][env] = (sbr_huff_dec(ld, t_huff) << delta); } + } + } + extract_envelope_data(sbr, ch); +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 11 */ +void NeaacDecoder::sbr_noise(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t noise, band; + int8_t delta = 0; + sbr_huff_tab t_huff, f_huff; + if ((sbr->bs_coupling == 1) && (ch == 1)) { + delta = 1; + t_huff = t_huffman_noise_bal_3_0dB; + f_huff = f_huffman_env_bal_3_0dB; + } else { + delta = 0; + t_huff = t_huffman_noise_3_0dB; + f_huff = f_huffman_env_3_0dB; + } + for (noise = 0; noise < sbr->L_Q[ch]; noise++) { + if (sbr->bs_df_noise[ch][noise] == 0) { + if ((sbr->bs_coupling == 1) && (ch == 1)) { + sbr->Q[ch][0][noise] = (faad_getbits(ld, 5) << delta); + } else { + sbr->Q[ch][0][noise] = (faad_getbits(ld, 5) << delta); + } + for (band = 1; band < sbr->N_Q; band++) { sbr->Q[ch][band][noise] = (sbr_huff_dec(ld, f_huff) << delta); } + } else { + for (band = 0; band < sbr->N_Q; band++) { sbr->Q[ch][band][noise] = (sbr_huff_dec(ld, t_huff) << delta); } + } + } + extract_noise_floor_data(sbr, ch); +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::sbr_reset(sbr_info* sbr) { + #if 0 + printf("%d\n", sbr->bs_start_freq_prev); + printf("%d\n", sbr->bs_stop_freq_prev); + printf("%d\n", sbr->bs_freq_scale_prev); + printf("%d\n", sbr->bs_alter_scale_prev); + printf("%d\n", sbr->bs_xover_band_prev); + printf("%d\n\n", sbr->bs_noise_bands_prev); + #endif + /* if these are different from the previous frame: Reset = 1 */ + if ((sbr->bs_start_freq != sbr->bs_start_freq_prev) || (sbr->bs_stop_freq != sbr->bs_stop_freq_prev) || (sbr->bs_freq_scale != sbr->bs_freq_scale_prev) || + (sbr->bs_alter_scale != sbr->bs_alter_scale_prev) || (sbr->bs_xover_band != sbr->bs_xover_band_prev) || (sbr->bs_noise_bands != sbr->bs_noise_bands_prev)) { + sbr->Reset = 1; + } else { + sbr->Reset = 0; + } + sbr->bs_start_freq_prev = sbr->bs_start_freq; + sbr->bs_stop_freq_prev = sbr->bs_stop_freq; + sbr->bs_freq_scale_prev = sbr->bs_freq_scale; + sbr->bs_alter_scale_prev = sbr->bs_alter_scale; + sbr->bs_xover_band_prev = sbr->bs_xover_band; + sbr->bs_noise_bands_prev = sbr->bs_noise_bands; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::calc_sbr_tables(sbr_info* sbr, uint8_t start_freq, uint8_t stop_freq, uint8_t samplerate_mode, uint8_t freq_scale, uint8_t alter_scale, uint8_t xover_band) { + uint8_t result = 0; + uint8_t k2; + /* calculate the Master Frequency Table */ + sbr->k0 = qmf_start_channel(start_freq, samplerate_mode, sbr->sample_rate); + k2 = qmf_stop_channel(stop_freq, sbr->sample_rate, sbr->k0); + /* check k0 and k2 */ + if (sbr->sample_rate >= 48000) { + if ((k2 - sbr->k0) > 32) result += 1; + } else if (sbr->sample_rate <= 32000) { + if ((k2 - sbr->k0) > 48) result += 1; + } else { /* (sbr->sample_rate == 44100) */ + if ((k2 - sbr->k0) > 45) result += 1; + } + if (freq_scale == 0) { + result += master_frequency_table_fs0(sbr, sbr->k0, k2, alter_scale); + } else { + result += master_frequency_table(sbr, sbr->k0, k2, freq_scale, alter_scale); + } + result += derived_frequency_table(sbr, xover_band, k2); + result = (result > 0) ? 1 : 0; + return result; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 2 */ +uint8_t NeaacDecoder::sbr_extension_data(bitfile* ld, sbr_info* sbr, uint16_t cnt, uint8_t psResetFlag) { + uint8_t result = 0; + uint16_t num_align_bits = 0; + uint16_t num_sbr_bits1 = (uint16_t)faad_get_processed_bits(ld); + uint16_t num_sbr_bits2; + uint8_t saved_start_freq, saved_samplerate_mode; + uint8_t saved_stop_freq, saved_freq_scale; + uint8_t saved_alter_scale, saved_xover_band; + #if (defined(PS_DEC) || defined(DRM_PS)) + if (psResetFlag) sbr->psResetFlag = psResetFlag; + #endif + #ifdef DRM + if (!sbr->Is_DRM_SBR) + #endif + { + uint8_t bs_extension_type = (uint8_t)faad_getbits(ld, 4); + if (bs_extension_type == EXT_SBR_DATA_CRC) { sbr->bs_sbr_crc_bits = (uint16_t)faad_getbits(ld, 10); } + } + /* save old header values, in case the new ones are corrupted */ + saved_start_freq = sbr->bs_start_freq; + saved_samplerate_mode = sbr->bs_samplerate_mode; + saved_stop_freq = sbr->bs_stop_freq; + saved_freq_scale = sbr->bs_freq_scale; + saved_alter_scale = sbr->bs_alter_scale; + saved_xover_band = sbr->bs_xover_band; + sbr->bs_header_flag = faad_get1bit(ld); + if (sbr->bs_header_flag) sbr_header(ld, sbr); + /* Reset? */ + sbr_reset(sbr); + /* first frame should have a header */ + // if (!(sbr->frame == 0 && sbr->bs_header_flag == 0)) + if (sbr->header_count != 0) { + if (sbr->Reset || (sbr->bs_header_flag && sbr->just_seeked)) { + uint8_t rt = calc_sbr_tables(sbr, sbr->bs_start_freq, sbr->bs_stop_freq, sbr->bs_samplerate_mode, sbr->bs_freq_scale, sbr->bs_alter_scale, sbr->bs_xover_band); + /* if an error occured with the new header values revert to the old ones */ + if (rt > 0) { result += calc_sbr_tables(sbr, saved_start_freq, saved_stop_freq, saved_samplerate_mode, saved_freq_scale, saved_alter_scale, saved_xover_band); } + } + if (result == 0) { + result = sbr_data(ld, sbr); + /* sbr_data() returning an error means that there was an error in + envelope_time_border_vector(). + In this case the old time border vector is saved and all the previous + data normally read after sbr_grid() is saved. + */ + /* to be on the safe side, calculate old sbr tables in case of error */ + if ((result > 0) && (sbr->Reset || (sbr->bs_header_flag && sbr->just_seeked))) { + result += calc_sbr_tables(sbr, saved_start_freq, saved_stop_freq, saved_samplerate_mode, saved_freq_scale, saved_alter_scale, saved_xover_band); + } + /* we should be able to safely set result to 0 now, */ + /* but practise indicates this doesn't work well */ + } + } else { + result = 1; + } + num_sbr_bits2 = (uint16_t)faad_get_processed_bits(ld) - num_sbr_bits1; + /* check if we read more bits then were available for sbr */ + if (8 * cnt < num_sbr_bits2) { + faad_resetbits(ld, num_sbr_bits1 + 8 * cnt); + num_sbr_bits2 = 8 * cnt; + #ifdef PS_DEC + /* turn off PS for the unfortunate case that we randomly read some + * PS data that looks correct */ + sbr->ps_used = 0; + #endif + /* Make sure it doesn't decode SBR in this frame, or we'll get glitches */ + return 1; + } + #ifdef DRM + if (!sbr->Is_DRM_SBR) + #endif + { + /* -4 does not apply, bs_extension_type is re-read in this function */ + num_align_bits = 8 * cnt /*- 4*/ - num_sbr_bits2; + while (num_align_bits > 7) { + faad_getbits(ld, 8); + num_align_bits -= 8; + } + faad_getbits(ld, num_align_bits); + } + return result; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 3 */ +void NeaacDecoder::sbr_header(bitfile* ld, sbr_info* sbr) { + uint8_t bs_header_extra_1, bs_header_extra_2; + sbr->header_count++; + sbr->bs_amp_res = faad_get1bit(ld); + /* bs_start_freq and bs_stop_freq must define a fequency band that does + not exceed 48 channels */ + sbr->bs_start_freq = (uint8_t)faad_getbits(ld, 4); + sbr->bs_stop_freq = (uint8_t)faad_getbits(ld, 4); + sbr->bs_xover_band = (uint8_t)faad_getbits(ld, 3); + faad_getbits(ld, 2); + bs_header_extra_1 = (uint8_t)faad_get1bit(ld); + bs_header_extra_2 = (uint8_t)faad_get1bit(ld); + if (bs_header_extra_1) { + sbr->bs_freq_scale = (uint8_t)faad_getbits(ld, 2); + sbr->bs_alter_scale = (uint8_t)faad_get1bit(ld); + sbr->bs_noise_bands = (uint8_t)faad_getbits(ld, 2); + } else { + /* Default values */ + sbr->bs_freq_scale = 2; + sbr->bs_alter_scale = 1; + sbr->bs_noise_bands = 2; + } + if (bs_header_extra_2) { + sbr->bs_limiter_bands = (uint8_t)faad_getbits(ld, 2); + sbr->bs_limiter_gains = (uint8_t)faad_getbits(ld, 2); + sbr->bs_interpol_freq = (uint8_t)faad_get1bit(ld); + sbr->bs_smoothing_mode = (uint8_t)faad_get1bit(ld); + } else { + /* Default values */ + sbr->bs_limiter_bands = 2; + sbr->bs_limiter_gains = 2; + sbr->bs_interpol_freq = 1; + sbr->bs_smoothing_mode = 1; + } + #if 0 + /* print the header to screen */ + printf("bs_amp_res: %d\n", sbr->bs_amp_res); + printf("bs_start_freq: %d\n", sbr->bs_start_freq); + printf("bs_stop_freq: %d\n", sbr->bs_stop_freq); + printf("bs_xover_band: %d\n", sbr->bs_xover_band); + if (bs_header_extra_1) + { + printf("bs_freq_scale: %d\n", sbr->bs_freq_scale); + printf("bs_alter_scale: %d\n", sbr->bs_alter_scale); + printf("bs_noise_bands: %d\n", sbr->bs_noise_bands); + } + if (bs_header_extra_2) + { + printf("bs_limiter_bands: %d\n", sbr->bs_limiter_bands); + printf("bs_limiter_gains: %d\n", sbr->bs_limiter_gains); + printf("bs_interpol_freq: %d\n", sbr->bs_interpol_freq); + printf("bs_smoothing_mode: %d\n", sbr->bs_smoothing_mode); + } + printf("\n"); + #endif +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 5 */ +uint8_t NeaacDecoder::sbr_single_channel_element(bitfile* ld, sbr_info* sbr) { + uint8_t result; + if (faad_get1bit(ld)) { faad_getbits(ld, 4); } + #ifdef DRM + /* bs_coupling, from sbr_channel_pair_base_element(bs_amp_res) */ + if (sbr->Is_DRM_SBR) { faad_get1bit(ld); } + #endif + if ((result = sbr_grid(ld, sbr, 0)) > 0) return result; + sbr_dtdf(ld, sbr, 0); + invf_mode(ld, sbr, 0); + sbr_envelope(ld, sbr, 0); + sbr_noise(ld, sbr, 0); + #ifndef FIXED_POINT + envelope_noise_dequantisation(sbr, 0); + #endif + memset(sbr->bs_add_harmonic[0], 0, 64 * sizeof(uint8_t)); + sbr->bs_add_harmonic_flag[0] = faad_get1bit(ld); + if (sbr->bs_add_harmonic_flag[0]) sinusoidal_coding(ld, sbr, 0); + sbr->bs_extended_data = faad_get1bit(ld); + if (sbr->bs_extended_data) { + uint16_t nr_bits_left; + #if (defined(PS_DEC) || defined(DRM_PS)) + uint8_t ps_ext_read = 0; + #endif + uint16_t cnt = (uint16_t)faad_getbits(ld, 4); + if (cnt == 15) { cnt += (uint16_t)faad_getbits(ld, 8); } + nr_bits_left = 8 * cnt; + while (nr_bits_left > 7) { + uint16_t tmp_nr_bits = 0; + sbr->bs_extension_id = (uint8_t)faad_getbits(ld, 2); + tmp_nr_bits += 2; + /* allow only 1 PS extension element per extension data */ + #if (defined(PS_DEC) || defined(DRM_PS)) + #if (defined(PS_DEC) && defined(DRM_PS)) + if (sbr->bs_extension_id == EXTENSION_ID_PS || sbr->bs_extension_id == DRM_PARAMETRIC_STEREO) + #else + #ifdef PS_DEC + if (sbr->bs_extension_id == EXTENSION_ID_PS) + #else + #ifdef DRM_PS + if (sbr->bs_extension_id == DRM_PARAMETRIC_STEREO) + #endif + #endif + #endif + { + if (ps_ext_read == 0) { + ps_ext_read = 1; + } else { + /* to be safe make it 3, will switch to "default" + * in sbr_extension() */ + #ifdef DRM + return 1; + #else + sbr->bs_extension_id = 3; + #endif + } + } + #endif + tmp_nr_bits += sbr_extension(ld, sbr, sbr->bs_extension_id, nr_bits_left); + /* check if the data read is bigger than the number of available bits */ + if (tmp_nr_bits > nr_bits_left) return 1; + nr_bits_left -= tmp_nr_bits; + } + /* Corrigendum */ + if (nr_bits_left > 0) { faad_getbits(ld, nr_bits_left); } + } + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 6 */ +uint8_t NeaacDecoder::sbr_channel_pair_element(bitfile* ld, sbr_info* sbr) { + uint8_t n, result; + if (faad_get1bit(ld)) { + faad_getbits(ld, 4); + faad_getbits(ld, 4); + } + sbr->bs_coupling = faad_get1bit(ld); + if (sbr->bs_coupling) { + if ((result = sbr_grid(ld, sbr, 0)) > 0) return result; + /* need to copy some data from left to right */ + sbr->bs_frame_class[1] = sbr->bs_frame_class[0]; + sbr->L_E[1] = sbr->L_E[0]; + sbr->L_Q[1] = sbr->L_Q[0]; + sbr->bs_pointer[1] = sbr->bs_pointer[0]; + for (n = 0; n <= sbr->L_E[0]; n++) { + sbr->t_E[1][n] = sbr->t_E[0][n]; + sbr->f[1][n] = sbr->f[0][n]; + } + for (n = 0; n <= sbr->L_Q[0]; n++) sbr->t_Q[1][n] = sbr->t_Q[0][n]; + sbr_dtdf(ld, sbr, 0); + sbr_dtdf(ld, sbr, 1); + invf_mode(ld, sbr, 0); + /* more copying */ + for (n = 0; n < sbr->N_Q; n++) sbr->bs_invf_mode[1][n] = sbr->bs_invf_mode[0][n]; + sbr_envelope(ld, sbr, 0); + sbr_noise(ld, sbr, 0); + sbr_envelope(ld, sbr, 1); + sbr_noise(ld, sbr, 1); + memset(sbr->bs_add_harmonic[0], 0, 64 * sizeof(uint8_t)); + memset(sbr->bs_add_harmonic[1], 0, 64 * sizeof(uint8_t)); + sbr->bs_add_harmonic_flag[0] = faad_get1bit(ld); + if (sbr->bs_add_harmonic_flag[0]) sinusoidal_coding(ld, sbr, 0); + sbr->bs_add_harmonic_flag[1] = faad_get1bit(ld); + if (sbr->bs_add_harmonic_flag[1]) sinusoidal_coding(ld, sbr, 1); + } else { + uint8_t saved_t_E[6] = {0}, saved_t_Q[3] = {0}; + uint8_t saved_L_E = sbr->L_E[0]; + uint8_t saved_L_Q = sbr->L_Q[0]; + uint8_t saved_frame_class = sbr->bs_frame_class[0]; + for (n = 0; n < saved_L_E; n++) saved_t_E[n] = sbr->t_E[0][n]; + for (n = 0; n < saved_L_Q; n++) saved_t_Q[n] = sbr->t_Q[0][n]; + if ((result = sbr_grid(ld, sbr, 0)) > 0) return result; + if ((result = sbr_grid(ld, sbr, 1)) > 0) { + /* restore first channel data as well */ + sbr->bs_frame_class[0] = saved_frame_class; + sbr->L_E[0] = saved_L_E; + sbr->L_Q[0] = saved_L_Q; + for (n = 0; n < 6; n++) sbr->t_E[0][n] = saved_t_E[n]; + for (n = 0; n < 3; n++) sbr->t_Q[0][n] = saved_t_Q[n]; + return result; + } + sbr_dtdf(ld, sbr, 0); + sbr_dtdf(ld, sbr, 1); + invf_mode(ld, sbr, 0); + invf_mode(ld, sbr, 1); + sbr_envelope(ld, sbr, 0); + sbr_envelope(ld, sbr, 1); + sbr_noise(ld, sbr, 0); + sbr_noise(ld, sbr, 1); + memset(sbr->bs_add_harmonic[0], 0, 64 * sizeof(uint8_t)); + memset(sbr->bs_add_harmonic[1], 0, 64 * sizeof(uint8_t)); + sbr->bs_add_harmonic_flag[0] = faad_get1bit(ld); + if (sbr->bs_add_harmonic_flag[0]) sinusoidal_coding(ld, sbr, 0); + sbr->bs_add_harmonic_flag[1] = faad_get1bit(ld); + if (sbr->bs_add_harmonic_flag[1]) sinusoidal_coding(ld, sbr, 1); + } + #ifndef FIXED_POINT + envelope_noise_dequantisation(sbr, 0); + envelope_noise_dequantisation(sbr, 1); + if (sbr->bs_coupling) unmap_envelope_noise(sbr); + #endif + sbr->bs_extended_data = faad_get1bit(ld); + if (sbr->bs_extended_data) { + uint16_t nr_bits_left; + uint16_t cnt = (uint16_t)faad_getbits(ld, 4); + if (cnt == 15) { cnt += (uint16_t)faad_getbits(ld, 8); } + nr_bits_left = 8 * cnt; + while (nr_bits_left > 7) { + uint16_t tmp_nr_bits = 0; + sbr->bs_extension_id = (uint8_t)faad_getbits(ld, 2); + tmp_nr_bits += 2; + tmp_nr_bits += sbr_extension(ld, sbr, sbr->bs_extension_id, nr_bits_left); + /* check if the data read is bigger than the number of available bits */ + if (tmp_nr_bits > nr_bits_left) return 1; + nr_bits_left -= tmp_nr_bits; + } + /* Corrigendum */ + if (nr_bits_left > 0) { faad_getbits(ld, nr_bits_left); } + } + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 4 */ +uint8_t NeaacDecoder::sbr_data(bitfile* ld, sbr_info* sbr) { + uint8_t result; + #if 0 + sbr->bs_samplerate_mode = faad_get1bit(ld); + #endif + sbr->rate = (sbr->bs_samplerate_mode) ? 2 : 1; + switch (sbr->id_aac) { + case ID_SCE: + if ((result = sbr_single_channel_element(ld, sbr)) > 0) return result; + break; + case ID_CPE: + if ((result = sbr_channel_pair_element(ld, sbr)) > 0) return result; + break; + } + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* integer log[2](x): input range [0,10) */ +int8_t NeaacDecoder::sbr_log2(const int8_t val) { + int8_t log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3, 4}; + if (val < 10 && val >= 0) + return log2tab[val]; + else + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 7 */ +uint8_t NeaacDecoder::sbr_grid(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t i, env, rel, result; + uint8_t bs_abs_bord, bs_abs_bord_1; + uint8_t bs_num_env = 0; + uint8_t saved_L_E = sbr->L_E[ch]; + uint8_t saved_L_Q = sbr->L_Q[ch]; + uint8_t saved_frame_class = sbr->bs_frame_class[ch]; + sbr->bs_frame_class[ch] = (uint8_t)faad_getbits(ld, 2); + switch (sbr->bs_frame_class[ch]) { + case FIXFIX: + i = (uint8_t)faad_getbits(ld, 2); + bs_num_env = min(1 << i, 5); + i = (uint8_t)faad_get1bit(ld); + for (env = 0; env < bs_num_env; env++) sbr->f[ch][env] = i; + sbr->abs_bord_lead[ch] = 0; + sbr->abs_bord_trail[ch] = sbr->numTimeSlots; + sbr->n_rel_lead[ch] = bs_num_env - 1; + sbr->n_rel_trail[ch] = 0; + break; + case FIXVAR: + bs_abs_bord = (uint8_t)faad_getbits(ld, 2) + sbr->numTimeSlots; + bs_num_env = (uint8_t)faad_getbits(ld, 2) + 1; + for (rel = 0; rel < bs_num_env - 1; rel++) { sbr->bs_rel_bord[ch][rel] = 2 * (uint8_t)faad_getbits(ld, 2) + 2; } + i = sbr_log2(bs_num_env + 1); + sbr->bs_pointer[ch] = (uint8_t)faad_getbits(ld, i); + for (env = 0; env < bs_num_env; env++) { sbr->f[ch][bs_num_env - env - 1] = (uint8_t)faad_get1bit(ld); } + sbr->abs_bord_lead[ch] = 0; + sbr->abs_bord_trail[ch] = bs_abs_bord; + sbr->n_rel_lead[ch] = 0; + sbr->n_rel_trail[ch] = bs_num_env - 1; + break; + case VARFIX: + bs_abs_bord = (uint8_t)faad_getbits(ld, 2); + bs_num_env = (uint8_t)faad_getbits(ld, 2) + 1; + for (rel = 0; rel < bs_num_env - 1; rel++) { sbr->bs_rel_bord[ch][rel] = 2 * (uint8_t)faad_getbits(ld, 2) + 2; } + i = sbr_log2(bs_num_env + 1); + sbr->bs_pointer[ch] = (uint8_t)faad_getbits(ld, i); + for (env = 0; env < bs_num_env; env++) { sbr->f[ch][env] = (uint8_t)faad_get1bit(ld); } + sbr->abs_bord_lead[ch] = bs_abs_bord; + sbr->abs_bord_trail[ch] = sbr->numTimeSlots; + sbr->n_rel_lead[ch] = bs_num_env - 1; + sbr->n_rel_trail[ch] = 0; + break; + case VARVAR: + bs_abs_bord = (uint8_t)faad_getbits(ld, 2); + bs_abs_bord_1 = (uint8_t)faad_getbits(ld, 2) + sbr->numTimeSlots; + sbr->bs_num_rel_0[ch] = (uint8_t)faad_getbits(ld, 2); + sbr->bs_num_rel_1[ch] = (uint8_t)faad_getbits(ld, 2); + bs_num_env = min(5, sbr->bs_num_rel_0[ch] + sbr->bs_num_rel_1[ch] + 1); + for (rel = 0; rel < sbr->bs_num_rel_0[ch]; rel++) { sbr->bs_rel_bord_0[ch][rel] = 2 * (uint8_t)faad_getbits(ld, 2) + 2; } + for (rel = 0; rel < sbr->bs_num_rel_1[ch]; rel++) { sbr->bs_rel_bord_1[ch][rel] = 2 * (uint8_t)faad_getbits(ld, 2) + 2; } + i = sbr_log2(sbr->bs_num_rel_0[ch] + sbr->bs_num_rel_1[ch] + 2); + sbr->bs_pointer[ch] = (uint8_t)faad_getbits(ld, i); + for (env = 0; env < bs_num_env; env++) { sbr->f[ch][env] = (uint8_t)faad_get1bit(ld); } + sbr->abs_bord_lead[ch] = bs_abs_bord; + sbr->abs_bord_trail[ch] = bs_abs_bord_1; + sbr->n_rel_lead[ch] = sbr->bs_num_rel_0[ch]; + sbr->n_rel_trail[ch] = sbr->bs_num_rel_1[ch]; + break; + } + if (sbr->bs_frame_class[ch] == VARVAR) + sbr->L_E[ch] = min(bs_num_env, (uint8_t)5); + else + sbr->L_E[ch] = min(bs_num_env, (uint8_t)4); + if (sbr->L_E[ch] <= 0) return 1; + if (sbr->L_E[ch] > 1) + sbr->L_Q[ch] = 2; + else + sbr->L_Q[ch] = 1; + /* TODO: this code can probably be integrated into the code above! */ + if ((result = envelope_time_border_vector(sbr, ch)) > 0) { + sbr->bs_frame_class[ch] = saved_frame_class; + sbr->L_E[ch] = saved_L_E; + sbr->L_Q[ch] = saved_L_Q; + return result; + } + noise_floor_time_border_vector(sbr, ch); + #if 0 + for (env = 0; env < bs_num_env; env++) + { + printf("freq_res[ch:%d][env:%d]: %d\n", ch, env, sbr->f[ch][env]); + } + #endif + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 8 */ +void NeaacDecoder::sbr_dtdf(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t i; + for (i = 0; i < sbr->L_E[ch]; i++) { sbr->bs_df_env[ch][i] = faad_get1bit(ld); } + for (i = 0; i < sbr->L_Q[ch]; i++) { sbr->bs_df_noise[ch][i] = faad_get1bit(ld); } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* table 9 */ +void NeaacDecoder::invf_mode(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t n; + for (n = 0; n < sbr->N_Q; n++) { sbr->bs_invf_mode[ch][n] = (uint8_t)faad_getbits(ld, 2); } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint16_t NeaacDecoder::sbr_extension(bitfile* ld, sbr_info* sbr, uint8_t bs_extension_id, uint16_t num_bits_left) { + #ifdef PS_DEC + uint8_t header; + uint16_t ret; + #endif + switch (bs_extension_id) { + #ifdef PS_DEC + case EXTENSION_ID_PS: + if (!sbr->ps) { sbr->ps = ps_init(get_sr_index(sbr->sample_rate), sbr->numTimeSlotsRate); } + if (sbr->psResetFlag) { sbr->ps->header_read = 0; } + ret = ps_data(sbr->ps, ld, &header); + /* enable PS if and only if: a header has been decoded */ + if (sbr->ps_used == 0 && header == 1) { sbr->ps_used = 1; } + if (header == 1) { sbr->psResetFlag = 0; } + return ret; + #endif + #ifdef DRM_PS + case DRM_PARAMETRIC_STEREO: + sbr->ps_used = 1; + if (!sbr->drm_ps) { sbr->drm_ps = drm_ps_init(); } + return drm_ps_data(sbr->drm_ps, ld); + #endif + default: sbr->bs_extension_data = (uint8_t)faad_getbits(ld, 6); return 6; + } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* table 12 */ +void NeaacDecoder::sinusoidal_coding(bitfile* ld, sbr_info* sbr, uint8_t ch) { + uint8_t n; + for (n = 0; n < sbr->N_high; n++) { sbr->bs_add_harmonic[ch][n] = faad_get1bit(ld); } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::hf_adjustment(sbr_info* sbr, qmf_t Xsbr[MAX_NTSRHFG][64], real_t* deg /* aliasing degree */, uint8_t ch) { + // sbr_hfadj_info adj = {0}; + sbr_hfadj_info* adj = (sbr_hfadj_info*)faad_calloc(1, sizeof(sbr_hfadj_info)); + uint8_t ret = 0; + if (sbr->bs_frame_class[ch] == FIXFIX) { + sbr->l_A[ch] = -1; + } else if (sbr->bs_frame_class[ch] == VARFIX) { + if (sbr->bs_pointer[ch] > 1) + sbr->l_A[ch] = sbr->bs_pointer[ch] - 1; + else + sbr->l_A[ch] = -1; + } else { + if (sbr->bs_pointer[ch] == 0) + sbr->l_A[ch] = -1; + else + sbr->l_A[ch] = sbr->L_E[ch] + 1 - sbr->bs_pointer[ch]; + } + ret = estimate_current_envelope(sbr, adj, Xsbr, ch); + if (ret > 0) { + ret = 1; + goto exit; + } + calculate_gain(sbr, adj, ch); + #ifdef SBR_LOW_POWER + calc_gain_groups(sbr, adj, deg, ch); + aliasing_reduction(sbr, adj, deg, ch); + #endif + hf_assembly(sbr, adj, Xsbr, ch); + ret = 0; +exit: + if (adj) free(adj); + return ret; +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::get_S_mapped(sbr_info* sbr, uint8_t ch, uint8_t l, uint8_t current_band) { + if (sbr->f[ch][l] == HI_RES) { + /* in case of using f_table_high we just have 1 to 1 mapping + * from bs_add_harmonic[l][k] + */ + if ((l >= sbr->l_A[ch]) || (sbr->bs_add_harmonic_prev[ch][current_band] && sbr->bs_add_harmonic_flag_prev[ch])) { return sbr->bs_add_harmonic[ch][current_band]; } + } else { + uint8_t b, lb, ub; + /* in case of f_table_low we check if any of the HI_RES bands + * within this LO_RES band has bs_add_harmonic[l][k] turned on + * (note that borders in the LO_RES table are also present in + * the HI_RES table) + */ + /* find first HI_RES band in current LO_RES band */ + lb = 2 * current_band - ((sbr->N_high & 1) ? 1 : 0); + /* find first HI_RES band in next LO_RES band */ + ub = 2 * (current_band + 1) - ((sbr->N_high & 1) ? 1 : 0); + /* check all HI_RES bands in current LO_RES band for sinusoid */ + for (b = lb; b < ub; b++) { + if ((l >= sbr->l_A[ch]) || (sbr->bs_add_harmonic_prev[ch][b] && sbr->bs_add_harmonic_flag_prev[ch])) { + if (sbr->bs_add_harmonic[ch][b] == 1) return 1; + } + } + } + return 0; +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::estimate_current_envelope(sbr_info* sbr, sbr_hfadj_info* adj, qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch) { + uint8_t m, l, j, k, k_l, k_h, p; + real_t nrg, div; + if (sbr->bs_interpol_freq == 1) { + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t i, l_i, u_i; + l_i = sbr->t_E[ch][l]; + u_i = sbr->t_E[ch][l + 1]; + div = (real_t)(u_i - l_i); + if (div == 0) div = 1; + for (m = 0; m < sbr->M; m++) { + nrg = 0; + for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++) { + #ifdef FIXED_POINT + #ifdef SBR_LOW_POWER + nrg += ((QMF_RE(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_RE(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + #else + nrg += ((QMF_RE(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_RE(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) + + ((QMF_IM(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_IM(Xsbr[i][m + sbr->kx]) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + #endif + #else + nrg += MUL_R(QMF_RE(Xsbr[i][m + sbr->kx]), QMF_RE(Xsbr[i][m + sbr->kx])) + #ifndef SBR_LOW_POWER + + MUL_R(QMF_IM(Xsbr[i][m + sbr->kx]), QMF_IM(Xsbr[i][m + sbr->kx])) + #endif + ; + #endif + } + sbr->E_curr[ch][m][l] = nrg / div; + #ifdef SBR_LOW_POWER + #ifdef FIXED_POINT + sbr->E_curr[ch][m][l] <<= 1; + #else + sbr->E_curr[ch][m][l] *= 2; + #endif + #endif + } + } + } else { + for (l = 0; l < sbr->L_E[ch]; l++) { + for (p = 0; p < sbr->n[sbr->f[ch][l]]; p++) { + k_l = sbr->f_table_res[sbr->f[ch][l]][p]; + k_h = sbr->f_table_res[sbr->f[ch][l]][p + 1]; + for (k = k_l; k < k_h; k++) { + uint8_t i, l_i, u_i; + nrg = 0; + l_i = sbr->t_E[ch][l]; + u_i = sbr->t_E[ch][l + 1]; + div = (real_t)((u_i - l_i) * (k_h - k_l)); + if (div == 0) div = 1; + for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++) { + for (j = k_l; j < k_h; j++) { + #ifdef FIXED_POINT + #ifdef SBR_LOW_POWER + nrg += ((QMF_RE(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_RE(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + #else + nrg += ((QMF_RE(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_RE(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) + + ((QMF_IM(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS) * ((QMF_IM(Xsbr[i][j]) + (1 << (REAL_BITS - 1))) >> REAL_BITS); + #endif + #else + nrg += MUL_R(QMF_RE(Xsbr[i][j]), QMF_RE(Xsbr[i][j])) + #ifndef SBR_LOW_POWER + + MUL_R(QMF_IM(Xsbr[i][j]), QMF_IM(Xsbr[i][j])) + #endif + ; + #endif + } + } + sbr->E_curr[ch][k - sbr->kx][l] = nrg / div; + #ifdef SBR_LOW_POWER + #ifdef FIXED_POINT + sbr->E_curr[ch][k - sbr->kx][l] <<= 1; + #else + sbr->E_curr[ch][k - sbr->kx][l] *= 2; + #endif + #endif + } + } + } + } + return 0; +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +real_t NeaacDecoder::find_log2_E(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + uint8_t amp0 = (sbr->amp_res[0]) ? 0 : 1; + uint8_t amp1 = (sbr->amp_res[1]) ? 0 : 1; + real_t tmp = (7 << REAL_BITS) + (sbr->E[0][k][l] << (REAL_BITS - amp0)); + real_t pan; + /* E[1] should always be even so shifting is OK */ + uint8_t E = sbr->E[1][k][l] >> amp1; + if (ch == 0) { + if (E > 12) { + /* negative */ + pan = pan_log2_tab[-12 + E]; + } else { + /* positive */ + pan = pan_log2_tab[12 - E] + ((12 - E) << REAL_BITS); + } + } else { + if (E < 12) { + /* negative */ + pan = pan_log2_tab[-E + 12]; + } else { + /* positive */ + pan = pan_log2_tab[E - 12] + ((E - 12) << REAL_BITS); + } + } + /* tmp / pan in log2 */ + return tmp - pan; + } else { + uint8_t amp = (sbr->amp_res[ch]) ? 0 : 1; + return (6 << REAL_BITS) + (sbr->E[ch][k][l] << (REAL_BITS - amp)); + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +real_t NeaacDecoder::find_log2_Q(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + real_t tmp = (7 << REAL_BITS) - (sbr->Q[0][k][l] << REAL_BITS); + real_t pan; + uint8_t Q = sbr->Q[1][k][l]; + if (ch == 0) { + if (Q > 12) { + /* negative */ + pan = pan_log2_tab[-12 + Q]; + } else { + /* positive */ + pan = pan_log2_tab[12 - Q] + ((12 - Q) << REAL_BITS); + } + } else { + if (Q < 12) { + /* negative */ + pan = pan_log2_tab[-Q + 12]; + } else { + /* positive */ + pan = pan_log2_tab[Q - 12] + ((Q - 12) << REAL_BITS); + } + } + /* tmp / pan in log2 */ + return tmp - pan; + } else { + return (6 << REAL_BITS) - (sbr->Q[ch][k][l] << REAL_BITS); + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +real_t NeaacDecoder::find_log2_Qplus1(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch) { + /* check for coupled energy/noise data */ + if (sbr->bs_coupling == 1) { + if ((sbr->Q[0][k][l] >= 0) && (sbr->Q[0][k][l] <= 30) && (sbr->Q[1][k][l] >= 0) && (sbr->Q[1][k][l] <= 24)) { + if (ch == 0) { + return log_Qplus1_pan[sbr->Q[0][k][l]][sbr->Q[1][k][l] >> 1]; + } else { + return log_Qplus1_pan[sbr->Q[0][k][l]][12 - (sbr->Q[1][k][l] >> 1)]; + } + } else { + return 0; + } + } else { + if (sbr->Q[ch][k][l] >= 0 && sbr->Q[ch][k][l] <= 30) { + return log_Qplus1[sbr->Q[ch][k][l]]; + } else { + return 0; + } + } +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef FIXED_POINT +void NeaacDecoder::calculate_gain(sbr_info* sbr, sbr_hfadj_info* adj, uint8_t ch) { + /* log2 values of limiter gains */ + real_t limGain[] = {REAL_CONST(-1.0), REAL_CONST(0.0), REAL_CONST(1.0), REAL_CONST(33.219)}; + uint8_t m, l, k; + uint8_t current_t_noise_band = 0; + uint8_t S_mapped; + // real_t Q_M_lim[MAX_M]; + // real_t G_lim[MAX_M]; + // real_t S_M[MAX_M]; + real_t G_boost; + real_t* Q_M_lim = (real_t*)faad_malloc(MAX_M * sizeof(real_t)); + real_t* G_lim = (real_t*)faad_malloc(MAX_M * sizeof(real_t)); + real_t* S_M = (real_t*)faad_malloc(MAX_M * sizeof(real_t)); + for (l = 0; l < sbr->L_E[ch]; l++) { + uint8_t current_f_noise_band = 0; + uint8_t current_res_band = 0; + uint8_t current_res_band2 = 0; + uint8_t current_hi_res_band = 0; + real_t delta = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 0 : 1; + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + if (sbr->t_E[ch][l + 1] > sbr->t_Q[ch][current_t_noise_band + 1]) { current_t_noise_band++; } + for (k = 0; k < sbr->N_L[sbr->bs_limiter_bands]; k++) { + real_t Q_M = 0; + real_t G_max; + real_t den = 0; + real_t acc1 = 0; + real_t acc2 = 0; + uint8_t current_res_band_size = 0; + uint8_t Q_M_size = 0; + uint8_t ml1, ml2; + /* bounds of current limiter bands */ + ml1 = sbr->f_table_lim[sbr->bs_limiter_bands][k]; + ml2 = sbr->f_table_lim[sbr->bs_limiter_bands][k + 1]; + if (ml1 > MAX_M) ml1 = MAX_M; + if (ml2 > MAX_M) ml2 = MAX_M; + /* calculate the accumulated E_orig and E_curr over the limiter band */ + for (m = ml1; m < ml2; m++) { + if ((m + sbr->kx) < sbr->f_table_res[sbr->f[ch][l]][current_res_band + 1]) { + current_res_band_size++; + } else { + acc1 += pow2_int(-REAL_CONST(10) + log2_int_tab[current_res_band_size] + find_log2_E(sbr, current_res_band, l, ch)); + current_res_band++; + current_res_band_size = 1; + } + acc2 += sbr->E_curr[ch][m][l]; + } + acc1 += pow2_int(-REAL_CONST(10) + log2_int_tab[current_res_band_size] + find_log2_E(sbr, current_res_band, l, ch)); + if (acc1 == 0) + acc1 = LOG2_MIN_INF; + else + acc1 = log2_int(acc1); + /* calculate the maximum gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + G_max = acc1 - log2_int(acc2) + limGain[sbr->bs_limiter_gains]; + G_max = min(G_max, limGain[3]); + for (m = ml1; m < ml2; m++) { + real_t G; + real_t E_curr, E_orig; + real_t Q_orig, Q_orig_plus1; + uint8_t S_index_mapped; + /* check if m is on a noise band border */ + if ((m + sbr->kx) == sbr->f_table_noise[current_f_noise_band + 1]) { + /* step to next noise band */ + current_f_noise_band++; + } + /* check if m is on a resolution band border */ + if ((m + sbr->kx) == sbr->f_table_res[sbr->f[ch][l]][current_res_band2 + 1]) { + /* accumulate a whole range of equal Q_Ms */ + if (Q_M_size > 0) den += pow2_int(log2_int_tab[Q_M_size] + Q_M); + Q_M_size = 0; + /* step to next resolution band */ + current_res_band2++; + /* if we move to a new resolution band, we should check if we are + * going to add a sinusoid in this band + */ + S_mapped = get_S_mapped(sbr, ch, l, current_res_band2); + } + /* check if m is on a HI_RES band border */ + if ((m + sbr->kx) == sbr->f_table_res[HI_RES][current_hi_res_band + 1]) { + /* step to next HI_RES band */ + current_hi_res_band++; + } + /* find S_index_mapped + * S_index_mapped can only be 1 for the m in the middle of the + * current HI_RES band + */ + S_index_mapped = 0; + if ((l >= sbr->l_A[ch]) || (sbr->bs_add_harmonic_prev[ch][current_hi_res_band] && sbr->bs_add_harmonic_flag_prev[ch])) { + /* find the middle subband of the HI_RES frequency band */ + if ((m + sbr->kx) == (sbr->f_table_res[HI_RES][current_hi_res_band + 1] + sbr->f_table_res[HI_RES][current_hi_res_band]) >> 1) + S_index_mapped = sbr->bs_add_harmonic[ch][current_hi_res_band]; + } + /* find bitstream parameters */ + if (sbr->E_curr[ch][m][l] == 0) + E_curr = LOG2_MIN_INF; + else + E_curr = log2_int(sbr->E_curr[ch][m][l]); + E_orig = -REAL_CONST(10) + find_log2_E(sbr, current_res_band2, l, ch); + Q_orig = find_log2_Q(sbr, current_f_noise_band, current_t_noise_band, ch); + Q_orig_plus1 = find_log2_Qplus1(sbr, current_f_noise_band, current_t_noise_band, ch); + /* Q_M only depends on E_orig and Q_div2: + * since N_Q <= N_Low <= N_High we only need to recalculate Q_M on + * a change of current res band (HI or LO) + */ + Q_M = E_orig + Q_orig - Q_orig_plus1; + /* S_M only depends on E_orig, Q_div and S_index_mapped: + * S_index_mapped can only be non-zero once per HI_RES band + */ + if (S_index_mapped == 0) { + S_M[m] = LOG2_MIN_INF; /* -inf */ + } else { + S_M[m] = E_orig - Q_orig_plus1; + /* accumulate sinusoid part of the total energy */ + den += pow2_int(S_M[m]); + } + /* calculate gain */ + /* ratio of the energy of the original signal and the energy + * of the HF generated signal + */ + /* E_curr here is officially E_curr+1 so the log2() of that can never be < 0 */ + /* scaled by -10 */ + G = E_orig - max(-REAL_CONST(10), E_curr); + if ((S_mapped == 0) && (delta == 1)) { + /* G = G * 1/(1+Q) */ + G -= Q_orig_plus1; + } else if (S_mapped == 1) { + /* G = G * Q/(1+Q) */ + G += Q_orig - Q_orig_plus1; + } + /* limit the additional noise energy level */ + /* and apply the limiter */ + if (G_max > G) { + Q_M_lim[m] = Q_M; + G_lim[m] = G; + if ((S_index_mapped == 0) && (l != sbr->l_A[ch])) { Q_M_size++; } + } else { + /* G > G_max */ + Q_M_lim[m] = Q_M + G_max - G; + G_lim[m] = G_max; + /* accumulate limited Q_M */ + if ((S_index_mapped == 0) && (l != sbr->l_A[ch])) { den += pow2_int(Q_M_lim[m]); } + } + /* accumulate the total energy */ + /* E_curr changes for every m so we do need to accumulate every m */ + den += pow2_int(E_curr + G_lim[m]); + } + /* accumulate last range of equal Q_Ms */ + if (Q_M_size > 0) { den += pow2_int(log2_int_tab[Q_M_size] + Q_M); } + /* calculate the final gain */ + /* G_boost: [0..2.51188643] */ + G_boost = acc1 - log2_int(den /*+ _EPS*/); + G_boost = min(G_boost, REAL_CONST(1.328771237) /* log2(1.584893192 ^ 2) */); + for (m = ml1; m < ml2; m++) { + /* apply compensation to gain, noise floor sf's and sinusoid levels */ + #ifndef SBR_LOW_POWER + adj->G_lim_boost[l][m] = pow2_fix((G_lim[m] + G_boost) >> 1); + #else + /* sqrt() will be done after the aliasing reduction to save a + * few multiplies + */ + adj->G_lim_boost[l][m] = pow2_fix(G_lim[m] + G_boost); + #endif + adj->Q_M_lim_boost[l][m] = pow2_fix((Q_M_lim[m] + G_boost) >> 1); + if (S_M[m] != LOG2_MIN_INF) { + adj->S_M_boost[l][m] = pow2_int((S_M[m] + G_boost) >> 1); + } else { + adj->S_M_boost[l][m] = 0; + } + } + } + } + if (Q_M_lim) free(Q_M_lim); + if (G_lim) free(G_lim); + if (S_M) free(S_M); +} + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef FIXED_POINT + #ifdef LOG2_TEST + #define LOG2_MIN_INF -100000 +float NeaacDecoder::pow2(float val) { + return pow(2.0, val); +} +float NeaacDecoder::log2(float val) { + return log(val) / log(2.0); +} + #define RB 14 +float QUANTISE2REAL(float val) { + __int32 ival = (__int32)(val * (1 << RB)); + return (float)ival / (float)((1 << RB)); +} +float QUANTISE2INT(float val) { + return floor(val); +} + #endif // LOG2_TEST + #endif // FIXED_POINT +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::hf_generation(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], qmf_t Xhigh[MAX_NTSRHFG][64], real_t* deg, uint8_t ch) { + uint8_t l, i, x; + // complex_t alpha_0[64], alpha_1[64]; + complex_t* alpha_0 = (complex_t*)faad_malloc(64 * sizeof(complex_t)); + complex_t* alpha_1 = (complex_t*)faad_malloc(64 * sizeof(complex_t)); + #ifdef SBR_LOW_POWER + // real_t rxx[64]; + real_t* rxx = faad_malloc(64 * sizeof(real_t)); + #endif + uint8_t offset = sbr->tHFAdj; + uint8_t first = sbr->t_E[ch][0]; + uint8_t last = sbr->t_E[ch][sbr->L_E[ch]]; + calc_chirp_factors(sbr, ch); + #ifdef SBR_LOW_POWER + memset(deg, 0, 64 * sizeof(real_t)); + #endif + if ((ch == 0) && (sbr->Reset)) patch_construction(sbr); + /* calculate the prediction coefficients */ + #ifdef SBR_LOW_POWER + calc_prediction_coef_lp(sbr, Xlow, alpha_0, alpha_1, rxx); + calc_aliasing_degree(sbr, rxx, deg); + #endif + /* actual HF generation */ + for (i = 0; i < sbr->noPatches; i++) { + for (x = 0; x < sbr->patchNoSubbands[i]; x++) { + real_t a0_r, a0_i, a1_r, a1_i; + (void)a0_i; + (void)a1_i; + real_t bw, bw2; + uint8_t q, p, k, g; + /* find the low and high band for patching */ + k = sbr->kx + x; + for (q = 0; q < i; q++) { k += sbr->patchNoSubbands[q]; } + p = sbr->patchStartSubband[i] + x; + #ifdef SBR_LOW_POWER + if (x != 0 /*x < sbr->patchNoSubbands[i]-1*/) + deg[k] = deg[p]; + else + deg[k] = 0; + #endif + g = sbr->table_map_k_to_g[k]; + bw = sbr->bwArray[ch][g]; + bw2 = MUL_C(bw, bw); + /* do the patching */ + /* with or without filtering */ + if (bw2 > 0) { + real_t temp1_r, temp2_r, temp3_r; + #ifndef SBR_LOW_POWER + real_t temp1_i, temp2_i, temp3_i; + calc_prediction_coef(sbr, Xlow, alpha_0, alpha_1, p); + #endif + a0_r = MUL_C(RE(alpha_0[p]), bw); + a1_r = MUL_C(RE(alpha_1[p]), bw2); + #ifndef SBR_LOW_POWER + a0_i = MUL_C(IM(alpha_0[p]), bw); + a1_i = MUL_C(IM(alpha_1[p]), bw2); + #endif + temp2_r = QMF_RE(Xlow[first - 2 + offset][p]); + temp3_r = QMF_RE(Xlow[first - 1 + offset][p]); + #ifndef SBR_LOW_POWER + temp2_i = QMF_IM(Xlow[first - 2 + offset][p]); + temp3_i = QMF_IM(Xlow[first - 1 + offset][p]); + #endif + for (l = first; l < last; l++) { + temp1_r = temp2_r; + temp2_r = temp3_r; + temp3_r = QMF_RE(Xlow[l + offset][p]); + #ifndef SBR_LOW_POWER + temp1_i = temp2_i; + temp2_i = temp3_i; + temp3_i = QMF_IM(Xlow[l + offset][p]); + #endif + #ifdef SBR_LOW_POWER + QMF_RE(Xhigh[l + offset][k]) = temp3_r + (MUL_R(a0_r, temp2_r) + MUL_R(a1_r, temp1_r)); + #else + QMF_RE(Xhigh[l + offset][k]) = temp3_r + (MUL_R(a0_r, temp2_r) - MUL_R(a0_i, temp2_i) + MUL_R(a1_r, temp1_r) - MUL_R(a1_i, temp1_i)); + QMF_IM(Xhigh[l + offset][k]) = temp3_i + (MUL_R(a0_i, temp2_r) + MUL_R(a0_r, temp2_i) + MUL_R(a1_i, temp1_r) + MUL_R(a1_r, temp1_i)); + #endif + } + } else { + for (l = first; l < last; l++) { + QMF_RE(Xhigh[l + offset][k]) = QMF_RE(Xlow[l + offset][p]); + #ifndef SBR_LOW_POWER + QMF_IM(Xhigh[l + offset][k]) = QMF_IM(Xlow[l + offset][p]); + #endif + } + } + } + } + if (sbr->Reset) { limiter_frequency_table(sbr); } + faad_free(&alpha_0); + faad_free(&alpha_1); + #ifdef SBR_LOW_POWER + faad_free(&rxx); + #endif +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::auto_correlation(sbr_info* sbr, acorr_coef* ac, qmf_t buffer[MAX_NTSRHFG][64], uint8_t bd, uint8_t len) { + real_t r01 = 0, r02 = 0, r11 = 0; + int8_t j; + uint8_t offset = sbr->tHFAdj; + #ifdef FIXED_POINT + const real_t rel = FRAC_CONST(0.999999); // 1 / (1 + 1e-6f); + uint32_t maxi = 0; + (void)maxi; + uint32_t pow2, exp; + (void)pow2; + #else + const real_t rel = 1 / (1 + 1e-6f); + #endif + #ifdef FIXED_POINT + uint32_t mask = 0; + for (j = (offset - 2); j < (len + offset); j++) { + real_t x; + x = QMF_RE(buffer[j][bd]) >> REAL_BITS; + mask |= x ^ (x >> 31); + } + exp = wl_min_lzc(mask); + /* improves accuracy */ + if (exp > 0) exp -= 1; + for (j = offset; j < len + offset; j++) { + real_t buf_j = ((QMF_RE(buffer[j][bd]) + (1 << (exp - 1))) >> exp); + real_t buf_j_1 = ((QMF_RE(buffer[j - 1][bd]) + (1 << (exp - 1))) >> exp); + real_t buf_j_2 = ((QMF_RE(buffer[j - 2][bd]) + (1 << (exp - 1))) >> exp); + /* normalisation with rounding */ + r01 += MUL_R(buf_j, buf_j_1); + r02 += MUL_R(buf_j, buf_j_2); + r11 += MUL_R(buf_j_1, buf_j_1); + } + RE(ac->r12) = r01 - MUL_R(((QMF_RE(buffer[len + offset - 1][bd]) + (1 << (exp - 1))) >> exp), ((QMF_RE(buffer[len + offset - 2][bd]) + (1 << (exp - 1))) >> exp)) + + MUL_R(((QMF_RE(buffer[offset - 1][bd]) + (1 << (exp - 1))) >> exp), ((QMF_RE(buffer[offset - 2][bd]) + (1 << (exp - 1))) >> exp)); + RE(ac->r22) = r11 - MUL_R(((QMF_RE(buffer[len + offset - 2][bd]) + (1 << (exp - 1))) >> exp), ((QMF_RE(buffer[len + offset - 2][bd]) + (1 << (exp - 1))) >> exp)) + + MUL_R(((QMF_RE(buffer[offset - 2][bd]) + (1 << (exp - 1))) >> exp), ((QMF_RE(buffer[offset - 2][bd]) + (1 << (exp - 1))) >> exp)); + #else + for (j = offset; j < len + offset; j++) { + r01 += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j - 1][bd]); + r02 += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j - 2][bd]); + r11 += QMF_RE(buffer[j - 1][bd]) * QMF_RE(buffer[j - 1][bd]); + } + RE(ac->r12) = r01 - QMF_RE(buffer[len + offset - 1][bd]) * QMF_RE(buffer[len + offset - 2][bd]) + QMF_RE(buffer[offset - 1][bd]) * QMF_RE(buffer[offset - 2][bd]); + RE(ac->r22) = r11 - QMF_RE(buffer[len + offset - 2][bd]) * QMF_RE(buffer[len + offset - 2][bd]) + QMF_RE(buffer[offset - 2][bd]) * QMF_RE(buffer[offset - 2][bd]); + #endif + RE(ac->r01) = r01; + RE(ac->r02) = r02; + RE(ac->r11) = r11; + ac->det = MUL_R(RE(ac->r11), RE(ac->r22)) - MUL_F(MUL_R(RE(ac->r12), RE(ac->r12)), rel); +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +void NeaacDecoder::auto_correlation(sbr_info* sbr, acorr_coef* ac, qmf_t buffer[MAX_NTSRHFG][64], uint8_t bd, uint8_t len) { + real_t r01r = 0, r01i = 0, r02r = 0, r02i = 0, r11r = 0; + real_t temp1_r, temp1_i, temp2_r, temp2_i, temp3_r, temp3_i, temp4_r, temp4_i, temp5_r, temp5_i; + #ifdef FIXED_POINT + const real_t rel = FRAC_CONST(0.999999); // 1 / (1 + 1e-6f); + uint32_t mask, exp; + real_t pow2_to_exp; + #else + const real_t rel = 1 / (1 + 1e-6f); + #endif + int8_t j; + uint8_t offset = sbr->tHFAdj; + #ifdef FIXED_POINT + mask = 0; + for (j = (offset - 2); j < (len + offset); j++) { + real_t x; + x = QMF_RE(buffer[j][bd]) >> REAL_BITS; + mask |= x ^ (x >> 31); + x = QMF_IM(buffer[j][bd]) >> REAL_BITS; + mask |= x ^ (x >> 31); + } + exp = wl_min_lzc(mask); + /* improves accuracy */ + if (exp > 0) exp -= 1; + pow2_to_exp = 1 << (exp - 1); + temp2_r = (QMF_RE(buffer[offset - 2][bd]) + pow2_to_exp) >> exp; + temp2_i = (QMF_IM(buffer[offset - 2][bd]) + pow2_to_exp) >> exp; + temp3_r = (QMF_RE(buffer[offset - 1][bd]) + pow2_to_exp) >> exp; + temp3_i = (QMF_IM(buffer[offset - 1][bd]) + pow2_to_exp) >> exp; + // Save these because they are needed after loop + temp4_r = temp2_r; + temp4_i = temp2_i; + temp5_r = temp3_r; + temp5_i = temp3_i; + for (j = offset; j < len + offset; j++) { + temp1_r = temp2_r; // temp1_r = (QMF_RE(buffer[offset-2][bd] + (1<<(exp-1))) >> exp; + temp1_i = temp2_i; // temp1_i = (QMF_IM(buffer[offset-2][bd] + (1<<(exp-1))) >> exp; + temp2_r = temp3_r; // temp2_r = (QMF_RE(buffer[offset-1][bd] + (1<<(exp-1))) >> exp; + temp2_i = temp3_i; // temp2_i = (QMF_IM(buffer[offset-1][bd] + (1<<(exp-1))) >> exp; + temp3_r = (QMF_RE(buffer[j][bd]) + pow2_to_exp) >> exp; + temp3_i = (QMF_IM(buffer[j][bd]) + pow2_to_exp) >> exp; + r01r += MUL_R(temp3_r, temp2_r) + MUL_R(temp3_i, temp2_i); + r01i += MUL_R(temp3_i, temp2_r) - MUL_R(temp3_r, temp2_i); + r02r += MUL_R(temp3_r, temp1_r) + MUL_R(temp3_i, temp1_i); + r02i += MUL_R(temp3_i, temp1_r) - MUL_R(temp3_r, temp1_i); + r11r += MUL_R(temp2_r, temp2_r) + MUL_R(temp2_i, temp2_i); + } + // These are actual values in temporary variable at this point + // temp1_r = (QMF_RE(buffer[len+offset-1-2][bd] + (1<<(exp-1))) >> exp; + // temp1_i = (QMF_IM(buffer[len+offset-1-2][bd] + (1<<(exp-1))) >> exp; + // temp2_r = (QMF_RE(buffer[len+offset-1-1][bd] + (1<<(exp-1))) >> exp; + // temp2_i = (QMF_IM(buffer[len+offset-1-1][bd] + (1<<(exp-1))) >> exp; + // temp3_r = (QMF_RE(buffer[len+offset-1][bd]) + (1<<(exp-1))) >> exp; + // temp3_i = (QMF_IM(buffer[len+offset-1][bd]) + (1<<(exp-1))) >> exp; + // temp4_r = (QMF_RE(buffer[offset-2][bd]) + (1<<(exp-1))) >> exp; + // temp4_i = (QMF_IM(buffer[offset-2][bd]) + (1<<(exp-1))) >> exp; + // temp5_r = (QMF_RE(buffer[offset-1][bd]) + (1<<(exp-1))) >> exp; + // temp5_i = (QMF_IM(buffer[offset-1][bd]) + (1<<(exp-1))) >> exp; + RE(ac->r12) = r01r - (MUL_R(temp3_r, temp2_r) + MUL_R(temp3_i, temp2_i)) + (MUL_R(temp5_r, temp4_r) + MUL_R(temp5_i, temp4_i)); + IM(ac->r12) = r01i - (MUL_R(temp3_i, temp2_r) - MUL_R(temp3_r, temp2_i)) + (MUL_R(temp5_i, temp4_r) - MUL_R(temp5_r, temp4_i)); + RE(ac->r22) = r11r - (MUL_R(temp2_r, temp2_r) + MUL_R(temp2_i, temp2_i)) + (MUL_R(temp4_r, temp4_r) + MUL_R(temp4_i, temp4_i)); + #else + temp2_r = QMF_RE(buffer[offset - 2][bd]); + temp2_i = QMF_IM(buffer[offset - 2][bd]); + temp3_r = QMF_RE(buffer[offset - 1][bd]); + temp3_i = QMF_IM(buffer[offset - 1][bd]); + // Save these because they are needed after loop + temp4_r = temp2_r; + temp4_i = temp2_i; + temp5_r = temp3_r; + temp5_i = temp3_i; + for (j = offset; j < len + offset; j++) { + temp1_r = temp2_r; // temp1_r = QMF_RE(buffer[j-2][bd]; + temp1_i = temp2_i; // temp1_i = QMF_IM(buffer[j-2][bd]; + temp2_r = temp3_r; // temp2_r = QMF_RE(buffer[j-1][bd]; + temp2_i = temp3_i; // temp2_i = QMF_IM(buffer[j-1][bd]; + temp3_r = QMF_RE(buffer[j][bd]); + temp3_i = QMF_IM(buffer[j][bd]); + r01r += temp3_r * temp2_r + temp3_i * temp2_i; + r01i += temp3_i * temp2_r - temp3_r * temp2_i; + r02r += temp3_r * temp1_r + temp3_i * temp1_i; + r02i += temp3_i * temp1_r - temp3_r * temp1_i; + r11r += temp2_r * temp2_r + temp2_i * temp2_i; + } + // These are actual values in temporary variable at this point + // temp1_r = QMF_RE(buffer[len+offset-1-2][bd]; + // temp1_i = QMF_IM(buffer[len+offset-1-2][bd]; + // temp2_r = QMF_RE(buffer[len+offset-1-1][bd]; + // temp2_i = QMF_IM(buffer[len+offset-1-1][bd]; + // temp3_r = QMF_RE(buffer[len+offset-1][bd]); + // temp3_i = QMF_IM(buffer[len+offset-1][bd]); + // temp4_r = QMF_RE(buffer[offset-2][bd]); + // temp4_i = QMF_IM(buffer[offset-2][bd]); + // temp5_r = QMF_RE(buffer[offset-1][bd]); + // temp5_i = QMF_IM(buffer[offset-1][bd]); + RE(ac->r12) = r01r - (temp3_r * temp2_r + temp3_i * temp2_i) + (temp5_r * temp4_r + temp5_i * temp4_i); + IM(ac->r12) = r01i - (temp3_i * temp2_r - temp3_r * temp2_i) + (temp5_i * temp4_r - temp5_r * temp4_i); + RE(ac->r22) = r11r - (temp2_r * temp2_r + temp2_i * temp2_i) + (temp4_r * temp4_r + temp4_i * temp4_i); + #endif + RE(ac->r01) = r01r; + IM(ac->r01) = r01i; + RE(ac->r02) = r02r; + IM(ac->r02) = r02i; + RE(ac->r11) = r11r; + ac->det = MUL_R(RE(ac->r11), RE(ac->r22)) - MUL_F(rel, (MUL_R(RE(ac->r12), RE(ac->r12)) + MUL_R(IM(ac->r12), IM(ac->r12)))); +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +/* calculate linear prediction coefficients using the covariance method */ +void NeaacDecoder::calc_prediction_coef(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], complex_t* alpha_0, complex_t* alpha_1, uint8_t k) { + real_t tmp; + acorr_coef ac; + auto_correlation(sbr, &ac, Xlow, k, sbr->numTimeSlotsRate + 6); + if (ac.det == 0) { + RE(alpha_1[k]) = 0; + IM(alpha_1[k]) = 0; + } else { + #ifdef FIXED_POINT + tmp = (MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(IM(ac.r01), IM(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11))); + RE(alpha_1[k]) = DIV_R(tmp, ac.det); + tmp = (MUL_R(IM(ac.r01), RE(ac.r12)) + MUL_R(RE(ac.r01), IM(ac.r12)) - MUL_R(IM(ac.r02), RE(ac.r11))); + IM(alpha_1[k]) = DIV_R(tmp, ac.det); + #else + tmp = REAL_CONST(1.0) / ac.det; + RE(alpha_1[k]) = (MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(IM(ac.r01), IM(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11))) * tmp; + IM(alpha_1[k]) = (MUL_R(IM(ac.r01), RE(ac.r12)) + MUL_R(RE(ac.r01), IM(ac.r12)) - MUL_R(IM(ac.r02), RE(ac.r11))) * tmp; + #endif + } + if (RE(ac.r11) == 0) { + RE(alpha_0[k]) = 0; + IM(alpha_0[k]) = 0; + } else { + #ifdef FIXED_POINT + tmp = -(RE(ac.r01) + MUL_R(RE(alpha_1[k]), RE(ac.r12)) + MUL_R(IM(alpha_1[k]), IM(ac.r12))); + RE(alpha_0[k]) = DIV_R(tmp, RE(ac.r11)); + tmp = -(IM(ac.r01) + MUL_R(IM(alpha_1[k]), RE(ac.r12)) - MUL_R(RE(alpha_1[k]), IM(ac.r12))); + IM(alpha_0[k]) = DIV_R(tmp, RE(ac.r11)); + #else + tmp = 1.0f / RE(ac.r11); + RE(alpha_0[k]) = -(RE(ac.r01) + MUL_R(RE(alpha_1[k]), RE(ac.r12)) + MUL_R(IM(alpha_1[k]), IM(ac.r12))) * tmp; + IM(alpha_0[k]) = -(IM(ac.r01) + MUL_R(IM(alpha_1[k]), RE(ac.r12)) - MUL_R(RE(alpha_1[k]), IM(ac.r12))) * tmp; + #endif + } + if ((MUL_R(RE(alpha_0[k]), RE(alpha_0[k])) + MUL_R(IM(alpha_0[k]), IM(alpha_0[k])) >= REAL_CONST(16)) || + (MUL_R(RE(alpha_1[k]), RE(alpha_1[k])) + MUL_R(IM(alpha_1[k]), IM(alpha_1[k])) >= REAL_CONST(16))) { + RE(alpha_0[k]) = 0; + IM(alpha_0[k]) = 0; + RE(alpha_1[k]) = 0; + IM(alpha_1[k]) = 0; + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::calc_prediction_coef_lp(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], complex_t* alpha_0, complex_t* alpha_1, real_t* rxx) { + uint8_t k; + real_t tmp; + acorr_coef ac; + for (k = 1; k < sbr->f_master[0]; k++) { + auto_correlation(sbr, &ac, Xlow, k, sbr->numTimeSlotsRate + 6); + if (ac.det == 0) { + RE(alpha_0[k]) = 0; + RE(alpha_1[k]) = 0; + } else { + tmp = MUL_R(RE(ac.r01), RE(ac.r22)) - MUL_R(RE(ac.r12), RE(ac.r02)); + RE(alpha_0[k]) = DIV_R(tmp, (-ac.det)); + tmp = MUL_R(RE(ac.r01), RE(ac.r12)) - MUL_R(RE(ac.r02), RE(ac.r11)); + RE(alpha_1[k]) = DIV_R(tmp, ac.det); + } + if ((RE(alpha_0[k]) >= REAL_CONST(4)) || (RE(alpha_1[k]) >= REAL_CONST(4))) { + RE(alpha_0[k]) = REAL_CONST(0); + RE(alpha_1[k]) = REAL_CONST(0); + } + /* reflection coefficient */ + if (RE(ac.r11) == 0) { + rxx[k] = COEF_CONST(0.0); + } else { + rxx[k] = DIV_C(RE(ac.r01), RE(ac.r11)); + rxx[k] = -rxx[k]; + if (rxx[k] > COEF_CONST(1.0)) rxx[k] = COEF_CONST(1.0); + if (rxx[k] < COEF_CONST(-1.0)) rxx[k] = COEF_CONST(-1.0); + } + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::calc_aliasing_degree(sbr_info* sbr, real_t* rxx, real_t* deg) { + uint8_t k; + rxx[0] = COEF_CONST(0.0); + deg[1] = COEF_CONST(0.0); + for (k = 2; k < sbr->k0; k++) { + deg[k] = 0.0; + if ((k % 2 == 0) && (rxx[k] < COEF_CONST(0.0))) { + if (rxx[k - 1] < 0.0) { + deg[k] = COEF_CONST(1.0); + if (rxx[k - 2] > COEF_CONST(0.0)) { deg[k - 1] = COEF_CONST(1.0) - MUL_C(rxx[k - 1], rxx[k - 1]); } + } else if (rxx[k - 2] > COEF_CONST(0.0)) { + deg[k] = COEF_CONST(1.0) - MUL_C(rxx[k - 1], rxx[k - 1]); + } + } + if ((k % 2 == 1) && (rxx[k] > COEF_CONST(0.0))) { + if (rxx[k - 1] > COEF_CONST(0.0)) { + deg[k] = COEF_CONST(1.0); + if (rxx[k - 2] < COEF_CONST(0.0)) { deg[k - 1] = COEF_CONST(1.0) - MUL_C(rxx[k - 1], rxx[k - 1]); } + } else if (rxx[k - 2] < COEF_CONST(0.0)) { + deg[k] = COEF_CONST(1.0) - MUL_C(rxx[k - 1], rxx[k - 1]); + } + } + } +} + #endif // SBR_LOW_POWER +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* FIXED POINT: bwArray = COEF */ +real_t NeaacDecoder::mapNewBw(uint8_t invf_mode, uint8_t invf_mode_prev) { + switch (invf_mode) { + case 1: /* LOW */ + if (invf_mode_prev == 0) /* NONE */ + return COEF_CONST(0.6); + else + return COEF_CONST(0.75); + case 2: /* MID */ return COEF_CONST(0.9); + case 3: /* HIGH */ return COEF_CONST(0.98); + default: /* NONE */ + if (invf_mode_prev == 1) /* LOW */ + return COEF_CONST(0.6); + else + return COEF_CONST(0.0); + } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* FIXED POINT: bwArray = COEF */ +void NeaacDecoder::calc_chirp_factors(sbr_info* sbr, uint8_t ch) { + uint8_t i; + for (i = 0; i < sbr->N_Q; i++) { + sbr->bwArray[ch][i] = mapNewBw(sbr->bs_invf_mode[ch][i], sbr->bs_invf_mode_prev[ch][i]); + if (sbr->bwArray[ch][i] < sbr->bwArray_prev[ch][i]) + sbr->bwArray[ch][i] = MUL_F(sbr->bwArray[ch][i], FRAC_CONST(0.75)) + MUL_F(sbr->bwArray_prev[ch][i], FRAC_CONST(0.25)); + else + sbr->bwArray[ch][i] = MUL_F(sbr->bwArray[ch][i], FRAC_CONST(0.90625)) + MUL_F(sbr->bwArray_prev[ch][i], FRAC_CONST(0.09375)); + if (sbr->bwArray[ch][i] < COEF_CONST(0.015625)) sbr->bwArray[ch][i] = COEF_CONST(0.0); + if (sbr->bwArray[ch][i] >= COEF_CONST(0.99609375)) sbr->bwArray[ch][i] = COEF_CONST(0.99609375); + sbr->bwArray_prev[ch][i] = sbr->bwArray[ch][i]; + sbr->bs_invf_mode_prev[ch][i] = sbr->bs_invf_mode[ch][i]; + } +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::patch_construction(sbr_info* sbr) { + uint8_t i, k; + uint8_t odd, sb; + uint8_t msb = sbr->k0; + uint8_t usb = sbr->kx; + uint8_t goalSbTab[] = {21, 23, 32, 43, 46, 64, 85, 93, 128, 0, 0, 0}; + /* (uint8_t)(2.048e6/sbr->sample_rate + 0.5); */ + uint8_t goalSb = goalSbTab[get_sr_index(sbr->sample_rate)]; + sbr->noPatches = 0; + if (goalSb < (sbr->kx + sbr->M)) { + for (i = 0, k = 0; sbr->f_master[i] < goalSb; i++) k = i + 1; + } else { + k = sbr->N_master; + } + if (sbr->N_master == 0) { + sbr->noPatches = 0; + sbr->patchNoSubbands[0] = 0; + sbr->patchStartSubband[0] = 0; + return; + } + do { + uint8_t j = k + 1; + do { + j--; + sb = sbr->f_master[j]; + odd = (sb - 2 + sbr->k0) % 2; + } while (sb > (sbr->k0 - 1 + msb - odd)); + sbr->patchNoSubbands[sbr->noPatches] = max(sb - usb, 0); + sbr->patchStartSubband[sbr->noPatches] = sbr->k0 - odd - sbr->patchNoSubbands[sbr->noPatches]; + if (sbr->patchNoSubbands[sbr->noPatches] > 0) { + usb = sb; + msb = sb; + sbr->noPatches++; + } else { + msb = sbr->kx; + } + if (sbr->f_master[k] - sb < 3) k = sbr->N_master; + } while (sb != (sbr->kx + sbr->M)); + if ((sbr->patchNoSubbands[sbr->noPatches - 1] < 3) && (sbr->noPatches > 1)) { sbr->noPatches--; } + sbr->noPatches = min(sbr->noPatches, (uint8_t)5); +} +#endif // SBR_DEC +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +/* function constructs new time border vector */ +/* first build into temp vector to be able to use previous vector on error */ +uint8_t NeaacDecoder::envelope_time_border_vector(sbr_info* sbr, uint8_t ch) { + uint8_t l, border, temp; + uint8_t t_E_temp[6] = {0}; + t_E_temp[0] = sbr->rate * sbr->abs_bord_lead[ch]; + t_E_temp[sbr->L_E[ch]] = sbr->rate * sbr->abs_bord_trail[ch]; + switch (sbr->bs_frame_class[ch]) { + case FIXFIX: + switch (sbr->L_E[ch]) { + case 4: + temp = (sbr->numTimeSlots / 4); + t_E_temp[3] = sbr->rate * 3 * temp; + t_E_temp[2] = sbr->rate * 2 * temp; + t_E_temp[1] = sbr->rate * temp; + break; + case 2: t_E_temp[1] = sbr->rate * (sbr->numTimeSlots / 2); break; + default: break; + } + break; + case FIXVAR: + if (sbr->L_E[ch] > 1) { + int8_t i = sbr->L_E[ch]; + border = sbr->abs_bord_trail[ch]; + for (l = 0; l < (sbr->L_E[ch] - 1); l++) { + if (border < sbr->bs_rel_bord[ch][l]) return 1; + border -= sbr->bs_rel_bord[ch][l]; + t_E_temp[--i] = sbr->rate * border; + } + } + break; + case VARFIX: + if (sbr->L_E[ch] > 1) { + int8_t i = 1; + border = sbr->abs_bord_lead[ch]; + for (l = 0; l < (sbr->L_E[ch] - 1); l++) { + border += sbr->bs_rel_bord[ch][l]; + if (sbr->rate * border + sbr->tHFAdj > sbr->numTimeSlotsRate + sbr->tHFGen) return 1; + t_E_temp[i++] = sbr->rate * border; + } + } + break; + case VARVAR: + if (sbr->bs_num_rel_0[ch]) { + int8_t i = 1; + border = sbr->abs_bord_lead[ch]; + for (l = 0; l < sbr->bs_num_rel_0[ch]; l++) { + border += sbr->bs_rel_bord_0[ch][l]; + if (sbr->rate * border + sbr->tHFAdj > sbr->numTimeSlotsRate + sbr->tHFGen) return 1; + t_E_temp[i++] = sbr->rate * border; + } + } + if (sbr->bs_num_rel_1[ch]) { + int8_t i = sbr->L_E[ch]; + border = sbr->abs_bord_trail[ch]; + for (l = 0; l < sbr->bs_num_rel_1[ch]; l++) { + if (border < sbr->bs_rel_bord_1[ch][l]) return 1; + border -= sbr->bs_rel_bord_1[ch][l]; + t_E_temp[--i] = sbr->rate * border; + } + } + break; + } + /* no error occured, we can safely use this t_E vector */ + for (l = 0; l < 6; l++) { sbr->t_E[ch][l] = t_E_temp[l]; } + return 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::noise_floor_time_border_vector(sbr_info* sbr, uint8_t ch) { + sbr->t_Q[ch][0] = sbr->t_E[ch][0]; + if (sbr->L_E[ch] == 1) { + sbr->t_Q[ch][1] = sbr->t_E[ch][1]; + sbr->t_Q[ch][2] = 0; + } else { + uint8_t index = middleBorder(sbr, ch); + sbr->t_Q[ch][1] = sbr->t_E[ch][index]; + sbr->t_Q[ch][2] = sbr->t_E[ch][sbr->L_E[ch]]; + } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +uint8_t NeaacDecoder::middleBorder(sbr_info* sbr, uint8_t ch) { + int8_t retval = 0; + switch (sbr->bs_frame_class[ch]) { + case FIXFIX: retval = sbr->L_E[ch] / 2; break; + case VARFIX: + if (sbr->bs_pointer[ch] == 0) + retval = 1; + else if (sbr->bs_pointer[ch] == 1) + retval = sbr->L_E[ch] - 1; + else + retval = sbr->bs_pointer[ch] - 1; + break; + case FIXVAR: + case VARVAR: + if (sbr->bs_pointer[ch] > 1) + retval = sbr->L_E[ch] + 1 - sbr->bs_pointer[ch]; + else + retval = sbr->L_E[ch] - 1; + break; + } + return (retval > 0) ? retval : 0; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +qmfs_info* NeaacDecoder::qmfs_init(uint8_t channels) { + qmfs_info* qmfs = (qmfs_info*)faad_malloc(sizeof(qmfs_info)); + /* v is a double ringbuffer */ + qmfs->v = (real_t*)faad_malloc(2 * channels * 20 * sizeof(real_t)); + memset(qmfs->v, 0, 2 * channels * 20 * sizeof(real_t)); + qmfs->v_index = 0; + qmfs->channels = channels; + return qmfs; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::qmfs_end(qmfs_info* qmfs) { + if (qmfs) { + if (qmfs->v) faad_free(&qmfs->v); + faad_free(&qmfs); + } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::sbr_qmf_synthesis_32(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output) { + real_t x[16]; + real_t y[16]; + int32_t n, k, out = 0; + uint8_t l; + /* qmf subsample l */ + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + /* shift buffers */ + /* we are not shifting v, it is a double ringbuffer */ + // memmove(qmfs->v + 64, qmfs->v, (640-64)*sizeof(real_t)); + /* calculate 64 samples */ + for (k = 0; k < 16; k++) { + #ifdef FIXED_POINT + y[k] = (QMF_RE(X[l][k]) - QMF_RE(X[l][31 - k])); + x[k] = (QMF_RE(X[l][k]) + QMF_RE(X[l][31 - k])); + #else + y[k] = (QMF_RE(X[l][k]) - QMF_RE(X[l][31 - k])) / 32.0; + x[k] = (QMF_RE(X[l][k]) + QMF_RE(X[l][31 - k])) / 32.0; + #endif + } + /* even n samples */ + DCT2_16_unscaled(x, x); + /* odd n samples */ + DCT4_16(y, y); + for (n = 8; n < 24; n++) { + qmfs->v[qmfs->v_index + n * 2] = qmfs->v[qmfs->v_index + 640 + n * 2] = x[n - 8]; + qmfs->v[qmfs->v_index + n * 2 + 1] = qmfs->v[qmfs->v_index + 640 + n * 2 + 1] = y[n - 8]; + } + for (n = 0; n < 16; n++) { qmfs->v[qmfs->v_index + n] = qmfs->v[qmfs->v_index + 640 + n] = qmfs->v[qmfs->v_index + 32 - n]; } + qmfs->v[qmfs->v_index + 48] = qmfs->v[qmfs->v_index + 640 + 48] = 0; + for (n = 1; n < 16; n++) { qmfs->v[qmfs->v_index + 48 + n] = qmfs->v[qmfs->v_index + 640 + 48 + n] = -qmfs->v[qmfs->v_index + 48 - n]; } + /* calculate 32 output samples and window */ + for (k = 0; k < 32; k++) { + output[out++] = MUL_F(qmfs->v[qmfs->v_index + k], qmf_c[2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 96 + k], qmf_c[64 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 128 + k], qmf_c[128 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 224 + k], qmf_c[192 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 256 + k], qmf_c[256 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 352 + k], qmf_c[320 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 384 + k], qmf_c[384 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 480 + k], qmf_c[448 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 512 + k], qmf_c[512 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 608 + k], qmf_c[576 + 2 * k]); + } + /* update the ringbuffer index */ + qmfs->v_index -= 64; + if (qmfs->v_index < 0) qmfs->v_index = (640 - 64); + } +} + #endif /*SBR_LOW_POWER*/ +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER +void NeaacDecoder::sbr_qmf_synthesis_64(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output) { + real_t x[64]; + real_t y[64]; + int32_t n, k, out = 0; + uint8_t l; + /* qmf subsample l */ + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + /* shift buffers */ + /* we are not shifting v, it is a double ringbuffer */ + // memmove(qmfs->v + 128, qmfs->v, (1280-128)*sizeof(real_t)); + /* calculate 128 samples */ + for (k = 0; k < 32; k++) { + #ifdef FIXED_POINT + y[k] = (QMF_RE(X[l][k]) - QMF_RE(X[l][63 - k])); + x[k] = (QMF_RE(X[l][k]) + QMF_RE(X[l][63 - k])); + #else + y[k] = (QMF_RE(X[l][k]) - QMF_RE(X[l][63 - k])) / 32.0; + x[k] = (QMF_RE(X[l][k]) + QMF_RE(X[l][63 - k])) / 32.0; + #endif + } + /* even n samples */ + DCT2_32_unscaled(x, x); + /* odd n samples */ + DCT4_32(y, y); + for (n = 16; n < 48; n++) { + qmfs->v[qmfs->v_index + n * 2] = qmfs->v[qmfs->v_index + 1280 + n * 2] = x[n - 16]; + qmfs->v[qmfs->v_index + n * 2 + 1] = qmfs->v[qmfs->v_index + 1280 + n * 2 + 1] = y[n - 16]; + } + for (n = 0; n < 32; n++) { qmfs->v[qmfs->v_index + n] = qmfs->v[qmfs->v_index + 1280 + n] = qmfs->v[qmfs->v_index + 64 - n]; } + qmfs->v[qmfs->v_index + 96] = qmfs->v[qmfs->v_index + 1280 + 96] = 0; + for (n = 1; n < 32; n++) { qmfs->v[qmfs->v_index + 96 + n] = qmfs->v[qmfs->v_index + 1280 + 96 + n] = -qmfs->v[qmfs->v_index + 96 - n]; } + /* calculate 64 output samples and window */ + for (k = 0; k < 64; k++) { + output[out++] = MUL_F(qmfs->v[qmfs->v_index + k], qmf_c[k]) + MUL_F(qmfs->v[qmfs->v_index + 192 + k], qmf_c[64 + k]) + MUL_F(qmfs->v[qmfs->v_index + 256 + k], qmf_c[128 + k]) + + MUL_F(qmfs->v[qmfs->v_index + 256 + 192 + k], qmf_c[128 + 64 + k]) + MUL_F(qmfs->v[qmfs->v_index + 512 + k], qmf_c[256 + k]) + + MUL_F(qmfs->v[qmfs->v_index + 512 + 192 + k], qmf_c[256 + 64 + k]) + MUL_F(qmfs->v[qmfs->v_index + 768 + k], qmf_c[384 + k]) + + MUL_F(qmfs->v[qmfs->v_index + 768 + 192 + k], qmf_c[384 + 64 + k]) + MUL_F(qmfs->v[qmfs->v_index + 1024 + k], qmf_c[512 + k]) + + MUL_F(qmfs->v[qmfs->v_index + 1024 + 192 + k], qmf_c[512 + 64 + k]); + } + /* update the ringbuffer index */ + qmfs->v_index -= 128; + if (qmfs->v_index < 0) qmfs->v_index = (1280 - 128); + } +} + #endif /*SBR_LOW_POWER*/ +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +void NeaacDecoder::sbr_qmf_synthesis_32(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output) { + real_t x1[32], x2[32]; + #ifndef FIXED_POINT + real_t scale = 1.f / 64.f; + #endif + int32_t n, k, out = 0; + uint8_t l; + /* qmf subsample l */ + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + /* shift buffer v */ + /* buffer is not shifted, we are using a ringbuffer */ + // memmove(qmfs->v + 64, qmfs->v, (640-64)*sizeof(real_t)); + /* calculate 64 samples */ + /* complex pre-twiddle */ + for (k = 0; k < 32; k++) { + x1[k] = MUL_F(QMF_RE(X[l][k]), RE(qmf32_pre_twiddle[k])) - MUL_F(QMF_IM(X[l][k]), IM(qmf32_pre_twiddle[k])); + x2[k] = MUL_F(QMF_IM(X[l][k]), RE(qmf32_pre_twiddle[k])) + MUL_F(QMF_RE(X[l][k]), IM(qmf32_pre_twiddle[k])); + #ifndef FIXED_POINT + x1[k] *= scale; + x2[k] *= scale; + #else + x1[k] >>= 1; + x2[k] >>= 1; + #endif + } + /* transform */ + DCT4_32(x1, x1); + DST4_32(x2, x2); + for (n = 0; n < 32; n++) { + qmfs->v[qmfs->v_index + n] = qmfs->v[qmfs->v_index + 640 + n] = -x1[n] + x2[n]; + qmfs->v[qmfs->v_index + 63 - n] = qmfs->v[qmfs->v_index + 640 + 63 - n] = x1[n] + x2[n]; + } + /* calculate 32 output samples and window */ + for (k = 0; k < 32; k++) { + output[out++] = MUL_F(qmfs->v[qmfs->v_index + k], qmf_c[2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 96 + k], qmf_c[64 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 128 + k], qmf_c[128 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 224 + k], qmf_c[192 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 256 + k], qmf_c[256 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 352 + k], qmf_c[320 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 384 + k], qmf_c[384 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 480 + k], qmf_c[448 + 2 * k]) + MUL_F(qmfs->v[qmfs->v_index + 512 + k], qmf_c[512 + 2 * k]) + + MUL_F(qmfs->v[qmfs->v_index + 608 + k], qmf_c[576 + 2 * k]); + } + /* update ringbuffer index */ + qmfs->v_index -= 64; + if (qmfs->v_index < 0) qmfs->v_index = (640 - 64); + } +} + #endif /*SBR_LOW_POWER*/ +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC + #ifndef SBR_LOW_POWER +void NeaacDecoder::sbr_qmf_synthesis_64(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output) { + // real_t x1[64], x2[64]; + #ifndef SBR_LOW_POWER + real_t in_real1[32], in_imag1[32], out_real1[32], out_imag1[32]; + real_t in_real2[32], in_imag2[32], out_real2[32], out_imag2[32]; + #endif + qmf_t* pX; + real_t *pring_buffer_1, *pring_buffer_3; + // real_t * ptemp_1, * ptemp_2; + #ifdef PREFER_POINTERS + // These pointers are used if target platform has autoinc address generators + real_t * pring_buffer_2, *pring_buffer_4; + real_t * pring_buffer_5, *pring_buffer_6; + real_t * pring_buffer_7, *pring_buffer_8; + real_t * pring_buffer_9, *pring_buffer_10; + const real_t *pqmf_c_1, *pqmf_c_2, *pqmf_c_3, *pqmf_c_4; + const real_t *pqmf_c_5, *pqmf_c_6, *pqmf_c_7, *pqmf_c_8; + const real_t *pqmf_c_9, *pqmf_c_10; + #endif // #ifdef PREFER_POINTERS + #ifndef FIXED_POINT + real_t scale = 1.f / 64.f; + #endif + int32_t n, k, out = 0; + uint8_t l; + /* qmf subsample l */ + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + /* shift buffer v */ + /* buffer is not shifted, we use double ringbuffer */ + // memmove(qmfs->v + 128, qmfs->v, (1280-128)*sizeof(real_t)); + /* calculate 128 samples */ + #ifndef FIXED_POINT + pX = X[l]; + in_imag1[31] = scale * QMF_RE(pX[1]); + in_real1[0] = scale * QMF_RE(pX[0]); + in_imag2[31] = scale * QMF_IM(pX[63 - 1]); + in_real2[0] = scale * QMF_IM(pX[63 - 0]); + for (k = 1; k < 31; k++) { + in_imag1[31 - k] = scale * QMF_RE(pX[2 * k + 1]); + in_real1[k] = scale * QMF_RE(pX[2 * k]); + in_imag2[31 - k] = scale * QMF_IM(pX[63 - (2 * k + 1)]); + in_real2[k] = scale * QMF_IM(pX[63 - (2 * k)]); + } + in_imag1[0] = scale * QMF_RE(pX[63]); + in_real1[31] = scale * QMF_RE(pX[62]); + in_imag2[0] = scale * QMF_IM(pX[63 - 63]); + in_real2[31] = scale * QMF_IM(pX[63 - 62]); + #else + pX = X[l]; + in_imag1[31] = QMF_RE(pX[1]) >> 1; + in_real1[0] = QMF_RE(pX[0]) >> 1; + in_imag2[31] = QMF_IM(pX[62]) >> 1; + in_real2[0] = QMF_IM(pX[63]) >> 1; + for (k = 1; k < 31; k++) { + in_imag1[31 - k] = QMF_RE(pX[2 * k + 1]) >> 1; + in_real1[k] = QMF_RE(pX[2 * k]) >> 1; + in_imag2[31 - k] = QMF_IM(pX[63 - (2 * k + 1)]) >> 1; + in_real2[k] = QMF_IM(pX[63 - (2 * k)]) >> 1; + } + in_imag1[0] = QMF_RE(pX[63]) >> 1; + in_real1[31] = QMF_RE(pX[62]) >> 1; + in_imag2[0] = QMF_IM(pX[0]) >> 1; + in_real2[31] = QMF_IM(pX[1]) >> 1; + #endif + // dct4_kernel is DCT_IV without reordering which is done before and after FFT + dct4_kernel(in_real1, in_imag1, out_real1, out_imag1); + dct4_kernel(in_real2, in_imag2, out_real2, out_imag2); + pring_buffer_1 = qmfs->v + qmfs->v_index; + pring_buffer_3 = pring_buffer_1 + 1280; + #ifdef PREFER_POINTERS + pring_buffer_2 = pring_buffer_1 + 127; + pring_buffer_4 = pring_buffer_1 + (1280 + 127); + #endif // #ifdef PREFER_POINTERS + // ptemp_1 = x1; + // ptemp_2 = x2; + #ifdef PREFER_POINTERS + for (n = 0; n < 32; n++) { + // real_t x1 = *ptemp_1++; + // real_t x2 = *ptemp_2++; + // pring_buffer_3 and pring_buffer_4 are needed only for double ring buffer + *pring_buffer_1++ = *pring_buffer_3++ = out_real2[n] - out_real1[n]; + *pring_buffer_2-- = *pring_buffer_4-- = out_real2[n] + out_real1[n]; + // x1 = *ptemp_1++; + // x2 = *ptemp_2++; + *pring_buffer_1++ = *pring_buffer_3++ = out_imag2[31 - n] + out_imag1[31 - n]; + *pring_buffer_2-- = *pring_buffer_4-- = out_imag2[31 - n] - out_imag1[31 - n]; + } + #else // #ifdef PREFER_POINTERS + for (n = 0; n < 32; n++) { + // pring_buffer_3 and pring_buffer_4 are needed only for double ring buffer + pring_buffer_1[2 * n] = pring_buffer_3[2 * n] = out_real2[n] - out_real1[n]; + pring_buffer_1[127 - 2 * n] = pring_buffer_3[127 - 2 * n] = out_real2[n] + out_real1[n]; + pring_buffer_1[2 * n + 1] = pring_buffer_3[2 * n + 1] = out_imag2[31 - n] + out_imag1[31 - n]; + pring_buffer_1[127 - (2 * n + 1)] = pring_buffer_3[127 - (2 * n + 1)] = out_imag2[31 - n] - out_imag1[31 - n]; + } + #endif // #ifdef PREFER_POINTERS + pring_buffer_1 = qmfs->v + qmfs->v_index; + #ifdef PREFER_POINTERS + pring_buffer_2 = pring_buffer_1 + 192; + pring_buffer_3 = pring_buffer_1 + 256; + pring_buffer_4 = pring_buffer_1 + (256 + 192); + pring_buffer_5 = pring_buffer_1 + 512; + pring_buffer_6 = pring_buffer_1 + (512 + 192); + pring_buffer_7 = pring_buffer_1 + 768; + pring_buffer_8 = pring_buffer_1 + (768 + 192); + pring_buffer_9 = pring_buffer_1 + 1024; + pring_buffer_10 = pring_buffer_1 + (1024 + 192); + pqmf_c_1 = qmf_c; + pqmf_c_2 = qmf_c + 64; + pqmf_c_3 = qmf_c + 128; + pqmf_c_4 = qmf_c + 192; + pqmf_c_5 = qmf_c + 256; + pqmf_c_6 = qmf_c + 320; + pqmf_c_7 = qmf_c + 384; + pqmf_c_8 = qmf_c + 448; + pqmf_c_9 = qmf_c + 512; + pqmf_c_10 = qmf_c + 576; + #endif // #ifdef PREFER_POINTERS + /* calculate 64 output samples and window */ + for (k = 0; k < 64; k++) { + #ifdef PREFER_POINTERS + output[out++] = MUL_F(*pring_buffer_1++, *pqmf_c_1++) + MUL_F(*pring_buffer_2++, *pqmf_c_2++) + MUL_F(*pring_buffer_3++, *pqmf_c_3++) + MUL_F(*pring_buffer_4++, *pqmf_c_4++) + + MUL_F(*pring_buffer_5++, *pqmf_c_5++) + MUL_F(*pring_buffer_6++, *pqmf_c_6++) + MUL_F(*pring_buffer_7++, *pqmf_c_7++) + MUL_F(*pring_buffer_8++, *pqmf_c_8++) + + MUL_F(*pring_buffer_9++, *pqmf_c_9++) + MUL_F(*pring_buffer_10++, *pqmf_c_10++); + #else // #ifdef PREFER_POINTERS + output[out++] = MUL_F(pring_buffer_1[k + 0], qmf_c[k + 0]) + MUL_F(pring_buffer_1[k + 192], qmf_c[k + 64]) + MUL_F(pring_buffer_1[k + 256], qmf_c[k + 128]) + + MUL_F(pring_buffer_1[k + (256 + 192)], qmf_c[k + 192]) + MUL_F(pring_buffer_1[k + 512], qmf_c[k + 256]) + MUL_F(pring_buffer_1[k + (512 + 192)], qmf_c[k + 320]) + + MUL_F(pring_buffer_1[k + 768], qmf_c[k + 384]) + MUL_F(pring_buffer_1[k + (768 + 192)], qmf_c[k + 448]) + MUL_F(pring_buffer_1[k + 1024], qmf_c[k + 512]) + + MUL_F(pring_buffer_1[k + (1024 + 192)], qmf_c[k + 576]); + #endif // #ifdef PREFER_POINTERS + } + /* update ringbuffer index */ + qmfs->v_index -= 128; + if (qmfs->v_index < 0) qmfs->v_index = (1280 - 128); + } +} + #endif /*SBR_LOW_POWER*/ +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +qmfa_info* NeaacDecoder::qmfa_init(uint8_t channels) { + qmfa_info* qmfa = (qmfa_info*)faad_malloc(sizeof(qmfa_info)); + /* x is implemented as double ringbuffer */ + qmfa->x = (real_t*)faad_malloc(2 * channels * 10 * sizeof(real_t)); + memset(qmfa->x, 0, 2 * channels * 10 * sizeof(real_t)); + /* ringbuffer index */ + qmfa->x_index = 0; + qmfa->channels = channels; + return qmfa; +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::qmfa_end(qmfa_info* qmfa) { + if (qmfa) { + if (qmfa->x) faad_free(&qmfa->x); + faad_free(&qmfa); + } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SBR_DEC +void NeaacDecoder::sbr_qmf_analysis_32(sbr_info* sbr, qmfa_info* qmfa, const real_t* input, qmf_t X[MAX_NTSRHFG][64], uint8_t offset, uint8_t kx) { + real_t u[64]; + #ifndef SBR_LOW_POWER + real_t in_real[32], in_imag[32], out_real[32], out_imag[32]; + #else + real_t y[32]; + #endif + uint32_t in = 0; + uint8_t l; + /* qmf subsample l */ + for (l = 0; l < sbr->numTimeSlotsRate; l++) { + int16_t n; + /* shift input buffer x */ + /* input buffer is not shifted anymore, x is implemented as double ringbuffer */ + // memmove(qmfa->x + 32, qmfa->x, (320-32)*sizeof(real_t)); + /* add new samples to input buffer x */ + for (n = 32 - 1; n >= 0; n--) { + #ifdef FIXED_POINT + qmfa->x[qmfa->x_index + n] = qmfa->x[qmfa->x_index + n + 320] = (input[in++]) >> 4; + #else + qmfa->x[qmfa->x_index + n] = qmfa->x[qmfa->x_index + n + 320] = input[in++]; + #endif + } + /* window and summation to create array u */ + for (n = 0; n < 64; n++) { + u[n] = MUL_F(qmfa->x[qmfa->x_index + n], qmf_c[2 * n]) + MUL_F(qmfa->x[qmfa->x_index + n + 64], qmf_c[2 * (n + 64)]) + MUL_F(qmfa->x[qmfa->x_index + n + 128], qmf_c[2 * (n + 128)]) + + MUL_F(qmfa->x[qmfa->x_index + n + 192], qmf_c[2 * (n + 192)]) + MUL_F(qmfa->x[qmfa->x_index + n + 256], qmf_c[2 * (n + 256)]); + } + /* update ringbuffer index */ + qmfa->x_index -= 32; + if (qmfa->x_index < 0) qmfa->x_index = (320 - 32); + /* calculate 32 subband samples by introducing X */ + #ifdef SBR_LOW_POWER + y[0] = u[48]; + for (n = 1; n < 16; n++) y[n] = u[n + 48] + u[48 - n]; + for (n = 16; n < 32; n++) y[n] = -u[n - 16] + u[48 - n]; + DCT3_32_unscaled(u, y); + for (n = 0; n < 32; n++) { + if (n < kx) { + #ifdef FIXED_POINT + QMF_RE(X[l + offset][n]) = u[n] /*<< 1*/; + #else + QMF_RE(X[l + offset][n]) = 2. * u[n]; + #endif + } else { + QMF_RE(X[l + offset][n]) = 0; + } + } + #else + // Reordering of data moved from DCT_IV to here + in_imag[31] = u[1]; + in_real[0] = u[0]; + for (n = 1; n < 31; n++) { + in_imag[31 - n] = u[n + 1]; + in_real[n] = -u[64 - n]; + } + in_imag[0] = u[32]; + in_real[31] = -u[33]; + // dct4_kernel is DCT_IV without reordering which is done before and after FFT + dct4_kernel(in_real, in_imag, out_real, out_imag); + // Reordering of data moved from DCT_IV to here + for (n = 0; n < 16; n++) { + if (2 * n + 1 < kx) { + #ifdef FIXED_POINT + QMF_RE(X[l + offset][2 * n]) = out_real[n]; + QMF_IM(X[l + offset][2 * n]) = out_imag[n]; + QMF_RE(X[l + offset][2 * n + 1]) = -out_imag[31 - n]; + QMF_IM(X[l + offset][2 * n + 1]) = -out_real[31 - n]; + #else + QMF_RE(X[l + offset][2 * n]) = 2. * out_real[n]; + QMF_IM(X[l + offset][2 * n]) = 2. * out_imag[n]; + QMF_RE(X[l + offset][2 * n + 1]) = -2. * out_imag[31 - n]; + QMF_IM(X[l + offset][2 * n + 1]) = -2. * out_real[31 - n]; + #endif + } else { + if (2 * n < kx) { + #ifdef FIXED_POINT + QMF_RE(X[l + offset][2 * n]) = out_real[n]; + QMF_IM(X[l + offset][2 * n]) = out_imag[n]; + #else + QMF_RE(X[l + offset][2 * n]) = 2. * out_real[n]; + QMF_IM(X[l + offset][2 * n]) = 2. * out_imag[n]; + #endif + } else { + QMF_RE(X[l + offset][2 * n]) = 0; + QMF_IM(X[l + offset][2 * n]) = 0; + } + QMF_RE(X[l + offset][2 * n + 1]) = 0; + QMF_IM(X[l + offset][2 * n + 1]) = 0; + } + } + #endif + } +} +#endif /*SBR_DEC*/ +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#ifdef SSR_DEC +void NeaacDecoder::gc_set_protopqf(real_t* p_proto) { + int j; + real_t a_half[48] = {1.2206911375946939E-05, 1.7261986723798209E-05, 1.2300093657077942E-05, -1.0833943097791965E-05, -5.7772498639901686E-05, -1.2764767618947719E-04, -2.0965186675013334E-04, + -2.8166673689263850E-04, -3.1234860429017460E-04, -2.6738519958452353E-04, -1.1949424681824722E-04, 1.3965139412648678E-04, 4.8864136409185725E-04, 8.7044629275148344E-04, + 1.1949430269934793E-03, 1.3519708175026700E-03, 1.2346314373964412E-03, 7.6953209114159191E-04, -5.2242432579537141E-05, -1.1516092887213454E-03, -2.3538469841711277E-03, + -3.4033123072127277E-03, -4.0028551071986133E-03, -3.8745415659693259E-03, -2.8321073426874310E-03, -8.5038892323704195E-04, 1.8856751185350931E-03, 4.9688741735340923E-03, + 7.8056704536795926E-03, 9.7027909685901654E-03, 9.9960423120166159E-03, 8.2019366335594487E-03, 4.1642072876103365E-03, -1.8364453822737758E-03, -9.0384863094167686E-03, + -1.6241528177129844E-02, -2.1939551286300665E-02, -2.4533179947088161E-02, -2.2591663337768787E-02, -1.5122066420044672E-02, -1.7971713448186293E-03, 1.6903413428575379E-02, + 3.9672315874127042E-02, 6.4487527248102796E-02, 8.8850025474701726E-02, 0.1101132906105560, 0.1258540205143761, 0.1342239368467012}; + for (j = 0; j < 48; ++j) { p_proto[j] = p_proto[95 - j] = a_half[j]; } +} +#endif +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.h b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.h new file mode 100644 index 0000000..82f7e42 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/aac_decoder/libfaad/neaacdec.h @@ -0,0 +1,425 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +**/ + +// ESP32 Version 29.07.2024 +// updated: 18.06.2026 + +#pragma once + +#include "aac_structs.h" +#include "aac_tables.h" +#include "aac_defines.h" +#include +#include +#include +#include +#include +#include +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +class NeaacDecoder { + public: + NeaacDecoder() { m_initFlag = 0; } + ~NeaacDecoder() = default; + NeAACDecHandle NeAACDecOpen(void); + NeAACDecConfigurationPtr NeAACDecGetCurrentConfiguration(NeAACDecHandle hpDecoder); + void NeAACDecClose(NeAACDecHandle hpDecoder); + uint8_t NeAACDecSetConfiguration(NeAACDecHandle hpDecoder, NeAACDecConfigurationPtr config); + char NeAACDecInit2(NeAACDecHandle hpDecoder, uint8_t* pBuffer, uint32_t SizeOfDecoderSpecificInfo, uint32_t* samplerate, uint8_t* channels); + long NeAACDecInit(NeAACDecHandle hpDecoder, uint8_t* buffer, uint32_t buffer_size, uint32_t* samplerate, uint8_t* channels); + void* NeAACDecDecode2(NeAACDecHandle hpDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size, void** sample_buffer, uint32_t sample_buffer_size); + error_info_t NeAACDecGetErrorMessage(const uint8_t errcode); + uint8_t get_sr_index(const uint32_t samplerate); + + private: + uint32_t __r1 __attribute__((unused)) = 1; + uint32_t __r2 __attribute__((unused)) = 1; + + ps_ptr m_mdct256; + ps_ptr m_mdct1024; + ps_ptr m_mdct2048; + ps_ptr m_ccft256; + ps_ptr m_ccft1024; + ps_ptr m_ccft2048; + ps_ptr m_work256; + ps_ptr m_work1024; + ps_ptr m_work2048; + ps_ptr m_G_temp_prev[48][2][5]; + ps_ptr m_Q_temp_prev[48][2][5]; + ps_ptr m_adif; + ps_ptr m_adts; + ps_ptr m_ld; + ps_ptr m_sample_buffer; + + uint32_t ne_rng(uint32_t* __r1, uint32_t* __r2); + uint32_t wl_min_lzc(uint32_t x); + uint8_t m_initFlag = 0; +#ifdef FIXED_POINT + int32_t log2_int(uint32_t val); + int32_t log2_fix(uint32_t val); + int32_t pow2_int(real_t val); + real_t pow2_fix(real_t val); +#endif + template void faad_free(freeType** b); + + void* faad_calloc(size_t len, size_t size); + uint32_t ones32(uint32_t x); + uint32_t floor_log2(uint32_t x); + int NeAACDecGetVersion(const char** faad_id_string, const char** faad_copyright_string); + uint32_t NeAACDecGetCapabilities(void); + void NeAACDecPostSeekReset(NeAACDecHandle hpDecoder, long frame); + void* NeAACDecDecode(NeAACDecHandle hpDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size); + void cfftf1pos(uint16_t n, complex_t* c, complex_t* ch, const uint16_t* ifac, const complex_t* wa, const int8_t isign); + void cfftf1neg(uint16_t n, complex_t* c, complex_t* ch, const uint16_t* ifac, const complex_t* wa, const int8_t isign); +#ifdef FIXED_POINT + real_t get_sample(real_t** input, uint8_t channel, uint16_t sample, uint8_t down_matrix, uint8_t up_matrix, uint8_t* internal_channel); +#endif +#ifndef FIXED_POINT + real_t get_sample(real_t** input, uint8_t channel, uint16_t sample, uint8_t down_matrix, uint8_t* internal_channel); + void to_PCM_16bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int16_t** sample_buffer); + void to_PCM_24bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int32_t** sample_buffer); + void to_PCM_32bit(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, int32_t** sample_buffer); + void to_PCM_float(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, float** sample_buffer); + void to_PCM_double(NeAACDecStruct* hDecoder, real_t** input, uint8_t channels, uint16_t frame_len, double** sample_buffer); +#endif + void imdct_ssr(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len); + void gc_setcoef_eff_pqfsyn(int mm, int kk, real_t* p_proto, real_t*** ppp_q0, real_t*** ppp_t0, real_t*** ppp_t1); + real_t calc_Q_div(sbr_info* sbr, uint8_t ch, uint8_t m, uint8_t l); + real_t calc_Q_div2(sbr_info* sbr, uint8_t ch, uint8_t m, uint8_t l); +#ifdef MAIN_DEC + void flt_round(float* pf); + int16_t quant_pred(float x); + float inv_quant_pred(int16_t q); + void ic_predict(pred_state* state, real_t input, real_t* output, uint8_t pred); + void reset_pred_state(pred_state* state); +#endif + void imdct_long(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len); + void mdct_init(fb_info* fb, real_t* in_data, real_t* out_data, uint16_t len); + uint32_t rewrev_word(uint32_t v, const uint8_t len); + void rewrev_lword(uint32_t* hi, uint32_t* lo, const uint8_t len); + void rewrev_bits(bits_t* bits); + void concat_bits(bits_t* b, bits_t* a); + uint8_t is_good_cb(uint8_t this_CB, uint8_t this_sec_CB); + void read_segment(bits_t* segment, uint8_t segwidth, bitfile* ld); + void fill_in_codeword(codeword_t* codeword, uint16_t index, uint16_t sp, uint8_t cb); + void fft_dif(real_t* Real, real_t* Imag); + real_t iquant(int16_t q, const real_t* tab, uint8_t* error); + uint8_t allocate_single_channel(NeAACDecStruct* hDecoder, uint8_t channel, uint8_t output_channels); + uint8_t allocate_channel_pair(NeAACDecStruct* hDecoder, uint8_t channel, uint8_t paired_channel); + uint8_t decode_scale_factors(ic_stream* ics, bitfile* ld); + uint32_t latm_get_value(bitfile* ld); + uint32_t latmParsePayload(latm_header* latm, bitfile* ld); + uint32_t latmAudioMuxElement(latm_header* latm, bitfile* ld); + char NeAACDecAudioSpecificConfig(uint8_t* pBuffer, uint32_t buffer_size, mp4AudioSpecificConfig* mp4ASC); + void hybrid_free(hyb_info* hyb); + void channel_filter4(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid); + void DCT3_6_unscaled(real_t* y, real_t* x); + void channel_filter12(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid); + real_t magnitude_c(complex_t c); + uint8_t sbr_process_channel(sbr_info* sbr, real_t* channel_buf, qmf_t X[MAX_NTSR][64], uint8_t ch, uint8_t dont_process, const uint8_t downSampledSBR); + real_t find_initial_power(uint8_t bands, uint8_t a0, uint8_t a1); + void sbr_reset(sbr_info* sbr); + int8_t sbr_log2(const int8_t val); + real_t find_log2_E(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch); + real_t find_log2_Q(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch); + real_t find_log2_Qplus1(sbr_info* sbr, uint8_t k, uint8_t l, uint8_t ch); + void auto_correlation(sbr_info* sbr, acorr_coef* ac, qmf_t buffer[MAX_NTSRHFG][64], uint8_t bd, uint8_t len); + real_t mapNewBw(uint8_t invf_mode, uint8_t invf_mode_prev); + uint8_t max_pred_sfb(const uint8_t sr_index); + uint8_t max_tns_sfb(const uint8_t sr_index, const uint8_t object_type, const uint8_t is_short); + uint32_t get_sample_rate(const uint8_t sr_index); + int8_t can_decode_ot(const uint8_t object_type); + void* faad_malloc(size_t size); + drc_info* drc_init(real_t cut, real_t boost); + void drc_end(drc_info* drc); + void drc_decode(drc_info* drc, real_t* spec); + sbr_info* sbrDecodeInit(uint16_t framelength, uint8_t id_aac, uint32_t sample_rate, uint8_t downSampledSBR, uint8_t IsDRM); + void sbrDecodeEnd(sbr_info* sbr, uint8_t i); + void sbrReset(sbr_info* sbr, uint8_t i); + uint8_t sbrDecodeCoupleFrame(sbr_info* sbr, real_t* left_chan, real_t* right_chan, const uint8_t just_seeked, const uint8_t downSampledSBR); + uint8_t sbrDecodeSingleFrame(sbr_info* sbr, real_t* channel, const uint8_t just_seeked, const uint8_t downSampledSBR); + uint16_t ps_data(ps_info* ps, bitfile* ld, uint8_t* header); + ps_info* ps_init(uint8_t sr_index, uint8_t numTimeSlotsRate); + void ps_free(ps_info* ps); + uint8_t ps_decode(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64]); + void faad_initbits(bitfile* ld, const void* buffer, const uint32_t buffer_size); + void faad_endbits(bitfile* ld); + void faad_initbits_rev(bitfile* ld, void* buffer, uint32_t bits_in_buffer); + uint8_t faad_byte_align(bitfile* ld); + uint32_t faad_get_processed_bits(bitfile* ld); + void faad_flushbits_ex(bitfile* ld, uint32_t bits); + void faad_rewindbits(bitfile* ld); + void faad_resetbits(bitfile* ld, int bits); + uint8_t* faad_getbitbuffer(bitfile* ld, uint32_t bits); + void* faad_origbitbuffer(bitfile* ld); + uint32_t faad_origbitbuffer_size(bitfile* ld); + uint8_t faad_get1bit(bitfile* ld); + uint32_t faad_getbits(bitfile* ld, uint32_t n); + uint32_t faad_showbits_rev(bitfile* ld, uint32_t bits); + void faad_flushbits_rev(bitfile* ld, uint32_t bits); + uint32_t getdword(void* mem); + uint32_t getdword_n(void* mem, int n); + void faad_flushbits(bitfile* ld, uint32_t bits); + uint32_t faad_showbits(bitfile* ld, uint32_t bits); + uint32_t showbits_hcr(bits_t* ld, uint8_t bits); + uint32_t faad_getbits_rev(bitfile* ld, uint32_t n); + int8_t get1bit_hcr(bits_t* ld, uint8_t* result); + int8_t flushbits_hcr(bits_t* ld, uint8_t bits); + int8_t getbits_hcr(bits_t* ld, uint8_t n, uint32_t* result); + void cfftf(uint16_t mdct_len, complex_t* c); + void cfftb(uint16_t mdct_len, complex_t* c); + void cffti(uint16_t mdct_len, uint16_t n); + void* aac_frame_decode(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, uint8_t* buffer, uint32_t buffer_size, void** sample_buffer2, uint32_t sample_buffer_size); + void create_channel_config(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo); + void passf2pos(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa); + void passf2neg(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa); + void passf3(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const int8_t isign); + void passf4pos(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3); + void passf4neg(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3); + void passf5(const uint16_t ido, const uint16_t l1, const complex_t* cc, complex_t* ch, const complex_t* wa1, const complex_t* wa2, const complex_t* wa3, const complex_t* wa4, const int8_t isign); + void cffti1(uint16_t n, complex_t* wa, uint16_t* ifac); + fb_info* filter_bank_init(uint16_t frame_len); + void filter_bank_end(fb_info* fb); + void filter_bank_ltp(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* in_data, real_t* out_mdct, uint8_t object_type, uint16_t frame_len); + void ifilter_bank(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, real_t* overlap, uint8_t object_type, + uint16_t frame_len); + void ms_decode(ic_stream* ics, ic_stream* icsr, real_t* l_spec, real_t* r_spec, uint16_t frame_len); + void is_decode(ic_stream* ics, ic_stream* icsr, real_t* l_spec, real_t* r_spec, uint16_t frame_len); + int8_t is_intensity(ic_stream* ics, uint8_t group, uint8_t sfb); + uint8_t is_noise(ic_stream* ics, uint8_t group, uint8_t sfb); + real_t fp_sqrt(real_t value); + void pns_decode(ic_stream* ics_left, ic_stream* ics_right, real_t* spec_left, real_t* spec_right, uint16_t frame_len, uint8_t channel_pair, uint8_t object_type, + /* RNG states */ uint32_t* __r1, uint32_t* __r2); + int8_t invert_intensity(ic_stream* ics, uint8_t group, uint8_t sfb); + void* output_to_PCM(NeAACDecStruct* hDecoder, real_t** input, void* samplebuffer, uint8_t channels, uint16_t frame_len, uint8_t format); + uint8_t pulse_decode(ic_stream* ics, int16_t* spec_coef, uint16_t framelen); + void gen_rand_vector(real_t* spec, int16_t scale_factor, uint16_t size, uint8_t sub, uint32_t* __r1, uint32_t* __r2); + void huffman_sign_bits(bitfile* ld, int16_t* sp, uint8_t len); + uint8_t huffman_getescape(bitfile* ld, int16_t* sp); + uint8_t huffman_2step_quad(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_2step_quad_sign(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_2step_pair(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_2step_pair_sign(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_binary_quad(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_binary_quad_sign(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_binary_pair(uint8_t cb, bitfile* ld, int16_t* sp); + uint8_t huffman_binary_pair_sign(uint8_t cb, bitfile* ld, int16_t* sp); + int16_t huffman_codebook(uint8_t i); + void vcb11_check_LAV(uint8_t cb, int16_t* sp); + uint16_t drm_ps_data(drm_ps_info* ps, bitfile* ld); + drm_ps_info* drm_ps_init(void); + void drm_ps_free(drm_ps_info* ps); + uint8_t drm_ps_decode(drm_ps_info* ps, uint8_t guess, qmf_t X_left[38][64], qmf_t X_right[38][64]); + int8_t huffman_scale_factor(bitfile* ld); + uint8_t huffman_spectral_data(uint8_t cb, bitfile* ld, int16_t* sp); + int8_t huffman_spectral_data_2(uint8_t cb, bits_t* ld, int16_t* sp); + int8_t AudioSpecificConfig2(uint8_t* pBuffer, uint32_t buffer_size, mp4AudioSpecificConfig* mp4ASC, program_config* pce, uint8_t short_form); + int8_t AudioSpecificConfigFromBitfile(bitfile* ld, mp4AudioSpecificConfig* mp4ASC, program_config* pce, uint32_t bsize, uint8_t short_form); + void pns_reset_pred_state(ic_stream* ics, pred_state* state); + void reset_all_predictors(pred_state* state, uint16_t frame_len); + void ic_prediction(ic_stream* ics, real_t* spec, pred_state* state, uint16_t frame_len, uint8_t sf_index); + uint8_t quant_to_spec(NeAACDecStruct* hDecoder, ic_stream* ics, int16_t* quant_data, real_t* spec_data, uint16_t frame_len); + uint8_t window_grouping_info(NeAACDecStruct* hDecoder, ic_stream* ics); + uint8_t reconstruct_channel_pair(NeAACDecStruct* hDecoder, ic_stream* ics1, ic_stream* ics2, element* cpe, int16_t* spec_data1, int16_t* spec_data2); + uint8_t reconstruct_single_channel(NeAACDecStruct* hDecoder, ic_stream* ics, element* sce, int16_t* spec_data); + void tns_decode_frame(ic_stream* ics, tns_info* tns, uint8_t sr_index, uint8_t object_type, real_t* spec, uint16_t frame_len); + void tns_encode_frame(ic_stream* ics, tns_info* tns, uint8_t sr_index, uint8_t object_type, real_t* spec, uint16_t frame_len); + uint8_t is_ltp_ot(uint8_t object_type); + void lt_prediction(ic_stream* ics, ltp_info* ltp, real_t* spec, int16_t* lt_pred_stat, fb_info* fb, uint8_t win_shape, uint8_t win_shape_prev, uint8_t sr_index, uint8_t object_type, + uint16_t frame_len); + void lt_update_state(int16_t* lt_pred_stat, real_t* time, real_t* overlap, uint16_t frame_len, uint8_t object_type); + void tns_decode_coef(uint8_t order, uint8_t coef_res_bits, uint8_t coef_compress, uint8_t* coef, real_t* a); + void tns_ar_filter(real_t* spectrum, uint16_t size, int8_t inc, real_t* lpc, uint8_t order); + void tns_ma_filter(real_t* spectrum, uint16_t size, int8_t inc, real_t* lpc, uint8_t order); + uint8_t faad_check_CRC(bitfile* ld, uint16_t len); + /* static function declarations */ + void decode_sce_lfe(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, uint8_t id_syn_ele); + void decode_cpe(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, uint8_t id_syn_ele); + uint8_t single_lfe_channel_element(NeAACDecStruct* hDecoder, bitfile* ld, uint8_t channel, uint8_t* tag); + uint8_t channel_pair_element(NeAACDecStruct* hDecoder, bitfile* ld, uint8_t channel, uint8_t* tag); +#ifdef COUPLING_DEC + uint8_t coupling_channel_element(NeAACDecStruct* hDecoder, bitfile* ld); +#endif + uint16_t data_stream_element(NeAACDecStruct* hDecoder, bitfile* ld); + uint8_t program_config_element(program_config* pce, bitfile* ld); + uint8_t fill_element(NeAACDecStruct* hDecoder, bitfile* ld, drc_info* drc, uint8_t sbr_ele); + uint8_t individual_channel_stream(NeAACDecStruct* hDecoder, element* ele, bitfile* ld, ic_stream* ics, uint8_t scal_flag, int16_t* spec_data); + uint8_t ics_info(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, uint8_t common_window); + uint8_t section_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld); + uint8_t scale_factor_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld); +#ifdef SSR_DEC + void gain_control_data(bitfile* ld, ic_stream* ics); +#endif + uint8_t spectral_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, int16_t* spectral_data); + uint16_t extension_payload(bitfile* ld, drc_info* drc, uint16_t count); + uint8_t pulse_data(ic_stream* ics, pulse_info* pul, bitfile* ld); + void tns_data(ic_stream* ics, tns_info* tns, bitfile* ld); +#ifdef LTP_DEC + uint8_t ltp_data(NeAACDecStruct* hDecoder, ic_stream* ics, ltp_info* ltp, bitfile* ld); +#endif + uint8_t adts_fixed_header(adts_header* adts, bitfile* ld); + void adts_variable_header(adts_header* adts, bitfile* ld); + void adts_error_check(adts_header* adts, bitfile* ld); + uint8_t dynamic_range_info(bitfile* ld, drc_info* drc); + uint8_t excluded_channels(bitfile* ld, drc_info* drc); + uint8_t side_info(NeAACDecStruct* hDecoder, element* ele, bitfile* ld, ic_stream* ics, uint8_t scal_flag); + int8_t GASpecificConfig(bitfile* ld, mp4AudioSpecificConfig* mp4ASC, program_config* pce); + uint8_t adts_frame(adts_header* adts, bitfile* ld); + void get_adif_header(adif_header* adif, bitfile* ld); + void raw_data_block(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, program_config* pce, drc_info* drc); + uint8_t reordered_spectral_data(NeAACDecStruct* hDecoder, ic_stream* ics, bitfile* ld, int16_t* spectral_data); +#ifdef DRM + int8_t DRM_aac_scalable_main_header(NeAACDecStruct* hDecoder, ic_stream* ics1, ic_stream* ics2, bitfile* ld, uint8_t this_layer_stereo); +#endif + void dct4_kernel(real_t* in_real, real_t* in_imag, real_t* out_real, real_t* out_imag); + void DCT3_32_unscaled(real_t* y, real_t* x); + void DCT4_32(real_t* y, real_t* x); + void DST4_32(real_t* y, real_t* x); + void DCT2_32_unscaled(real_t* y, real_t* x); + void DCT4_16(real_t* y, real_t* x); + void DCT2_16_unscaled(real_t* y, real_t* x); + uint8_t rvlc_scale_factor_data(ic_stream* ics, bitfile* ld); + uint8_t rvlc_decode_scale_factors(ic_stream* ics, bitfile* ld); + uint8_t sbr_extension_data(bitfile* ld, sbr_info* sbr, uint16_t cnt, uint8_t resetFlag); + int8_t rvlc_huffman_sf(bitfile* ld_sf, bitfile* ld_esc, int8_t direction); + int8_t rvlc_huffman_esc(bitfile* ld_esc, int8_t direction); + uint8_t rvlc_decode_sf_forward(ic_stream* ics, bitfile* ld_sf, bitfile* ld_esc, uint8_t* intensity_used); +#ifdef DRM + void DRM_aac_scalable_main_element(NeAACDecStruct* hDecoder, NeAACDecFrameInfo* hInfo, bitfile* ld, program_config* pce, drc_info* drc); +#endif + uint32_t faad_latm_frame(latm_header* latm, bitfile* ld); +#ifdef SSR_DEC + void ssr_decode(ssr_info* ssr, fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, real_t* overlap, + real_t ipqf_buffer[SSR_BANDS][96 / 4], real_t* prev_fmd, uint16_t frame_len); + void ssr_gain_control(ssr_info* ssr, real_t* data, real_t* output, real_t* overlap, real_t* prev_fmd, uint8_t band, uint8_t window_sequence, uint16_t frame_len); + void ssr_gc_function(ssr_info* ssr, real_t* prev_fmd, real_t* gc_function, uint8_t window_sequence, uint16_t frame_len); +#endif + void extract_envelope_data(sbr_info* sbr, uint8_t ch); + void extract_noise_floor_data(sbr_info* sbr, uint8_t ch); +#ifndef FIXED_POINT + void envelope_noise_dequantisation(sbr_info* sbr, uint8_t ch); + void unmap_envelope_noise(sbr_info* sbr); +#endif + void ssr_ipqf(ssr_info* ssr, real_t* in_data, real_t* out_data, real_t buffer[SSR_BANDS][96 / 4], uint16_t frame_len, uint8_t bands); + void faad_mdct_init(uint16_t mdct_len, uint16_t N); + void faad_mdct_end(uint16_t mdct_len); + void faad_imdct(uint16_t mdct_idx, real_t* X_in, real_t* X_out); + void faad_mdct(uint16_t mdct_len, real_t* X_in, real_t* X_out); +#if (defined(PS_DEC) || defined(DRM_PS)) + uint8_t sbrDecodeSingleFramePS(sbr_info* sbr, real_t* left_channel, real_t* right_channel, const uint8_t just_seeked, const uint8_t downSampledSBR); +#endif + // void unmap_envelope_noise(sbr_info* sbr); + int16_t real_to_int16(real_t sig_in); + uint8_t sbr_save_prev_data(sbr_info* sbr, uint8_t ch); + void sbr_save_matrix(sbr_info* sbr, uint8_t ch); + fb_info* ssr_filter_bank_init(uint16_t frame_len); + void ssr_filter_bank_end(fb_info* fb); + void ssr_ifilter_bank(fb_info* fb, uint8_t window_sequence, uint8_t window_shape, uint8_t window_shape_prev, real_t* freq_in, real_t* time_out, uint16_t frame_len); + int32_t find_bands(uint8_t warp, uint8_t bands, uint8_t a0, uint8_t a1); + void sbr_header(bitfile* ld, sbr_info* sbr); + uint8_t calc_sbr_tables(sbr_info* sbr, uint8_t start_freq, uint8_t stop_freq, uint8_t samplerate_mode, uint8_t freq_scale, uint8_t alter_scale, uint8_t xover_band); + uint8_t sbr_data(bitfile* ld, sbr_info* sbr); + uint16_t sbr_extension(bitfile* ld, sbr_info* sbr, uint8_t bs_extension_id, uint16_t num_bits_left); + uint8_t sbr_single_channel_element(bitfile* ld, sbr_info* sbr); + uint8_t sbr_channel_pair_element(bitfile* ld, sbr_info* sbr); + uint8_t sbr_grid(bitfile* ld, sbr_info* sbr, uint8_t ch); + void sbr_dtdf(bitfile* ld, sbr_info* sbr, uint8_t ch); + void invf_mode(bitfile* ld, sbr_info* sbr, uint8_t ch); + void sinusoidal_coding(bitfile* ld, sbr_info* sbr, uint8_t ch); + uint8_t hf_adjustment(sbr_info* sbr, qmf_t Xsbr[MAX_NTSRHFG][64], real_t* deg, uint8_t ch); + uint8_t qmf_start_channel(uint8_t bs_start_freq, uint8_t bs_samplerate_mode, uint32_t sample_rate); + uint8_t qmf_stop_channel(uint8_t bs_stop_freq, uint32_t sample_rate, uint8_t k0); + uint8_t master_frequency_table_fs0(sbr_info* sbr, uint8_t k0, uint8_t k2, uint8_t bs_alter_scale); + uint8_t master_frequency_table(sbr_info* sbr, uint8_t k0, uint8_t k2, uint8_t bs_freq_scale, uint8_t bs_alter_scale); + uint8_t derived_frequency_table(sbr_info* sbr, uint8_t bs_xover_band, uint8_t k2); + void limiter_frequency_table(sbr_info* sbr); +#ifdef SBR_DEC + #ifdef SBR_LOW_POWER + void calc_prediction_coef_lp(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], complex_t* alpha_0, complex_t* alpha_1, real_t* rxx); + void calc_aliasing_degree(sbr_info* sbr, real_t* rxx, real_t* deg); + #else // SBR_LOW_POWER + void calc_prediction_coef(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], complex_t* alpha_0, complex_t* alpha_1, uint8_t k); + #endif // SBR_LOW_POWER + void calc_chirp_factors(sbr_info* sbr, uint8_t ch); + void patch_construction(sbr_info* sbr); +#endif // SBR_DEC +#ifdef SBR_DEC + uint8_t estimate_current_envelope(sbr_info* sbr, sbr_hfadj_info* adj, qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch); + void calculate_gain(sbr_info* sbr, sbr_hfadj_info* adj, uint8_t ch); + #ifdef SBR_LOW_POWER + void calc_gain_groups(sbr_info* sbr, sbr_hfadj_info* adj, real_t* deg, uint8_t ch); + void aliasing_reduction(sbr_info* sbr, sbr_hfadj_info* adj, real_t* deg, uint8_t ch); + #endif // SBR_LOW_POWER + void hf_assembly(sbr_info* sbr, sbr_hfadj_info* adj, qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch); +#endif // SBR_DEC + uint8_t get_S_mapped(sbr_info* sbr, uint8_t ch, uint8_t l, uint8_t current_band); + qmfa_info* qmfa_init(uint8_t channels); + void qmfa_end(qmfa_info* qmfa); + qmfs_info* qmfs_init(uint8_t channels); + void qmfs_end(qmfs_info* qmfs); + void sbr_qmf_analysis_32(sbr_info* sbr, qmfa_info* qmfa, const real_t* input, qmf_t X[MAX_NTSRHFG][64], uint8_t offset, uint8_t kx); + void sbr_qmf_synthesis_32(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output); + void sbr_qmf_synthesis_64(sbr_info* sbr, qmfs_info* qmfs, qmf_t X[MAX_NTSRHFG][64], real_t* output); + uint8_t envelope_time_border_vector(sbr_info* sbr, uint8_t ch); + void noise_floor_time_border_vector(sbr_info* sbr, uint8_t ch); + void hf_generation(sbr_info* sbr, qmf_t Xlow[MAX_NTSRHFG][64], qmf_t Xhigh[MAX_NTSRHFG][64], real_t* deg, uint8_t ch); + void sbr_envelope(bitfile* ld, sbr_info* sbr, uint8_t ch); + void sbr_noise(bitfile* ld, sbr_info* sbr, uint8_t ch); + uint8_t middleBorder(sbr_info* sbr, uint8_t ch); +#ifdef SSR_DEC + // void ssr_ipqf(ssr_info* ssr, real_t* in_data, real_t* out_data, real_t buffer[SSR_BANDS][96 / 4], uint16_t frame_len, uint8_t bands); + void gc_set_protopqf(real_t* p_proto); +#endif +#ifdef PS_DEC + hyb_info* hybrid_init(uint8_t numTimeSlotsRate); + void channel_filter2(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid); + void inline DCT3_4_unscaled(real_t* y, real_t* x); + void channel_filter8(hyb_info* hyb, uint8_t frame_len, const real_t* filter, qmf_t* buffer, qmf_t** X_hybrid); + void hybrid_analysis(hyb_info* hyb, qmf_t X[32][64], qmf_t X_hybrid[32][32], uint8_t use34, uint8_t numTimeSlotsRate); + void hybrid_synthesis(hyb_info* hyb, qmf_t X[32][64], qmf_t X_hybrid[32][32], uint8_t use34, uint8_t numTimeSlotsRate); + int8_t delta_clip(int8_t i, int8_t min, int8_t max); + void delta_decode(uint8_t enable, int8_t* index, int8_t* index_prev, uint8_t dt_flag, uint8_t nr_par, uint8_t stride, int8_t min_index, int8_t max_index); + void delta_modulo_decode(uint8_t enable, int8_t* index, int8_t* index_prev, uint8_t dt_flag, uint8_t nr_par, uint8_t stride, int8_t and_modulo); + void map20indexto34(int8_t* index, uint8_t bins); + #ifdef PS_LOW_POWER + void map34indexto20(int8_t* index, uint8_t bins); + #endif + void ps_data_decode(ps_info* ps); + void ps_decorrelate(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64], qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32]); + void ps_mix_phase(ps_info* ps, qmf_t X_left[38][64], qmf_t X_right[38][64], qmf_t X_hybrid_left[32][32], qmf_t X_hybrid_right[32][32]); +#endif // PS_DEC +#ifdef PS_DEC + uint16_t ps_extension(ps_info* ps, bitfile* ld, const uint8_t ps_extension_id, const uint16_t num_bits_left); + void huff_data(bitfile* ld, const uint8_t dt, const uint8_t nr_par, ps_huff_tab t_huff, ps_huff_tab f_huff, int8_t* par); + int8_t ps_huff_dec(bitfile* ld, ps_huff_tab t_huff); +#endif // PS_DEC + typedef const int8_t (*sbr_huff_tab)[2]; + int16_t sbr_huff_dec(bitfile* ld, sbr_huff_tab t_huff); +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// Macro for comfortable calls +// #define AAC_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +// #define AAC_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +// #define AAC_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +// #define AAC_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +// #define AAC_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/audiolib_structs.hpp b/libraries/ESP32-audioI2S/src/audiolib_structs.hpp new file mode 100644 index 0000000..dcf6e12 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/audiolib_structs.hpp @@ -0,0 +1,446 @@ +#pragma once +#include "psram_unique_ptr.hpp" +#include +#include +#include + +// this file contains definitions of various structs used in Audio lib + +namespace audiolib { +struct sylt_t { + size_t size; + uint32_t pos; + char lang[5]; + uint8_t text_encoding; + uint8_t time_stamp_format; + uint8_t content_type; +}; + +struct ID3Hdr_t { // used only in readID3header() + size_t retvalue = {}; + size_t headerSize = {}; + size_t tagSize = {}; + size_t cnt = {}; + size_t id3Size = {}; + size_t totalId3Size = {}; // if we have more header, id3_1_size + id3_2_size + .... + size_t remainingHeaderBytes = {}; + size_t v22_tag_length = {}; + uint8_t ID3version = {}; + uint8_t ID3revision = {}; + uint8_t flags = {}; + bool unsync = {}; + bool extended_header = {}; + bool experimental_indicator = {}; + bool footer_present = {}; + size_t offset = {}; + size_t currentPosition = {}; + int ehsz = {}; + char tag[5] = {}; + char frameid[5] = {}; + char lang[5] = {}; + size_t framesize = {}; + bool compressed = {}; + std::vector APIC_vec = {}; + sylt_t SYLT = {}; + uint8_t numID3Header = {}; + uint16_t iBuffSize = {}; + uint8_t contentDescriptorTerminator_0 = {}; + uint8_t contentDescriptorTerminator_1 = {}; + uint8_t textStringTerminator_0 = {}; + uint8_t textStringTerminator_1 = {}; + bool byteOrderMark = {}; + ps_ptr iBuff; + + void reset() { *this = ID3Hdr_t{}; } +}; + +struct pwsHLS_t { // used in processWebStreamHLS() + uint16_t maxFrameSize; + uint16_t ID3BuffSize; + uint32_t availableBytes; + bool firstBytes; + bool f_chunkFinished; + uint32_t byteCounter; + int32_t chunkSize; + uint16_t ID3WritePtr; + uint16_t ID3ReadPtr; + ps_ptr ID3Buff; +}; + +struct pplM3u8_t { // used in parsePlaylist_M3U8 + uint64_t xMedSeq; + bool f_mediaSeq_found; + bool firstCall; +}; + +struct m4aHdr_t { // used in read_M4A_Header + size_t headerSize; + size_t retvalue; + size_t atomsize; + size_t sizeof_ftyp; + size_t sizeof_moov; + size_t sizeof_free; + size_t sizeof_mdat; + size_t sizeof_trak; + size_t sizeof_ilst; + size_t sizeof_esds; + size_t sizeof_mdia; + size_t sizeof_minf; + size_t sizeof_mdhd; + size_t sizeof_stbl; + size_t sizeof_stsd; + size_t sizeof_stsz; + size_t sizeof_mp4a; + size_t sizeof_udta; + size_t sizeof_meta; + size_t sizeof_chpl; + size_t audioDataPos; + size_t cnt; + size_t offset; + uint32_t mdat_startPos; + uint32_t picPos; + uint32_t picLen; + uint32_t ilst_pos; + uint8_t channel_count; + uint8_t sample_size; // bps + uint8_t objectTypeIndicator; // esds + uint8_t streamType; // esds + uint32_t bufferSizeDB; // esds + uint32_t maxBitrate; // esds + uint32_t nomBitrate; // esds + uint32_t timescale; // mdhd + uint32_t duration; // mdhd + uint16_t sample_rate; + uint8_t aac_profile; + uint32_t stsz_num_entries; + uint32_t stsz_table_pos; + uint32_t ilst_already_consumed; + bool progressive; // Progressive (moov before mdat) + bool version_flags; + bool mdat_seen; +}; + +struct plCh_t { // used in playChunk + uint32_t count = 0; + size_t i2s_bytesConsumed; + uint16_t samples; + int16_t* sample[2]; + esp_err_t err; +}; + +struct lVar_t { // used in loop + uint8_t no_host_cnt; + uint32_t no_host_timer; + uint8_t count; +}; + +struct hwoe_t { // used in dismantle_host + bool ssl; + ps_ptr hwoe; // host without extension + ps_ptr rqh_host; // host in request header + uint16_t port; + ps_ptr extension; + ps_ptr query_string; +}; + +struct prlf_t { // used in processLocalFile + uint32_t ctime; + int32_t newFilePos; + bool audioHeaderFound; + uint32_t timeout; + uint32_t maxFrameSize; + uint32_t availableBytes; + int32_t bytesAddedToBuffer; +}; + +typedef struct _cat { // used in calculateAudioTime + uint64_t sumBytesIn{}; + uint64_t sum_samples{}; + uint32_t counter{}; + uint32_t timeStamp{}; + uint32_t deltaBytesIn{}; + uint32_t nominalBitRate{}; + uint32_t tota_samples{}; + uint32_t avrBitRate{}; + uint16_t syltIdx{}; + uint32_t avrBitrateStable{}; + uint32_t oldAvrBitrate{}; + uint32_t brCounter{}; + bool firstCall{}; + + void reset() { *this = _cat{}; } +} cat_t; + +struct ifCh_t { // used in IIR_filterChain0, 1, 2 + // s16 + float inSample0_16[2]; + float outSample0_16[2]; + int16_t iir_out0_16[2]; + float inSample1_16[2]; + float outSample1_16[2]; + int16_t iir_out1_16[2]; + float inSample2_16[2]; + float outSample2_16[2]; + int16_t iir_out2_16[2]; + // s32 + float inSample0_32[2]; + float outSample0_32[2]; + int32_t iir_out0_32[2]; + float inSample1_32[2]; + float outSample1_32[2]; + int32_t iir_out1_32[2]; + float inSample2_32[2]; + float outSample2_32[2]; + int32_t iir_out2_32[2]; +}; + +typedef struct _tspp { // used in ts_parsePacket + int pidNumber{}; + int pids[4]{}; // PID_ARRAY_LEN + int PES_DataLength{}; + int pidOfAAC{}; + uint8_t fillData{}; + + void reset() { + *this = _tspp{}; // Default-initialize all new (inclusive Array) + } +} tspp_t; + +struct pwst_t { // used in processWebStream + uint16_t maxFrameSize; + uint32_t chunkSize = 0; + bool f_skipCRLF = false; + uint32_t availableBytes; + bool f_clientIsConnected; + uint32_t writeSpace = 0; + uint16_t readedBytes; +}; + +struct gchs_t { // used in getChunkSize + int32_t chunkSize = -1; + uint32_t timeStamp = {}; + ps_ptr chunkLine = {}; + ps_ptr extension = {}; + ps_ptr trailer = {}; + uint16_t position = 0; + + void reset() { *this = gchs_t{}; } +}; + +struct pwf_t { // used in processWebFile + uint32_t maxFrameSize; + int32_t newFilePos; + bool audioHeaderFound; + uint32_t chunkSize; + size_t audioDataCount; + uint32_t byteCounter; + uint32_t nextChunkCount; + bool f_waitingForPayload = false; + bool f_clientIsConnected; + uint32_t ctime; + uint32_t timeout; + uint32_t availableBytes; + int32_t bytesAddedToBuffer; +}; + +struct pad_t { // used in playAudioData + uint8_t count = 0; + size_t oldAudioDataSize = 0; + bool lastFrames = false; + int32_t bytesToDecode; + int32_t bytesDecoded; +}; + +struct sbyt_t { // used in sendBytes + int32_t bytesLeft; + bool f_setDecodeParamsOnce = true; + uint8_t channels = 0; + int nextSync = 0; + uint8_t isPS = 0; + const char* opus_mode = nullptr; +}; + +struct rmet_t { // used in readMetadata + uint32_t pos_ml = 0; // determines the current position in metaline + uint32_t metaDataSize = 0; + uint16_t res = 0; +}; + +struct pwsts_t { // used in processWebStreamTS + uint32_t availableBytes; // available bytes in stream + bool f_firstPacket; + bool f_chunkFinished; + bool f_nextRound; + uint32_t byteCounter; // count received data + uint8_t ts_packetStart = 0; + uint8_t ts_packetLength = 0; + uint8_t ts_packetPtr = 0; + const uint8_t ts_packetsize = 188; + ps_ptr ts_packet; + size_t chunkSize = 0; +}; + +struct rwh_t { // used in read_WAV_Header + size_t headerSize; + uint32_t cs = 0; + uint8_t bts = 0; +}; + +typedef struct _rflh { // used in read_FLAC_Header + std::vector picVec{}; + size_t headerSize{}; + size_t retvalue{}; + bool f_lastMetaBlock{}; + uint32_t picPos{}; + uint32_t picLen{}; + uint32_t duration{}; + uint32_t nominalBitrate{}; + uint8_t numChannels{}; + uint8_t bitsPerSample{}; + uint32_t sampleRate{}; + uint32_t maxFrameSize{}; + uint32_t maxBlockSize{}; + uint32_t totalSamplesInStream{}; + + void reset() { + // Default-initialize alles neu (inklusive Array) + *this = _rflh{}; + } +} rflh_t; + +typedef struct _phreh { // used in parseHttpResponseHeader + uint32_t ctime{}; + uint32_t timeout{}; + uint32_t stime{}; + uint32_t bitrate{}; + bool f_time{}; + bool f_icy_data{}; + + void reset() { + // Default-initialize alles neu (inklusive Array) + *this = _phreh{}; + } +} phreh_t; + +struct phrah_t { // used in parseHttpRangeHeader + uint32_t ctime; + uint32_t timeout; + uint32_t stime; + bool f_time = false; +}; + +struct sdet_t { // used in streamDetection + uint32_t tmr_slow = 0; + uint32_t tmr_lost = 0; + uint32_t cnt_slow = 0; + uint8_t cnt_lost = 0; +}; + +struct fnsy_t { // used in findNextSync + int nextSync = 0; + uint32_t swnf = 0; +}; + +struct audioItems_t { + float gain_ls_db = 0.0; // lowshelf + float gain_peq_db = 0.0; // peakingEQ + float gain_hs_db = 0.0; // highshelf + float pre_gain = 0.0; // correction factor for level adjustment + float coeffs[3][5] = {0}; + float state_biquad[3][4] = {0}; + uint8_t volume = 0; + uint8_t volume_steps = 21; + float cur_volume = 0.0f; + float limiter[2] = {0}; + float balance = 0.0f; // -16.0 dB left ... 0 ... -16 db right + bool mute = false; +}; + +struct i2s_items_t { + int32_t i2s_num = 0; + uint32_t sampleRate = 48000; + bool commFMT = false; +}; + +struct vu_items_t { + ps_ptr delay_l; + ps_ptr delay_r; + uint16_t delay_line_index = 0; + float left = 0; // average value of samples, left channel + float right = 0; // average value of samples, right channel + uint8_t left_peak = 0; + uint8_t right_peak = 0; + uint16_t left_hold = 0; + uint16_t right_hold = 0; +}; + +#define FFT_BANDS 6 +#define FFT_SIZE 256 +struct fft_items_t { + const uint16_t SIZE = FFT_SIZE; + const uint16_t BANDS = FFT_BANDS; + ps_ptr buffer; // FFT input (real) + ps_ptr window; // FFT window + uint16_t buffer_index = 0; + uint16_t pos = 0; + bool initialized = false; // FFT state + float spec_smooth[FFT_BANDS] = {0}; // smoothing + uint32_t last_ms = 0; // timing (10 Hz) + float gain = 1.0f; // AGC in process() + bool lr_switch = false; // start/stop + ps_ptr work; // FFT work buffer (complex interleaved) + uint8_t spectrum[FFT_BANDS] = {0}; // output +}; + +struct Biquad { + int64_t z1 = 0; + int64_t z2 = 0; +}; + +struct BiquadCoeffs { + int64_t b0; + int64_t b1; + int64_t b2; + int64_t a1; + int64_t a2; +}; + +struct resampler_t { + static constexpr size_t MAX_IN_FRAMES = 4608; + static constexpr size_t MAX_OUT_FRAMES = 10500; + uint64_t phase = 0; + uint64_t phaseStep = 0; + Biquad lpLeft; + Biquad lpRight; + uint32_t outFrames = 0; + BiquadCoeffs g_lpCoeffs; + // Condition for continuous interpolation between frames + int32_t lastL = 0; // Last left sample from previous frame + int32_t lastR = 0; // Last right sample from previous frame + bool hasLast = false; // First frame has no “last” +}; + +struct info_queue_t { + std::deque> msg = {}; + std::deque> s = {}; + std::deque e = {}; // event type + std::deque arg1 = {}; + std::deque arg2 = {}; + std::deque> vec = {}; // apic [pos, len, pos, len, pos, len, ....] + + void reset() { *this = info_queue_t{}; } +}; + +struct icy_items_t { + ps_ptr icy_genre = {}; + ps_ptr icy_logo = {}; + ps_ptr icy_name = {}; + ps_ptr icy_description = {}; + ps_ptr icy_url = {}; + ps_ptr icy_metaint = {}; + ps_ptr icy_br = {}; + + void reset() { *this = icy_items_t{}; } +}; + +} // namespace audiolib \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.cpp b/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.cpp new file mode 100644 index 0000000..8b20904 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.cpp @@ -0,0 +1,1374 @@ +/* + * flac_decoder.cpp + * Java source code from https://www.nayuki.io/page/simple-flac-implementation + * adapted to ESP32 + * + * Created on: Jul 03,2020 + * Updated on: Apr 25,2025 + * + * Author: Wolle + * + */ +#include "flac_decoder.h" + +namespace { +constexpr uint32_t FLAC_MAX_VORBIS_VENDOR_LENGTH = 1024; +constexpr uint32_t FLAC_MAX_VORBIS_COMMENT_ENTRY_LENGTH = 1024 * 1024; +} + +//---------------------------------------------------------------------------------------------------------------------- +// FLAC INI SECTION +//---------------------------------------------------------------------------------------------------------------------- + +bool FlacDecoder::init() { + if (!FLACFrameHeader.alloc_array(1, "FLACFrameHeader")) { + FLAC_LOG_ERROR("not enough memory to allocate FLAC frame header"); + m_valid = false; + return false; + } + if (!FLACFrameHeader.valid()) { + FLAC_LOG_ERROR("FLAC frame header allocation returned invalid pointer"); + m_valid = false; + return false; + } + if (!FLACMetadataBlock.alloc_array(1, "FLACMetadataBlock")) { + FLAC_LOG_ERROR("not enough memory to allocate FLAC metadata block"); + FLACFrameHeader.reset(); + m_valid = false; + return false; + } + if (!FLACMetadataBlock.valid()) { + FLAC_LOG_ERROR("FLAC metadata block allocation returned invalid pointer"); + FLACFrameHeader.reset(); + m_valid = false; + return false; + } + + clear(); + setDefaults(); + m_flacPageNr = 0; + m_valid = true; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void FlacDecoder::clear() { + FLACFrameHeader.zero_mem(); + FLACMetadataBlock.zero_mem(); + + m_samplesBuffer[0].clear(); + m_samplesBuffer[1].clear(); + coefs.clear(); + m_flacSegmTableVec.clear(); + m_flacStatus = DECODE_FRAME; + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void FlacDecoder::reset() { + FLACFrameHeader.reset(); + FLACMetadataBlock.reset(); + m_flacStreamTitle.reset(); + m_flacVendorString.reset(); + + m_samplesBuffer[0].reset(); + m_samplesBuffer[1].reset(); + coefs.clear(); + m_flacSegmTableVec.clear(); + m_flacBlockPicItem.clear(); + m_valid = false; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void FlacDecoder::setDefaults() { + coefs.clear(); + m_flacSegmTableVec.clear(); + m_flacBlockPicItem.clear(); + m_flac_bitBuffer = 0; + m_flacBitrate = 0; + m_flacBlockPicLenUntilFrameEnd = 0; + m_flacCurrentFilePos = 0; + m_flacBlockPicPos = 0; + m_flacBlockPicLen = 0; + m_flacRemainBlockPicLen = 0; + m_flacAudioDataStart = 0; + m_numOfOutSamples = 0; + m_offset = 0; + m_flacValidSamples = 0; + m_rIndex = 0; + m_flacStatus = DECODE_FRAME; + m_flacCompressionRatio = 0; + m_flacBitBufferLen = 0; + m_flac_pageSegments = 0; + m_f_flacNewStreamtitle = false; + m_f_flacFirstCall = true; + m_f_oggWrapper = false; + m_f_lastMetaDataBlock = false; + m_f_flacNewMetadataBlockPicture = false; + m_f_flacParseOgg = false; + m_f_bitReaderError = false; + m_nBytes = 0; +} +bool FlacDecoder::isValid() { + return m_valid; +} +//---------------------------------------------------------------------------------------------------------------------- +// B I T R E A D E R +//---------------------------------------------------------------------------------------------------------------------- + +uint32_t FlacDecoder::readUint(uint8_t nBits, int32_t* bytesLeft) { + + const uint32_t mask[33] = {0x00000000, 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}; + + while (m_flacBitBufferLen < nBits) { + uint8_t temp = *(m_flacInptr + m_rIndex); + m_rIndex++; + (*bytesLeft)--; + if (*bytesLeft == -1) { + if (m_f_oggWrapper) { + m_rIndex--; + (*bytesLeft)++; + // If the Flac frame is larger than the OGG frame, we are looking for the OGG's identifier + if (specialIndexOf(m_flacInptr + m_rIndex, "OggS", 4) == 0) { // next OGG recognized + parseOGG(m_flacInptr + m_rIndex, bytesLeft); // parse OGG and set segment tables, bytesLeft is now negative + m_segmLength = m_flacSegmTableVec.back(); // read the first table + m_flacSegmTableVec.pop_back(); // and remove them + m_f_flacParseOgg = false; // no next OGG parse necessary + m_rIndex += abs(*bytesLeft); // increase m_rIndex + continue; // go ahead + } else { + FLAC_LOG_ERROR("error in bitreader"); + m_f_bitReaderError = true; + break; + } + } + } + m_flac_bitBuffer = (m_flac_bitBuffer << 8) | temp; + m_flacBitBufferLen += 8; + } + m_flacBitBufferLen -= nBits; + uint32_t result = m_flac_bitBuffer >> m_flacBitBufferLen; + if (nBits < 32) result &= mask[nBits]; + return result; +} + +void FlacDecoder::alignToByte() { + m_flacBitBufferLen -= m_flacBitBufferLen % 8; +} +//---------------------------------------------------------------------------------------------------------------------- +// F L A C - D E C O D E R +//---------------------------------------------------------------------------------------------------------------------- +void FlacDecoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) { + FLAC_LOG_DEBUG("channels {}, sampleRate {}, BPS {}, tsis {}, AuDaLength {}", channels, sampleRate, BPS, tsis, AuDaLength); + FLACMetadataBlock->numChannels = channels; + FLACMetadataBlock->sampleRate = sampleRate; + FLACMetadataBlock->bitsPerSample = BPS; + FLACMetadataBlock->totalSamples = tsis; // total samples in stream + FLACMetadataBlock->audioDataLength = AuDaLength; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void FlacDecoder::decoderReset() { // set var to default + setDefaults(); + clear(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + + // FLAC CRC-8 table (polynomial 0x07, initial value 0) + static const uint8_t FLAC_CRC8_TABLE[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; + + // Correct FLAC UTF-8 parsing (shortened UTF-8 for frame/sample numbers) + auto parseFlacUtf8 = [&](const uint8_t* p, uint64_t& value) -> int { + value = 0; + uint8_t c = p[0]; + + // Single byte: 0xxxxxxx + if ((c & 0x80) == 0) { + value = c; + return 1; + } + + // 10xxxxxx is never a valid start + if ((c & 0xC0) == 0x80) { return 0; } + + int len = 0; + uint8_t mask = 0; + + // Determine length and mask + if ((c & 0xE0) == 0xC0) { // 110xxxxx + len = 2; + mask = 0x1F; + } else if ((c & 0xF0) == 0xE0) { // 1110xxxx + len = 3; + mask = 0x0F; + } else if ((c & 0xF8) == 0xF0) { // 11110xxx + len = 4; + mask = 0x07; + } else if ((c & 0xFC) == 0xF8) { // 111110xx + len = 5; + mask = 0x03; + } else if ((c & 0xFE) == 0xFC) { // 1111110x + len = 6; + mask = 0x01; + } else if (c == 0xFE) { // 11111110 + len = 7; + mask = 0x00; + } else { + return 0; // Invalid + } + + // Start value from first byte + value = c & mask; + + // Process continuation bytes + for (int i = 1; i < len; i++) { + uint8_t b = p[i]; + // Each continuation byte must be 10xxxxxx + if ((b & 0xC0) != 0x80) { return 0; } + value = (value << 6) | (b & 0x3F); + } + + // FLAC Limit: max 36 Bit + if (value >= (1ULL << 36)) { return 0; } + + return len; + }; + + // CRC-8 calculation with table + auto checkHeaderCRC8 = [&](const uint8_t* hdr, int header_len) -> bool { + if (header_len < 2) return false; + + uint8_t expected = hdr[header_len - 1]; + uint8_t crc = 0; + + for (int i = 0; i < header_len - 1; i++) { crc = FLAC_CRC8_TABLE[crc ^ hdr[i]]; } + return crc == expected; + }; + + // OggS Wrapper Check + int32_t i = specialIndexOf(buf, "OggS", nBytes); + if (i == 0) { + m_f_bitReaderError = false; + return 0; + } + + if (m_f_oggWrapper && i > 0) { + m_f_bitReaderError = false; + return i; + } + + // FLAC native search + for (int32_t i = 0; i < nBytes - 16; i++) { // Less than 16 bytes for full download + + // 1. Sync check (14 bits): 0xFFF8 bis 0xFFFF im ersten Word + if (buf[i] != 0xFF || (buf[i + 1] & 0xFC) != 0xF8) { continue; } + + // Optional: Prevent split sync (if previous byte was 0xFF) + if (i > 0 && buf[i - 1] == 0xFF) { continue; } + + // 2. Extract header fields + uint8_t b2 = buf[i + 2]; + uint8_t b3 = buf[i + 3]; + + uint8_t blocksize_code = (b2 >> 4) & 0x0F; + uint8_t samplerate_code = b2 & 0x0F; + uint8_t channel_assign = (b3 >> 4) & 0x0F; + uint8_t bps_code = (b3 >> 1) & 0x07; + uint8_t reserved_bit = b3 & 0x01; + + // 3. Plausibility checks + if (reserved_bit) continue; + if (blocksize_code == 0) continue; + if (samplerate_code == 0x0F) continue; + if (channel_assign > 10) continue; + if (bps_code == 0 || bps_code == 7) continue; + + // 4. UTF-8 frame/sample number parsen + uint64_t frameNum; + int utf8_len = parseFlacUtf8(&buf[i + 4], frameNum); + if (utf8_len == 0) continue; + + // 5.calculate header length + int header_len = 4 + utf8_len; // Sync(2) + Header(2) + UTF8 + + // extra blocksize bytes (Big-Endian) + if (blocksize_code == 6) { + header_len += 1; // 8-Bit + } else if (blocksize_code == 7) { + header_len += 2; // 16-Bit + } + + // Extra Samplerate Bytes (Big-Endian) + if (samplerate_code == 12) { + header_len += 1; // 8-Bit kHz + } else if (samplerate_code == 13) { + header_len += 2; // 16-Bit Hz + } else if (samplerate_code == 14) { + header_len += 2; // 16-bit kHz + } + + header_len += 1; // CRC-8 Byte + + // chack if header is completely in buffer + if (i + header_len > nBytes) continue; + + // 6. validate CRC-8 + if (!checkHeaderCRC8(&buf[i], header_len)) continue; + + // found valid sync! + if (i > 0) { decoderReset(); } + return i; + } + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +boolean FlacDecoder::FLACFindMagicWord(unsigned char* buf, int32_t nBytes) { + int32_t idx = specialIndexOf(buf, "fLaC", nBytes); + if (idx > 0) { // Metadatablock follows + idx += 4; + boolean lmdbf = ((buf[idx + 1] & 0x80) == 0x80); // Last-metadata-block flag + uint8_t bt = (buf[idx + 1] & 0x7F); // block type + uint32_t lomd = (buf[idx + 2] << 16) + (buf[idx + 3] << 8) + buf[idx + 4]; // Length of metadata to follow + + (void)lmdbf; + (void)bt; + (void)lomd; + // FLAC_LOG_INFO("Last-metadata-block flag: {}", lmdbf); + // FLAC_LOG_INFO("block type: {}", bt); + // FLAC_LOG_INFO("Length (in bytes) of metadata to follow: {}", lomd); + return true; + } + return false; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* FlacDecoder::getStreamTitle() { + if (m_f_flacNewStreamtitle) { + m_f_flacNewStreamtitle = false; + return m_flacStreamTitle.get(); + } + return NULL; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* FlacDecoder::whoIsIt() { + return "FLAC"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::parseOGG(uint8_t* inbuf, int32_t* bytesLeft) { // reference https://www.xiph.org/ogg/doc/rfc3533.txt + + m_f_flacParseOgg = false; + int32_t idx = specialIndexOf(inbuf, "OggS", 6); + if (idx != 0) { + FLAC_LOG_ERROR("Flac decoder asyncron, \"OggS\" not found"); + return FLAC_ERR; + } + + uint8_t version = *(inbuf + 4); + (void)version; + uint8_t headerType = *(inbuf + 5); + (void)headerType; + uint64_t granulePosition = (uint64_t)*(inbuf + 13) << 56; // granule_position: an 8 Byte field containing - + granulePosition += (uint64_t)*(inbuf + 12) << 48; // position information. For an audio stream, it MAY + granulePosition += (uint64_t)*(inbuf + 11) << 40; // contain the total number of PCM samples encoded + granulePosition += (uint64_t)*(inbuf + 10) << 32; // after including all frames finished on this page. + granulePosition += *(inbuf + 9) << 24; // This is a hint for the decoder and gives it some timing + granulePosition += *(inbuf + 8) << 16; // and position information. A special value of -1 (in two's + granulePosition += *(inbuf + 7) << 8; // complement) indicates that no packets finish on this page. + granulePosition += *(inbuf + 6); + (void)granulePosition; + uint32_t bitstreamSerialNr = *(inbuf + 17) << 24; // bitstream_serial_number: a 4 Byte field containing the + bitstreamSerialNr += *(inbuf + 16) << 16; // unique serial number by which the logical bitstream + bitstreamSerialNr += *(inbuf + 15) << 8; // is identified. + bitstreamSerialNr += *(inbuf + 14); + (void)bitstreamSerialNr; + uint32_t pageSequenceNr = *(inbuf + 21) << 24; // page_sequence_number: a 4 Byte field containing the sequence + pageSequenceNr += *(inbuf + 20) << 16; // number of the page so the decoder can identify page loss + pageSequenceNr += *(inbuf + 19) << 8; // This sequence number is increasing on each logical bitstream + pageSequenceNr += *(inbuf + 18); + (void)pageSequenceNr; + uint32_t CRCchecksum = *(inbuf + 25) << 24; + CRCchecksum += *(inbuf + 24) << 16; + CRCchecksum += *(inbuf + 23) << 8; + CRCchecksum += *(inbuf + 22); + (void)CRCchecksum; + uint8_t pageSegments = *(inbuf + 26); // giving the number of segment entries + + // read the segment table (contains pageSegments bytes), 1...251: Length of the frame in bytes, + // 255: A second byte is needed. The total length is first_byte + second byte + m_flacSegmTableVec.clear(); + for (int32_t i = 0; i < pageSegments; i++) { + int32_t n = *(inbuf + 27 + i); + while (*(inbuf + 27 + i) == 255) { + i++; + if (i == pageSegments) break; + n += *(inbuf + 27 + i); + } + m_flacSegmTableVec.insert(m_flacSegmTableVec.begin(), n); + } + // for(int32_t i = 0; i< m_flacSegmTableVec.size(); i++){FLAC_LOG_INFO("{}", m_flacSegmTableVec[i]);} + + bool continuedPage = headerType & 0x01; // set: page contains data of a packet continued from the previous page + bool firstPage = headerType & 0x02; // set: this is the first page of a logical bitstream (bos) + bool lastPage = headerType & 0x04; // set: this is the last page of a logical bitstream (eos) + m_continued_page = continuedPage; + (void)lastPage; + + // FLAC_LOG_INFO("firstPage {}, continuedPage {}, lastPage {}", firstPage, continuedPage, lastPage); + + if (firstPage) m_flacPageNr = 0; + + uint32_t headerSize = pageSegments + 27; + + *bytesLeft -= headerSize; + m_flacCurrentFilePos += headerSize; + return FLAC_NONE; // no error +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector FlacDecoder::getMetadataBlockPicture() { + if (m_f_flacNewMetadataBlockPicture) { + m_f_flacNewMetadataBlockPicture = false; + return m_flacBlockPicItem; + } + return m_flacBlockPicItem; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::parseFlacFirstPacket(uint8_t* inbuf, int16_t nBytes) { // 4.2.2. Identification header https://xiph.org/flac/ogg_mapping.html + + int32_t ret = 0; + int32_t idx = specialIndexOf(inbuf, "fLaC", nBytes); + // FLAC_LOG_INFO("idx {}, nBytes {}", idx, nBytes); + if (idx >= 0) { // FLAC signature found + ret = idx + 4; + } else { + FLAC_LOG_ERROR("Flac signature \"fLaC\" not found"); + ret = FLAC_ERR; + } + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::parseMetaDataBlockHeader(uint8_t* inbuf, int16_t nBytes) { + + int8_t ret = FLAC_PARSE_OGG_DONE; + uint16_t pos = 0; + int32_t blockLength = 0; + uint16_t minBlocksize = 0; + uint16_t maxBlocksize = 0; + uint32_t minFrameSize = 0; + uint32_t maxFrameSize = 0; + uint32_t sampleRate = 0; + uint32_t vendorLength = 0; + uint32_t commemtStringLength = 0; + uint32_t userCommentListLength = 0; + uint8_t nrOfChannels = 0; + uint8_t bitsPerSample = 0; + uint64_t totalSamplesInStream = 0; + uint8_t mdBlockHeader = 0; + uint8_t blockType = 0; + uint8_t bt = 0; + std::vector> vb(8); // vorbis comment + + auto readLE32 = [](const uint8_t* p) -> uint32_t { + return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); + }; + + auto isVorbisField = [&](const uint8_t* comment, uint32_t commentLength, const char* upper, const char* lower, uint32_t valueOffset) -> bool { + if (commentLength < valueOffset) return false; + return (specialIndexOf((uint8_t*)comment, upper, valueOffset) == 0) || (specialIndexOf((uint8_t*)comment, lower, valueOffset) == 0); + }; + + auto assignVorbisValue = [](ps_ptr& dst, const uint8_t* comment, uint32_t commentLength, uint32_t valueOffset) -> bool { + if (commentLength < valueOffset) return false; + dst.assign((const char*)(comment + valueOffset), min((uint32_t)127, commentLength - valueOffset)); + return true; + }; + + enum { streamInfo, padding, application, seekTable, vorbisComment, cueSheet, picture }; + + while (true) { + mdBlockHeader = *(inbuf + pos); + m_f_lastMetaDataBlock = mdBlockHeader & 0b10000000; // FLAC_LOG_INFO("lastMdBlockFlag {}", m_f_lastMetaDataBlock); + blockType = mdBlockHeader & 0b01111111; // FLAC_LOG_INFO("blockType {}", blockType); + + blockLength = *(inbuf + pos + 1) << 16; + blockLength += *(inbuf + pos + 2) << 8; + blockLength += *(inbuf + pos + 3); // FLAC_LOG_INFO("blockLength {}", blockLength); + + nBytes -= 4; + pos += 4; + + switch (blockType) { + case 0: bt = streamInfo; break; + case 1: + bt = padding; + // FLAC_LOG_ERROR("padding"); + return FLAC_NONE; + break; + case 2: + bt = application; + FLAC_LOG_ERROR("Flac unimplemented block type: {}", blockType); + return FLAC_ERR; + break; + case 3: + bt = seekTable; + FLAC_LOG_ERROR("Flac unimplemented seek table: {}", seekTable); + return FLAC_ERR; + break; + case 4: bt = vorbisComment; break; + case 5: + bt = cueSheet; + FLAC_LOG_ERROR("Flac unimplemented cue sheet: {}", cueSheet); + return FLAC_ERR; + break; + case 6: bt = picture; break; + default: + bt = streamInfo; + // return ERR_FLAC_UNIMPLEMENTED; + break; + } + + switch (bt) { + case streamInfo: + minBlocksize += *(inbuf + pos + 0) << 8; + minBlocksize += *(inbuf + pos + 1); + maxBlocksize += *(inbuf + pos + 2) << 8; + maxBlocksize += *(inbuf + pos + 3); + // FLAC_LOG_INFO("minBlocksize {}", minBlocksize); + // FLAC_LOG_INFO("maxBlocksize {}", maxBlocksize); + FLACMetadataBlock->minblocksize = minBlocksize; + FLACMetadataBlock->maxblocksize = maxBlocksize; + + if (maxBlocksize > m_maxBlocksize) { + FLAC_LOG_ERROR("s_blocksize is too big: {} bytes, max block size: {}", maxBlocksize, m_maxBlocksize); + return FLAC_ERR; + } + + minFrameSize = *(inbuf + pos + 4) << 16; + minFrameSize += *(inbuf + pos + 5) << 8; + minFrameSize += *(inbuf + pos + 6); + maxFrameSize = *(inbuf + pos + 7) << 16; + maxFrameSize += *(inbuf + pos + 8) << 8; + maxFrameSize += *(inbuf + pos + 9); + // FLAC_LOG_INFO("minFrameSize {}", minFrameSize); + // FLAC_LOG_INFO("maxFrameSize {}", maxFrameSize); + FLACMetadataBlock->minframesize = minFrameSize; + FLACMetadataBlock->maxframesize = maxFrameSize; + + sampleRate = *(inbuf + pos + 10) << 12; + sampleRate += *(inbuf + pos + 11) << 4; + sampleRate += (*(inbuf + pos + 12) & 0xF0) >> 4; + // FLAC_LOG_INFO("sampleRate {}", sampleRate); + FLACMetadataBlock->sampleRate = sampleRate; + + nrOfChannels = ((*(inbuf + pos + 12) & 0x0E) >> 1) + 1; + // FLAC_LOG_INFO("nrOfChannels {}", nrOfChannels); + FLACMetadataBlock->numChannels = nrOfChannels; + + bitsPerSample = (*(inbuf + pos + 12) & 0x01) << 4; + bitsPerSample += ((*(inbuf + pos + 13) & 0xF0) >> 4) + 1; + FLACMetadataBlock->bitsPerSample = bitsPerSample; + // FLAC_LOG_INFO("bitsPerSample {}", bitsPerSample); + + totalSamplesInStream = (uint64_t)(*(inbuf + pos + 13) & 0x0F) << 32; + totalSamplesInStream += (uint64_t)(*(inbuf + pos + 14)) << 24; + totalSamplesInStream += (uint64_t)(*(inbuf + pos + 15)) << 16; + totalSamplesInStream += (uint64_t)(*(inbuf + pos + 16)) << 8; + totalSamplesInStream += (uint64_t)(*(inbuf + pos + 17)); + // FLAC_LOG_INFO("totalSamplesInStream {}", totalSamplesInStream); + FLACMetadataBlock->totalSamples = totalSamplesInStream; + + // FLAC_LOG_INFO("nBytes {}, blockLength {}", nBytes, blockLength); + pos += blockLength; + nBytes -= blockLength; + if (ret == FLAC_PARSE_OGG_DONE) return ret; + break; + + case vorbisComment: { // https://www.xiph.org/vorbis/doc/v-comment.html + if (blockLength < 8 || blockLength > nBytes) { + FLAC_LOG_ERROR("Flac invalid Vorbis comment block length: {}, bytes available: {}", blockLength, nBytes); + return FLAC_ERR; + } + + const uint32_t vorbisBlockEnd = (uint32_t)pos + (uint32_t)blockLength; + vendorLength = readLE32(inbuf + pos); + if (vendorLength > FLAC_MAX_VORBIS_VENDOR_LENGTH) { + FLAC_LOG_ERROR("Flac Vorbis vendor string too long: {} bytes, max: {}", vendorLength, FLAC_MAX_VORBIS_VENDOR_LENGTH); + return FLAC_ERR; + } + if (vendorLength > (uint32_t)blockLength - 8) { + FLAC_LOG_ERROR("Flac invalid Vorbis vendor string length: {}, block length: {}", vendorLength, blockLength); + return FLAC_ERR; + } + + if (!m_flacVendorString.alloc(vendorLength + 1, "m_flacVendorString")) { + m_valid = false; + return FLAC_ERR; + } + m_flacVendorString.clear(); + m_flacVendorString.copy_from((char*)inbuf + pos + 4, vendorLength); + // FLAC_LOG_VERBOSE("Vendor: {}", m_flacVendorString.c_get()); + + pos += 4 + vendorLength; + userCommentListLength = readLE32(inbuf + pos); + + pos += 4; + commemtStringLength = 0; + for (uint32_t i = 0; i < userCommentListLength; i++) { + if ((uint32_t)pos + 4 > vorbisBlockEnd) { + FLAC_LOG_ERROR("Flac invalid Vorbis comment list length: {}", userCommentListLength); + return FLAC_ERR; + } + + commemtStringLength = readLE32(inbuf + pos); + if (commemtStringLength > FLAC_MAX_VORBIS_COMMENT_ENTRY_LENGTH) { + FLAC_LOG_ERROR("Flac Vorbis comment string too long: {} bytes, max: {}", commemtStringLength, FLAC_MAX_VORBIS_COMMENT_ENTRY_LENGTH); + return FLAC_ERR; + } + if (commemtStringLength > vorbisBlockEnd - ((uint32_t)pos + 4)) { + FLAC_LOG_ERROR("Flac invalid Vorbis comment string length: {}", commemtStringLength); + return FLAC_ERR; + } + + const uint8_t* comment = inbuf + pos + 4; + + if (isVorbisField(comment, commemtStringLength, "TITLE", "title", 6)) { + assignVorbisValue(vb[0], comment, commemtStringLength, 6); + audio.info(audio, Audio::evt_id3data, "Title: {}", vb[0].c_get()); + // FLAC_LOG_VERBOSE("TITLE: {}", vb[0].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "ARTIST", "artist", 7)) { + assignVorbisValue(vb[1], comment, commemtStringLength, 7); + audio.info(audio, Audio::evt_id3data, "Artist: {}", vb[1].c_get()); + // FLAC_LOG_VERBOSE("ARTIST: {}", vb[1].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "GENRE", "genre", 6)) { + assignVorbisValue(vb[2], comment, commemtStringLength, 6); + audio.info(audio, Audio::evt_id3data, "Genre: {}", vb[2].c_get()); + FLAC_LOG_VERBOSE("GENRE: {}", vb[2].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "ALBUM", "album", 6)) { + assignVorbisValue(vb[3], comment, commemtStringLength, 6); + audio.info(audio, Audio::evt_id3data, "Album: {}", vb[3].c_get()); + FLAC_LOG_VERBOSE("ALBUM: {}", vb[3].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "COMMENT", "comment", 8)) { + assignVorbisValue(vb[4], comment, commemtStringLength, 8); + audio.info(audio, Audio::evt_id3data, "Comments: {}", vb[4].c_get()); + FLAC_LOG_VERBOSE("COMMENT: {}", vb[4].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "DATE", "date", 5)) { + assignVorbisValue(vb[5], comment, commemtStringLength, 5); + audio.info(audio, Audio::evt_id3data, "Date: {}", vb[5].c_get()); + FLAC_LOG_VERBOSE("DATE: {}", vb[5].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "TRACKNUMBER", "tracknumber", 12)) { + assignVorbisValue(vb[6], comment, commemtStringLength, 12); + audio.info(audio, Audio::evt_id3data, "Track number/Position in set: {}", vb[6].c_get()); + FLAC_LOG_VERBOSE("TRACKNUMBER: {}", vb[6].c_get()); + } + if (isVorbisField(comment, commemtStringLength, "METADATA_BLOCK_PICTURE", "metadata_block_picture", 23)) { + if (commemtStringLength < 23) { + FLAC_LOG_ERROR("Flac invalid METADATA_BLOCK_PICTURE length: {}", commemtStringLength); + return FLAC_ERR; + } + FLAC_LOG_VERBOSE("METADATA_BLOCK_PICTURE found, commemtStringLength {}", commemtStringLength); + m_flacBlockPicLen = commemtStringLength - 23; + m_flacBlockPicPos = m_flacCurrentFilePos + pos + 4 + 23; + m_flacBlockPicLenUntilFrameEnd = 0; + if ((uint32_t)nBytes > (uint32_t)pos + 23) m_flacBlockPicLenUntilFrameEnd = (uint32_t)nBytes - ((uint32_t)pos + 23); + if (m_flacBlockPicLen < m_flacBlockPicLenUntilFrameEnd) m_flacBlockPicLenUntilFrameEnd = m_flacBlockPicLen; + m_flacRemainBlockPicLen = m_flacBlockPicLen - m_flacBlockPicLenUntilFrameEnd; + // FLAC_LOG_INFO("s_flacBlockPicPos {}, m_flacBlockPicLen {}", m_flacBlockPicPos, m_flacBlockPicLen); + // FLAC_LOG_INFO("s_flacBlockPicLenUntilFrameEnd {}, m_flacRemainBlockPicLen {}", m_flacBlockPicLenUntilFrameEnd, m_flacRemainBlockPicLen); + if (m_flacRemainBlockPicLen <= 0) m_f_lastMetaDataBlock = true; // exeption:: goto audiopage after commemt if lastMetaDataFlag is not set + if (m_flacBlockPicLen) { + m_flacBlockPicItem.push_back(m_flacBlockPicPos); + m_flacBlockPicItem.push_back(m_flacBlockPicLenUntilFrameEnd); + } + } + pos += 4 + commemtStringLength; + FLAC_LOG_VERBOSE("nBytes {}, pos {}, commemtStringLength {}", nBytes, pos, commemtStringLength); + } + if (vb[1].valid() && vb[0].valid()) { // artist and title + m_flacStreamTitle.assign(vb[1].c_get()); + m_flacStreamTitle.append(" - "); + m_flacStreamTitle.append(vb[0].c_get()); + m_f_flacNewStreamtitle = true; + } else if (vb[1].valid()) { + m_flacStreamTitle.assign(vb[1].c_get()); + m_f_flacNewStreamtitle = true; + } else if (vb[0].valid()) { + m_flacStreamTitle.assign(vb[0].c_get()); + m_f_flacNewStreamtitle = true; + } + if (!m_flacBlockPicLen && m_flacSegmTableVec.size() == 1) m_f_lastMetaDataBlock = true; // exeption:: goto audiopage after commemt if lastMetaDataFlag is not set + if (ret == FLAC_PARSE_OGG_DONE) return ret; + break; + } + + case picture: + if (ret == FLAC_PARSE_OGG_DONE) return ret; + break; + + default: return ret; break; + } + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { // MAIN LOOP + + int32_t ret = 0; + uint32_t segmLen = 0; + + m_segmLenTmp = 0; + + if (m_f_flacFirstCall) { // determine if ogg or flag + m_f_flacFirstCall = false; + m_nBytes = 0; + m_segmLenTmp = 0; + if (specialIndexOf(inbuf, "OggS", 5) == 0) { + m_f_oggWrapper = true; + m_f_flacParseOgg = true; + m_f_first_flac_frame = true; + } + } + + if (m_f_oggWrapper) { + + if (m_segmLenTmp) { // can't skip more than 16K + if (m_segmLenTmp > FLAC_MAX_BLOCKSIZE) { + m_flacCurrentFilePos += FLAC_MAX_BLOCKSIZE; + *bytesLeft -= FLAC_MAX_BLOCKSIZE; + m_segmLenTmp -= FLAC_MAX_BLOCKSIZE; + } else { + m_flacCurrentFilePos += m_segmLenTmp; + *bytesLeft -= m_segmLenTmp; + m_segmLenTmp = 0; + } + return FLAC_PARSE_OGG_DONE; + } + + if (m_nBytes > 0) { + int16_t diff = m_nBytes; + if (m_flacAudioDataStart == 0) { m_flacAudioDataStart = m_flacCurrentFilePos; } + ret = decodeNative(inbuf, &m_nBytes, outbuf); + diff -= m_nBytes; + m_flacCurrentFilePos += diff; + *bytesLeft -= diff; + if (m_nBytes < 0) m_nBytes = 0; // When the FLAC frame is larger than the OGG frame m_nbytes becomes negative + return ret; + } + if (m_nBytes < 0) { + FLAC_LOG_ERROR("Flac decoder asynchron"); + return FLAC_ERR; + } + + if (m_f_flacParseOgg == true) { + m_f_flacParseOgg = false; + ret = parseOGG(inbuf, bytesLeft); + if (ret == FLAC_NONE) + return FLAC_PARSE_OGG_DONE; // ok + else + return ret; // error + } + //------------------------------------------------------- + if (!m_flacSegmTableVec.size()) { FLAC_LOG_ERROR("size is 0"); } + segmLen = m_flacSegmTableVec.back(); + m_segmLength = segmLen; + m_flacSegmTableVec.pop_back(); + if (!m_flacSegmTableVec.size()) m_f_flacParseOgg = true; + //------------------------------------------------------- + + if (m_flacRemainBlockPicLen <= 0 && !m_f_flacNewMetadataBlockPicture) { + if (m_flacBlockPicItem.size() > 0) { // get blockpic data + // FLAC_LOG_INFO("---------------------------------------------------------------------------"); + // FLAC_LOG_INFO("metadata blockpic found at pos {}, size {} bytes", m_flacBlockPicPos, m_flacBlockPicLen); + // for(int32_t i = 0; i < m_flacBlockPicItem.size(); i += 2) { FLAC_LOG_INFO("segment {:02}, pos {:07}, len {:05}", i / 2, m_flacBlockPicItem[i], m_flacBlockPicItem[i + 1]); } + // FLAC_LOG_INFO("---------------------------------------------------------------------------"); + m_f_flacNewMetadataBlockPicture = true; + } + } + + switch (m_flacPageNr) { + case 0: + ret = parseFlacFirstPacket(inbuf, segmLen); + if (ret == segmLen) { + m_flacPageNr = 1; + ret = FLAC_PARSE_OGG_DONE; + break; + } + if (ret < 0) { // fLaC signature not found + break; + } + if (ret < segmLen) { + segmLen -= ret; + *bytesLeft -= ret; + m_flacCurrentFilePos += ret; + inbuf += ret; + m_flacPageNr = 1; + } /* fallthrough */ + case 1: + if (m_flacRemainBlockPicLen > 0) { + m_flacRemainBlockPicLen -= segmLen; + // FLAC_LOG_INFO("s_flacCurrentFilePos {}, len {}, m_flacRemainBlockPicLen {}", m_flacCurrentFilePos, segmLen, m_flacRemainBlockPicLen); + m_flacBlockPicItem.push_back(m_flacCurrentFilePos); + m_flacBlockPicItem.push_back(segmLen); + if (m_flacRemainBlockPicLen <= 0) { m_flacPageNr = 2; } + ret = FLAC_PARSE_OGG_DONE; + break; + } + ret = parseMetaDataBlockHeader(inbuf, segmLen); + if (m_f_lastMetaDataBlock) m_flacPageNr = 2; + break; + case 2: + m_nBytes = segmLen; + return FLAC_PARSE_OGG_DONE; + break; + } + if (segmLen > FLAC_MAX_BLOCKSIZE) { + m_segmLenTmp = segmLen; + return FLAC_PARSE_OGG_DONE; + } + *bytesLeft -= segmLen; + m_flacCurrentFilePos += segmLen; + return ret; + } + ret = decodeNative(inbuf, bytesLeft, outbuf); + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeNative(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + int32_t bl = *bytesLeft; + static int32_t sbl = 0; + + if (m_flacStatus != OUT_SAMPLES) { + m_rIndex = 0; + m_flacInptr = inbuf; + } + + while (m_flacStatus == DECODE_FRAME) { // Read a ton of header fields, and ignore most of them + int32_t ret = decodeFrame(inbuf, bytesLeft); + if (ret != 0) return ret; + if (*bytesLeft < FLAC_MAX_BLOCKSIZE) return FLAC_DECODE_FRAMES_LOOP; // need more data + sbl += bl - *bytesLeft; + } + + if (m_flacStatus == DECODE_SUBFRAMES) { + // Decode each channel's subframe, then skip footer + int32_t ret = decodeSubframes(bytesLeft); + if (ret != 0) return ret; + m_flacStatus = OUT_SAMPLES; + sbl += bl - *bytesLeft; + } + + if (m_flacStatus == OUT_SAMPLES) { // Write the decoded samples + // blocksize can be much greater than outbuff, so we can't stuff all in once + // therefore we need often more than one loop (split outputblock into pieces) + uint32_t blockSize; + if (m_numOfOutSamples - m_offset > FLAC_MAX_OUTBUFFSIZE) { + blockSize = FLAC_MAX_OUTBUFFSIZE; + m_flacValidSamples = FLAC_MAX_OUTBUFFSIZE; + } else { + blockSize = m_numOfOutSamples - m_offset; + m_flacValidSamples = blockSize; + } + + if (FLACMetadataBlock->numChannels == 1) { + const int64_t* src = m_samplesBuffer[0].get() + m_offset; + + for (int32_t i = 0; i < blockSize; i++) { + int32_t val = *src++; + if (FLACMetadataBlock->bitsPerSample == 8) { + val += 128; + outbuf[i * 2] = (val << 24); + outbuf[i * 2 + 1] = (val << 24); + } else if (FLACMetadataBlock->bitsPerSample == 16) { + outbuf[i * 2] = (val << 16); + outbuf[i * 2 + 1] = (val << 16); + } else if (FLACMetadataBlock->bitsPerSample == 24) { + outbuf[i * 2] = (val << 8); + outbuf[i * 2 + 1] = (val << 8); + } else if (FLACMetadataBlock->bitsPerSample == 32) { + outbuf[i * 2] = (val); + outbuf[i * 2 + 1] = (val); + } + } + } + + if (FLACMetadataBlock->numChannels == 2) { + const int64_t* left = m_samplesBuffer[0].get() + m_offset; + const int64_t* right = m_samplesBuffer[1].get() + m_offset; + + for (int32_t i = 0; i < blockSize; i++) { + int32_t l = *left++; + int32_t r = *right++; + if (FLACMetadataBlock->bitsPerSample == 8) { + l += 128; + r += 128; + outbuf[i * 2] = (l << 24); + outbuf[i * 2 + 1] = (r << 24); + } else if (FLACMetadataBlock->bitsPerSample == 16) { + outbuf[i * 2] = l = (l << 16); + outbuf[i * 2 + 1] = (r << 16); + } else if (FLACMetadataBlock->bitsPerSample == 24) { + outbuf[i * 2] = (l << 8); + outbuf[i * 2 + 1] = (r << 8); + } else if (FLACMetadataBlock->bitsPerSample == 32) { + outbuf[i * 2] = l; + outbuf[i * 2 + 1] = r; + } + } + } + + m_offset += blockSize; + if (sbl > 0) { + m_flacCompressionRatio = (float)((m_flacValidSamples * 2) * FLACMetadataBlock->numChannels) / sbl; // valid samples are 16 bit + sbl = 0; + m_flacBitrate = FLACMetadataBlock->sampleRate * FLACMetadataBlock->bitsPerSample * FLACMetadataBlock->numChannels; + m_flacBitrate /= m_flacCompressionRatio; + // FLAC_LOG_INFO("s_flacBitrate {}, m_flacCompressionRatio {}, FLACMetadataBlock->sampleRate {} ", m_flacBitrate, m_flacCompressionRatio, FLACMetadataBlock->sampleRate); + } + + if (m_offset != m_numOfOutSamples) return GIVE_NEXT_LOOP; + + m_offset = 0; + } + + alignToByte(); + readUint(16, bytesLeft); + // m_flacCompressionRatio = (float)m_bytesDecoded / (float)s_numOfOutSamples * FLACMetadataBlock->numChannels * (16/8); + // FLAC_LOG_INFO("s_flacCompressionRatio {}", m_flacCompressionRatio); + m_flacStatus = DECODE_FRAME; + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeFrame(uint8_t* inbuf, int32_t* bytesLeft) { + if (specialIndexOf(inbuf, "OggS", *bytesLeft) == 0) { // async? => new sync is OggS => reset and decode (not page 0 or 1) + decoderReset(); + m_flacPageNr = 2; + return FLAC_OGG_SYNC_FOUND; + } + if (inbuf[0] != 0xFF || inbuf[1] != 0xF8) { + if (m_f_first_flac_frame && m_continued_page) { // these are the remains of a previous FLAC frame that was interrupted by OGG. We continue with the next segment, + // FLAC_LOG_WARN("need next segment"); + m_f_first_flac_frame = false; + *bytesLeft -= m_segmLength; + return FLAC_NONE; + } + FLAC_LOG_ERROR("Sync 0xFFF8 not found"); + return FLAC_ERR; + } + + m_rIndex = 0; + m_flac_bitBuffer = 0; + coefs.clear(); + + readUint(14 + 1, bytesLeft); // synccode + reserved bit + FLACFrameHeader->blockingStrategy = readUint(1, bytesLeft); + FLACFrameHeader->blockSizeCode = readUint(4, bytesLeft); + FLACFrameHeader->sampleRateCode = readUint(4, bytesLeft); + FLACFrameHeader->chanAsgn = readUint(4, bytesLeft); + FLACFrameHeader->sampleSizeCode = readUint(3, bytesLeft); + if (!FLACMetadataBlock->numChannels) { + if (FLACFrameHeader->chanAsgn == 0) FLACMetadataBlock->numChannels = 1; + if (FLACFrameHeader->chanAsgn == 1) FLACMetadataBlock->numChannels = 2; + if (FLACFrameHeader->chanAsgn > 7) FLACMetadataBlock->numChannels = 2; + } + if (FLACMetadataBlock->numChannels < 1) { + FLAC_LOG_ERROR("Flac unknown channel assignment, ch: {}", FLACMetadataBlock->numChannels); + return FLAC_STOP; + } + if (FLACMetadataBlock->numChannels > FLAC_MAX_CHANNELS) { + FLAC_LOG_ERROR("Flac unsupported channel count: {}, max: {}", FLACMetadataBlock->numChannels, FLAC_MAX_CHANNELS); + return FLAC_STOP; + } + if (FLACFrameHeader->chanAsgn <= 7) { + uint8_t frameChannels = FLACFrameHeader->chanAsgn + 1; + if (frameChannels != FLACMetadataBlock->numChannels) { + FLAC_LOG_ERROR("Flac channel assignment mismatch, assignment: {}, channels: {}", FLACFrameHeader->chanAsgn, FLACMetadataBlock->numChannels); + return FLAC_ERR; + } + } else if (FLACFrameHeader->chanAsgn <= 10) { + if (FLACMetadataBlock->numChannels != 2) { + FLAC_LOG_ERROR("Flac stereo channel assignment requires 2 channels, assignment: {}, channels: {}", FLACFrameHeader->chanAsgn, FLACMetadataBlock->numChannels); + return FLAC_ERR; + } + } else { + FLAC_LOG_ERROR("Flac reserved channel assignment, {}", FLACFrameHeader->chanAsgn); + return FLAC_ERR; + } + if (!FLACMetadataBlock->bitsPerSample) { + if (FLACFrameHeader->sampleSizeCode == 1) FLACMetadataBlock->bitsPerSample = 8; + if (FLACFrameHeader->sampleSizeCode == 2) FLACMetadataBlock->bitsPerSample = 12; + if (FLACFrameHeader->sampleSizeCode == 4) FLACMetadataBlock->bitsPerSample = 16; + if (FLACFrameHeader->sampleSizeCode == 5) FLACMetadataBlock->bitsPerSample = 20; + if (FLACFrameHeader->sampleSizeCode == 6) FLACMetadataBlock->bitsPerSample = 24; + } + if (FLACMetadataBlock->bitsPerSample == 12 || FLACMetadataBlock->bitsPerSample == 20) { + FLAC_LOG_ERROR("Flac, bits per sample must be 8, 16 or 24, is: {}", FLACMetadataBlock->bitsPerSample); + return FLAC_STOP; + } + if (FLACMetadataBlock->bitsPerSample < 8) { + FLAC_LOG_ERROR("Flac, bits per sample <8, bps: {}", FLACMetadataBlock->bitsPerSample); + return FLAC_STOP; + } + if (!FLACMetadataBlock->sampleRate) { + if (FLACFrameHeader->sampleRateCode == 1) FLACMetadataBlock->sampleRate = 88200; + if (FLACFrameHeader->sampleRateCode == 2) FLACMetadataBlock->sampleRate = 176400; + if (FLACFrameHeader->sampleRateCode == 3) FLACMetadataBlock->sampleRate = 192000; + if (FLACFrameHeader->sampleRateCode == 4) FLACMetadataBlock->sampleRate = 8000; + if (FLACFrameHeader->sampleRateCode == 5) FLACMetadataBlock->sampleRate = 16000; + if (FLACFrameHeader->sampleRateCode == 6) FLACMetadataBlock->sampleRate = 22050; + if (FLACFrameHeader->sampleRateCode == 7) FLACMetadataBlock->sampleRate = 24000; + if (FLACFrameHeader->sampleRateCode == 8) FLACMetadataBlock->sampleRate = 32000; + if (FLACFrameHeader->sampleRateCode == 9) FLACMetadataBlock->sampleRate = 44100; + if (FLACFrameHeader->sampleRateCode == 10) FLACMetadataBlock->sampleRate = 48000; + if (FLACFrameHeader->sampleRateCode == 11) FLACMetadataBlock->sampleRate = 96000; + } + readUint(1, bytesLeft); + uint32_t temp = (readUint(8, bytesLeft) << 24); + temp = ~temp; + uint32_t shift = 0x80000000; // Number of leading zeros + int8_t count = 0; + for (int32_t i = 0; i < 32; i++) { + if ((temp & shift) == 0) { + count++; + shift >>= 1; + } else + break; + } + count--; + for (int32_t i = 0; i < count; i++) readUint(8, bytesLeft); + uint32_t decodedBlockSize = 0; + if (FLACFrameHeader->blockSizeCode == 1) + decodedBlockSize = 192; + else if (2 <= FLACFrameHeader->blockSizeCode && FLACFrameHeader->blockSizeCode <= 5) + decodedBlockSize = 576U << (FLACFrameHeader->blockSizeCode - 2); + else if (FLACFrameHeader->blockSizeCode == 6) + decodedBlockSize = readUint(8, bytesLeft) + 1; + else if (FLACFrameHeader->blockSizeCode == 7) + decodedBlockSize = readUint(16, bytesLeft) + 1; + else if (8 <= FLACFrameHeader->blockSizeCode && FLACFrameHeader->blockSizeCode <= 15) + decodedBlockSize = 256U << (FLACFrameHeader->blockSizeCode - 8); + else { + FLAC_LOG_ERROR("Flac, reserved blocksize unsupported, block size code: {}", FLACFrameHeader->blockSizeCode); + return FLAC_ERR; + } + if (decodedBlockSize == 0 || decodedBlockSize > FLAC_MAX_BLOCKSIZE) { + FLAC_LOG_ERROR("Flac block size too large: {} samples, max: {}", decodedBlockSize, FLAC_MAX_BLOCKSIZE); + return FLAC_ERR; + } + m_numOfOutSamples = decodedBlockSize; + + if (FLACFrameHeader->sampleRateCode == 12) + readUint(8, bytesLeft); + else if (FLACFrameHeader->sampleRateCode == 13 || FLACFrameHeader->sampleRateCode == 14) { readUint(16, bytesLeft); } + readUint(8, bytesLeft); + + for (int32_t i = 0; i < FLAC_MAX_CHANNELS; i++) { + if (m_samplesBuffer[i].size() == m_numOfOutSamples) continue; + if (!m_samplesBuffer[i].calloc_array(m_numOfOutSamples, "m_samplesBuffer") || !m_samplesBuffer[i].valid()) { + FLAC_LOG_ERROR("not enough memory to allocate flacdecoder buffer {}, samples: {}", i, m_numOfOutSamples); + m_samplesBuffer[i].reset(); + m_valid = false; + return FLAC_ERR; + } + } + + m_flacStatus = DECODE_SUBFRAMES; + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t FlacDecoder::getOutputSamples() { + if (!FLACMetadataBlock->numChannels) return 0; + return m_flacValidSamples; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint64_t FlacDecoder::getTotoalSamplesInStream() { + if (!FLACMetadataBlock) return 0; + return FLACMetadataBlock->totalSamples; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t FlacDecoder::getBitsPerSample() { + if (!FLACMetadataBlock) return 0; + return FLACMetadataBlock->bitsPerSample; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t FlacDecoder::getChannels() { + if (!FLACMetadataBlock) return 0; + return FLACMetadataBlock->numChannels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t FlacDecoder::getSampleRate() { + if (!FLACMetadataBlock) return 0; + return FLACMetadataBlock->sampleRate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t FlacDecoder::getBitRate() { + return m_flacBitrate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t FlacDecoder::getAudioDataStart() { + return m_flacAudioDataStart; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t FlacDecoder::getAudioFileDuration() { + if (getSampleRate()) { // DIV0 + uint32_t afd = getTotoalSamplesInStream() / getSampleRate(); // AudioFileDuration + return afd; + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::val1() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::val2() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeSubframes(int32_t* bytesLeft) { + + if (FLACFrameHeader->chanAsgn <= 7) { + for (int32_t ch = 0; ch < FLACMetadataBlock->numChannels; ch++) decodeSubframe(FLACMetadataBlock->bitsPerSample, ch, bytesLeft); + } else if (8 <= FLACFrameHeader->chanAsgn && FLACFrameHeader->chanAsgn <= 10) { + if (FLACMetadataBlock->numChannels != 2) { + FLAC_LOG_ERROR("Flac stereo channel assignment requires 2 channels, assignment: {}, channels: {}", FLACFrameHeader->chanAsgn, FLACMetadataBlock->numChannels); + return FLAC_ERR; + } + decodeSubframe(FLACMetadataBlock->bitsPerSample + (FLACFrameHeader->chanAsgn == 9 ? 1 : 0), 0, bytesLeft); + decodeSubframe(FLACMetadataBlock->bitsPerSample + (FLACFrameHeader->chanAsgn == 9 ? 0 : 1), 1, bytesLeft); + + int64_t* ch0 = m_samplesBuffer[0].get(); + int64_t* ch1 = m_samplesBuffer[1].get(); + const int32_t n = m_numOfOutSamples; + + switch (FLACFrameHeader->chanAsgn) { // 8, 9 or 10 + case 8: // left + side → right + for (int32_t i = 0; i < n; i++) ch1[i] = ch0[i] - ch1[i]; + break; + + case 9: // right + side → left + for (int32_t i = 0; i < n; i++) ch0[i] += ch1[i]; + break; + + case 10: // mid + side → left/right + for (int32_t i = 0; i < n; i++) { + int32_t s = ch1[i]; + int32_t r = ch0[i] - (s >> 1); + ch1[i] = r; + ch0[i] = r + s; + } + break; + + default: break; + } + + } else { + FLAC_LOG_ERROR("Flac reserved channel assignment, {}", FLACFrameHeader->chanAsgn); + return FLAC_ERR; + } + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeSubframe(uint8_t sampleDepth, uint8_t ch, int32_t* bytesLeft) { + + int8_t ret = 0; + readUint(1, bytesLeft); // Zero bit padding, to prevent sync-fooling string of 1s + uint8_t type = readUint(6, bytesLeft); // Subframe type: 000000 : SUBFRAME_CONSTANT + // 000001 : SUBFRAME_VERBATIM + // 00001x : reserved + // 0001xx : reserved + // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved + // 01xxxx : reserved + // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1 + + int32_t shift = readUint(1, bytesLeft); // Wasted bits-per-sample' flag: + // 0 : no wasted bits-per-sample in source subblock, k=0 + // 1 : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 => 001 follows, k=7 => 0000001 follows. + if (shift == 1) { + while (readUint(1, bytesLeft) == 0) { shift++; } + } + sampleDepth -= shift; + + if (type == 0) { // Constant coding + int32_t s = readSignedInt(sampleDepth, bytesLeft); // SUBFRAME_CONSTANT + for (int32_t i = 0; i < m_numOfOutSamples; i++) { m_samplesBuffer[ch][i] = s; } + } else if (type == 1) { // Verbatim coding + for (int32_t i = 0; i < m_numOfOutSamples; i++) m_samplesBuffer[ch][i] = readSignedInt(sampleDepth, bytesLeft); // SUBFRAME_VERBATIM + } else if (8 <= type && type <= 12) { + ret = decodeFixedPredictionSubframe(type - 8, sampleDepth, ch, bytesLeft); // SUBFRAME_FIXED + if (ret) return ret; + } else if (32 <= type && type <= 63) { + ret = decodeLinearPredictiveCodingSubframe(type - 31, sampleDepth, ch, bytesLeft); // SUBFRAME_LPC + if (ret) return ret; + } else { + FLAC_LOG_ERROR("Flac unimplemented reserved subtype: {}", type); + return FLAC_ERR; + } + if (shift > 0) { + for (int32_t i = 0; i < m_numOfOutSamples; i++) { m_samplesBuffer[ch][i] <<= shift; } + } + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeFixedPredictionSubframe(uint8_t predOrder, uint8_t sampleDepth, uint8_t ch, int32_t* bytesLeft) { // SUBFRAME_FIXED + + uint8_t ret = 0; + for (uint8_t i = 0; i < predOrder; i++) m_samplesBuffer[ch][i] = readSignedInt(sampleDepth, bytesLeft); // Unencoded warm-up samples (n = frame's bits-per-sample * predictor order). + ret = decodeResiduals(predOrder, ch, bytesLeft); + if (ret) return ret; + coefs.clear(); + coefs.shrink_to_fit(); + if (predOrder == 0) coefs.resize(0); + if (predOrder == 1) coefs.push_back(1); // FIXED_PREDICTION_COEFFICIENTS + if (predOrder == 2) { + coefs.push_back(2); + coefs.push_back(-1); + } + if (predOrder == 3) { + coefs.push_back(3); + coefs.push_back(-3); + coefs.push_back(1); + } + if (predOrder == 4) { + coefs.push_back(4); + coefs.push_back(-6); + coefs.push_back(4); + coefs.push_back(-1); + } + if (predOrder > 4) { + FLAC_LOG_ERROR("Flac preorder too big: {}", predOrder); + return FLAC_ERR; + } // Error: preorder > 4" + restoreLinearPrediction(ch, 0); + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeLinearPredictiveCodingSubframe(int32_t lpcOrder, int32_t sampleDepth, uint8_t ch, int32_t* bytesLeft) { + int8_t ret = 0; + for (int32_t i = 0; i < lpcOrder; i++) { + m_samplesBuffer[ch][i] = readSignedInt(sampleDepth, bytesLeft); // Unencoded warm-up samples (n = frame's bits-per-sample * lpc order). + } + int32_t precision = readUint(4, bytesLeft) + 1; // (Quantized linear predictor coefficients' precision in bits)-1 (1111 = invalid). + int32_t shift = readSignedInt(5, bytesLeft); // Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement). + coefs.clear(); + for (uint8_t i = 0; i < lpcOrder; i++) { + coefs.push_back(readSignedInt(precision, bytesLeft)); // Unencoded predictor coefficients (n = qlp coeff precision * lpc order) (NOTE: the coefficients are signed two's-complement). + } + ret = decodeResiduals(lpcOrder, ch, bytesLeft); + if (ret) return ret; + restoreLinearPrediction(ch, shift); + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t FlacDecoder::decodeResiduals(uint8_t warmup, uint8_t ch, int32_t* bytesLeft) { + int32_t method = readUint(2, bytesLeft); + if (method >= 2) { + FLAC_LOG_ERROR("Flac reserved residual coding, method: {}", method); + return FLAC_ERR; + } + + const uint8_t paramBits = (method == 0 ? 4 : 5); + const int32_t escapeParam = (method == 0 ? 0xF : 0x1E); + const int32_t partitionOrder = readUint(4, bytesLeft); + const int32_t numPartitions = 1 << partitionOrder; + + if (m_numOfOutSamples % numPartitions != 0) { + FLAC_LOG_ERROR("Flac, wrong rice partition number"); + return FLAC_ERR; + } + + const int32_t partitionSize = m_numOfOutSamples / numPartitions; + int64_t* sampleBase = m_samplesBuffer[ch].get(); + + for (int32_t i = 0; i < numPartitions; i++) { + const int32_t start = i * partitionSize + ((i == 0) ? warmup : 0); + const int32_t end = (i + 1) * partitionSize; + int64_t* dst = sampleBase + start; + int64_t* dstEnd = sampleBase + end; + + const int32_t param = readUint(paramBits, bytesLeft); + + if (param < escapeParam) { + // Rice-coded partition + while (dst < dstEnd) { + if (m_f_bitReaderError) break; + + uint32_t val = 0; + // Inline Rice unary prefix + while (readUint(1, bytesLeft) == 0) { + val++; + if (m_f_bitReaderError) { break; } + } + + // Append remainder bits + val = (val << param) | readUint(param, bytesLeft); + + // Convert to signed + int64_t signedVal = (val >> 1) ^ -(val & 1); + *dst++ = (int32_t)signedVal; + } + } else { + // Escape partition (raw signed integers) + const int32_t numBits = readUint(5, bytesLeft); + while (dst < dstEnd) { + if (m_f_bitReaderError) break; + + uint32_t val = readUint(numBits, bytesLeft); + // Sign extend + int64_t signedVal = (int64_t)(val << (32 - numBits)) >> (32 - numBits); + *dst++ = (int32_t)signedVal; + } + } + } + + if (m_f_bitReaderError) { + FLAC_LOG_ERROR("Flac bitreader underflow"); + return FLAC_ERR; + } + return FLAC_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void FlacDecoder::restoreLinearPrediction(uint8_t ch, uint8_t shift) { + + for (int32_t i = coefs.size(); i < m_numOfOutSamples; i++) { + int64_t sum = 0; + for (int32_t j = 0; j < coefs.size(); j++) { sum += m_samplesBuffer[ch][i - 1 - j] * coefs[j]; } + m_samplesBuffer[ch][i] += (sum >> shift); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t FlacDecoder::specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact) { + if (!base || !str || baselen < 0) return -1; // seek for str in buffer or in header up to baselen, not nullterminated + + const size_t haystackLen = (size_t)baselen; + const size_t needleLen = strlen(str); + const size_t matchLen = needleLen + (exact ? 1U : 0U); // if exact == true search string must include "\0" at the end + + if (matchLen > haystackLen) return -1; + if (matchLen == 0) return 0; + + const size_t lastStart = haystackLen - matchLen; + for (size_t i = 0; i <= lastStart; i++) { + size_t j = 0; + while (j < matchLen && base[i + j] == (uint8_t)str[j]) j++; + if (j == matchLen) return (int32_t)i; + } + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* FlacDecoder::arg1() { + return nullptr; +} // virtual method +const char* FlacDecoder::arg2() { + return nullptr; +} // virtual method diff --git a/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.h b/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.h new file mode 100644 index 0000000..ebf48fe --- /dev/null +++ b/libraries/ESP32-audioI2S/src/flac_decoder/flac_decoder.h @@ -0,0 +1,258 @@ +/* + * flac_decoder.h + * + * Created on: Jul 03,2020 + * Updated on: Apr 25,2025 + * + * Author: wolle + * + * Restrictions: + * blocksize must not exceed 24576 bytes + * bits per sample must be 8, 16, 24 or 32 + * num Channels must be 1 or 2 + * + * + */ +#pragma once +#pragma GCC optimize("Ofast") + +#include "../Audio.h" + +#define ANSI_ESC_RESET "\033[0m" +#define ANSI_ESC_BLACK "\033[30m" +#define ANSI_ESC_RED "\033[31m" +#define ANSI_ESC_GREEN "\033[32m" +#define ANSI_ESC_YELLOW "\033[33m" +#define ANSI_ESC_BLUE "\033[34m" +#define ANSI_ESC_MAGENTA "\033[35m" +#define ANSI_ESC_CYAN "\033[36m" +#define ANSI_ESC_WHITE "\033[37m" + +class FlacDecoder : public Decoder { + + public: + FlacDecoder(Audio& audioRef) : Decoder(audioRef), audio(audioRef) {} + ~FlacDecoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; + const char* arg2() override; + virtual int32_t val1() override; + virtual int32_t val2() override; + + enum : int8_t { + FLAC_PARSE_OGG_DONE = 100, + FLAC_DECODE_FRAMES_LOOP = 100, + FLAC_OGG_SYNC_FOUND = +2, + GIVE_NEXT_LOOP = +1, + FLAC_NONE = 0, + FLAC_ERR = -1, + FLAC_STOP = -100, + }; + + private: + Audio& audio; +#define FLAC_MAX_CHANNELS 2 +#define FLAC_MAX_BLOCKSIZE 24576 // 24 * 1024 +#define FLAC_MAX_OUTBUFFSIZE 4096 * 2 + + enum : uint8_t { FLACDECODER_INIT, FLACDECODER_READ_IN, FLACDECODER_WRITE_OUT }; + enum : uint8_t { DECODE_FRAME, DECODE_SUBFRAMES, OUT_SAMPLES }; + + typedef struct FLACMetadataBlock_t { + // METADATA_BLOCK_STREAMINFO + uint16_t minblocksize; // The minimum block size (in samples) used in the stream. + //---------------------------------------------------------------------------------------- + // The maximum block size (in samples) used in the stream. + uint16_t maxblocksize; // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. + //---------------------------------------------------------------------------------------- + // The minimum frame size (in bytes) used in the stream. + uint32_t minframesize; // May be 0 to imply the value is not known. + //---------------------------------------------------------------------------------------- + // The maximum frame size (in bytes) used in the stream. + uint32_t maxframesize; // May be 0 to imply the value is not known. + //---------------------------------------------------------------------------------------- + // Sample rate in Hz. Though 20 bits are available, + // the maximum sample rate is limited by the structure of frame headers to 655350Hz. + uint32_t sampleRate; // Also, a value of 0 is invalid. + //---------------------------------------------------------------------------------------- + // Number of channels FLAC supports from 1 to 8 channels + uint8_t numChannels; // 000 : 1 channel .... 111 : 8 channels + //---------------------------------------------------------------------------------------- + // Sample size in bits: + // 000 : get from STREAMINFO metadata block + // 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 + uint8_t bitsPerSample; // 111 : reserved + //---------------------------------------------------------------------------------------- + // Total samples in stream. 'Samples' means inter-channel sample, + // i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number + uint64_t totalSamples; // of channels. A value of zero here means the number of total samples is unknown. + //---------------------------------------------------------------------------------------- + uint32_t audioDataLength; // is not the filelength, is only the length of the audio datablock in bytes + } FLACMetadataBlock_t; + + typedef struct FLACFrameHeader_t { + // 0 : fixed-blocksize stream; frame header encodes the frame number + uint8_t blockingStrategy; // 1 : variable-blocksize stream; frame header encodes the sample number + //---------------------------------------------------------------------------------------- + // Block size in inter-channel samples: + // 0000 : reserved + // 0001 : 192 samples + // 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608 + // 0110 : get 8 bit (blocksize-1) from end of header + // 0111 : get 16 bit (blocksize-1) from end of header + uint8_t blockSizeCode; // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768 + //---------------------------------------------------------------------------------------- + // 0000 : get from STREAMINFO metadata block + // 0001 : 88.2kHz + // 0010 : 176.4kHz + // 0011 : 192kHz + // 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 + uint8_t sampleRateCode; // 1111 : invalid, to prevent sync-fooling string of 1s + //---------------------------------------------------------------------------------------- + // Channel assignment + // 0000 1 channel: mono + // 0001 2 channels: left, right + // 0010 3 channels + // 0011 4 channels + // 0100 5 channels + // 0101 6 channels + // 0110 7 channels + // 0111 8 channels + // 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 + uint8_t chanAsgn; // 1011-1111 : reserved + //---------------------------------------------------------------------------------------- + // Sample size in bits: + // 000 : get from STREAMINFO metadata block + // 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 + uint8_t sampleSizeCode; // 111 : reserved + //---------------------------------------------------------------------------------------- + uint32_t totalSamples; // totalSamplesInStream + //---------------------------------------------------------------------------------------- + uint32_t bitrate; // bitrate + } FLACFrameHeader_t; + + const std::deque> FIXED_PREDICTION_COEFFICIENTS = { + {}, // {} + {1}, // {1} + {2, -1}, // {2, -1} + {3, -3, 1}, // {3, -3, 1} + {4, -6, 4, -1} // {4, -6, 4, -1} + }; + + // std::deque coefs; + + ps_ptr FLACFrameHeader; + ps_ptr FLACMetadataBlock; + + std::vector m_flacSegmTableVec; + std::vector coefs; + std::vector m_flacBlockPicItem; + + uint64_t m_flac_bitBuffer = 0; + uint32_t m_flacBitrate = 0; + uint32_t m_flacBlockPicLenUntilFrameEnd = 0; + uint32_t m_flacCurrentFilePos = 0; + uint32_t m_flacBlockPicPos = 0; + uint32_t m_flacBlockPicLen = 0; + uint32_t m_segmLength = 0; + uint32_t m_flacAudioDataStart = 0; + int32_t m_flacRemainBlockPicLen = 0; + uint32_t m_segmLenTmp = 0; + uint16_t m_numOfOutSamples = 0; + uint16_t m_flacValidSamples = 0; + uint16_t m_rIndex = 0; + uint16_t m_offset = 0; + uint8_t m_flacStatus = 0; + uint8_t* m_flacInptr; + float m_flacCompressionRatio = 0; + uint8_t m_flacBitBufferLen = 0; + bool m_f_flacParseOgg = false; + bool m_f_bitReaderError = false; + uint8_t m_flac_pageSegments = 0; + ps_ptr m_flacStreamTitle = {}; + ps_ptr m_flacVendorString = {}; + bool m_f_flacNewStreamtitle = false; + bool m_f_flacFirstCall = true; + bool m_f_oggWrapper = false; + bool m_f_lastMetaDataBlock = false; + bool m_f_flacNewMetadataBlockPicture = false; + bool m_valid = false; + bool m_continued_page = false; + bool m_f_first_flac_frame = false; + uint8_t m_flacPageNr = 0; + ps_ptr m_samplesBuffer[2]; + uint16_t m_maxBlocksize = FLAC_MAX_BLOCKSIZE; + int32_t m_nBytes = 0; + + boolean FLACFindMagicWord(unsigned char* buf, int32_t nBytes); + int32_t parseOGG(uint8_t* inbuf, int32_t* bytesLeft); + int32_t parseFlacFirstPacket(uint8_t* inbuf, int16_t nBytes); + int32_t parseMetaDataBlockHeader(uint8_t* inbuf, int16_t nBytes); + void setDefaults(); + void decoderReset(); + int8_t decodeNative(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf); + int8_t decodeFrame(uint8_t* inbuf, int32_t* bytesLeft); + uint64_t getTotoalSamplesInStream(); + uint32_t readUint(uint8_t nBits, int32_t* bytesLeft); + void alignToByte(); + int8_t decodeSubframes(int32_t* bytesLeft); + int8_t decodeSubframe(uint8_t sampleDepth, uint8_t ch, int32_t* bytesLeft); + int8_t decodeFixedPredictionSubframe(uint8_t predOrder, uint8_t sampleDepth, uint8_t ch, int32_t* bytesLeft); + int8_t decodeLinearPredictiveCodingSubframe(int32_t lpcOrder, int32_t sampleDepth, uint8_t ch, int32_t* bytesLeft); + int8_t decodeResiduals(uint8_t warmup, uint8_t ch, int32_t* bytesLeft); + void restoreLinearPrediction(uint8_t ch, uint8_t shift); + int32_t specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + + inline int32_t readSignedInt(int32_t nBits, int32_t* bytesLeft) { + int32_t temp = readUint(nBits, bytesLeft) << (32 - nBits); + temp = temp >> (32 - nBits); // The C++ compiler uses the sign bit to fill vacated bit positions + return temp; + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // Macro for comfortable calls +#define FLAC_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define FLAC_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define FLAC_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define FLAC_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define FLAC_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.cpp b/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.cpp new file mode 100644 index 0000000..6348161 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.cpp @@ -0,0 +1,3726 @@ +/* + * mp3_decoder.cpp + * libhelix_HMP3DECODER + * + * Created on: 26.10.2018 + * Updated on: 06.06.2026 + */ +#include "mp3_decoder.h" + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +bool MP3Decoder::init() { + m_MP3DecInfo.alloc("m_MP3DecInfo"); + m_FrameHeader.alloc("m_FrameHeader"); + m_SideInfo.alloc("m_SideInfo"); + m_ScaleFactorJS.alloc("m_ScaleFactorJS"); + m_HuffmanInfo.alloc("m_HuffmanInfo"); + m_DequantInfo.alloc("m_DequantInfo"); + m_IMDCTInfo.alloc("m_IMDCTInfo"); + m_SubbandInfo.alloc("m_SubbandInfo"); + m_MP3FrameInfo.alloc("m_MP3FrameInfo"); + m_out16.alloc_array(4608 * 2, "m_out16"); + + if (!m_MP3DecInfo.valid() || !m_FrameHeader.valid() || !m_SideInfo.valid() || !m_ScaleFactorJS.valid() || !m_HuffmanInfo.valid() || !m_DequantInfo.valid() || !m_IMDCTInfo.valid() || + !m_SubbandInfo.valid() || !m_MP3FrameInfo.valid() || !m_out16.valid()) { + reset(); + MP3_LOG_ERROR("not enough memory to allocate mp3decoder buffers"); + return false; + } + clear(); + return true; +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::reset() { + m_MP3DecInfo.reset(); + m_FrameHeader.reset(); + m_SideInfo.reset(); + m_ScaleFactorJS.reset(); + m_HuffmanInfo.reset(); + m_DequantInfo.reset(); + m_IMDCTInfo.reset(); + m_SubbandInfo.reset(); + m_MP3FrameInfo.reset(); + m_mpeg_version_str.reset(); + m_out16.reset(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::clear() { + /* important to do this - DSP primitives assume a bunch of state variables are 0 on first use */ + m_MP3DecInfo.clear(); + m_FrameHeader.clear(); + m_SideInfo.clear(); + m_ScaleFactorJS.clear(); + m_HuffmanInfo.clear(); + m_DequantInfo.clear(); + m_IMDCTInfo.clear(); + m_SubbandInfo.clear(); + m_MP3FrameInfo.clear(); + m_mpeg_version_str.clear(); + m_out16.clear(); + memset(&m_SFBandTable, 0, sizeof(SFBandTable_t)); // Clear SFBandTable + memset(&m_ScaleFactorInfoSub, 0, sizeof(ScaleFactorInfoSub_t) * (MAX_NGRAN * MAX_NCHAN)); // Clear ScaleFactorInfo + memset(&m_CriticalBandInfo, 0, sizeof(CriticalBandInfo_t) * MAX_NCHAN); // Clear CriticalBandInfo + memset(&m_SideInfoSub, 0, sizeof(SideInfoSub_t) * (MAX_NGRAN * MAX_NCHAN)); // Clear SideInfoSub + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool MP3Decoder::isValid() { + if (!m_MP3DecInfo.valid() || !m_FrameHeader.valid() || !m_SideInfo.valid() || !m_ScaleFactorJS.valid() || !m_HuffmanInfo.valid() || !m_DequantInfo.valid() || !m_IMDCTInfo.valid() || + !m_SubbandInfo.valid() || !m_MP3FrameInfo.valid() || !m_out16.valid()) { + return false; + } + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* B I T S T R E A M */ +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::SetBitstreamPointer(BitStreamInfo_t* bsi, int32_t nBytes, uint8_t* buf) { + /* init bitstream */ + bsi->bytePtr = buf; + bsi->iCache = 0; /* 4-byte uint32_t */ + bsi->cachedBits = 0; /* i.e. zero bits in cache */ + bsi->nBytes = nBytes; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::RefillBitstreamCache(BitStreamInfo_t* bsi) { + int32_t nBytes = bsi->nBytes; + /* optimize for common case, independent of machine endian-ness */ + if (nBytes >= 4) { + bsi->iCache = (*bsi->bytePtr++) << 24; + bsi->iCache |= (*bsi->bytePtr++) << 16; + bsi->iCache |= (*bsi->bytePtr++) << 8; + bsi->iCache |= (*bsi->bytePtr++); + bsi->cachedBits = 32; + bsi->nBytes -= 4; + } else { + bsi->iCache = 0; + while (nBytes--) { + bsi->iCache |= (*bsi->bytePtr++); + bsi->iCache <<= 8; + } + bsi->iCache <<= ((3 - bsi->nBytes) * 8); + bsi->cachedBits = 8 * bsi->nBytes; + bsi->nBytes = 0; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::GetBits(BitStreamInfo_t* bsi, int32_t nBits) { + uint32_t data, lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid MP3Decoder:: unpredictable results like >> by negative amount */ + data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + bsi->iCache <<= nBits; /* left-justify cache */ + bsi->cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ + if (bsi->cachedBits < 0) { /* if we cross anint32_t boundary, refill the cache */ + lowBits = -bsi->cachedBits; + RefillBitstreamCache(bsi); + data |= bsi->iCache >> (32 - lowBits); /* get the low-order bits */ + bsi->cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ + bsi->iCache <<= lowBits; /* left-justify cache */ + } + return data; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::CalcBitsUsed(BitStreamInfo_t* bsi, uint8_t* startBuf, int32_t startOffset) { + int32_t bitsUsed; + bitsUsed = (bsi->bytePtr - startBuf) * 8; + bitsUsed -= bsi->cachedBits; + bitsUsed -= startOffset; + return bitsUsed; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::CheckPadBit() { + return (m_FrameHeader->paddingBit ? 1 : 0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::UnpackFrameHeader(uint8_t* buf) { + int32_t verIdx; + /* validate pointers and sync word */ + if ((buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL) { return -1; } + /* read header fields - use bitmasks instead of GetBits() for speed, since format never varies */ + verIdx = (buf[1] >> 3) & 0x03; + m_MPEGVersion = (MPEGVersion_t)(verIdx == 0 ? MPEG25 : ((verIdx & 0x01) ? MPEG1 : MPEG2)); + m_FrameHeader->layer = 4 - ((buf[1] >> 1) & 0x03); /* easy mapping of index to layer number, 4 = error */ + m_FrameHeader->crc = 1 - ((buf[1] >> 0) & 0x01); + m_FrameHeader->brIdx = (buf[2] >> 4) & 0x0f; + m_FrameHeader->srIdx = (buf[2] >> 2) & 0x03; + m_FrameHeader->paddingBit = (buf[2] >> 1) & 0x01; + m_FrameHeader->privateBit = (buf[2] >> 0) & 0x01; + m_sMode = (StereoMode_t)((buf[3] >> 6) & 0x03); /* maps to correct enum (see definition) */ + m_FrameHeader->modeExt = (buf[3] >> 4) & 0x03; + m_FrameHeader->copyFlag = (buf[3] >> 3) & 0x01; + m_FrameHeader->origFlag = (buf[3] >> 2) & 0x01; + m_FrameHeader->emphasis = (buf[3] >> 0) & 0x03; + /* check parameters to avoid MP3Decoder:: indexing tables with bad values */ + if (m_FrameHeader->srIdx == 3 || m_FrameHeader->layer == 4 || m_FrameHeader->brIdx == 15) { return -1; } + /* for readability (we reference sfBandTable many times in decoder) */ + m_SFBandTable = sfBandTable[m_MPEGVersion][m_FrameHeader->srIdx]; + if (m_sMode != Joint) /* just to be safe (dequant, stproc check fh->modeExt) */ + m_FrameHeader->modeExt = 0; + /* init user-accessible data */ + m_MP3DecInfo->nChans = (m_sMode == Mono ? 1 : 2); + m_MP3DecInfo->samprate = samplerateTab[m_MPEGVersion][m_FrameHeader->srIdx]; + m_MP3DecInfo->nGrans = (m_MPEGVersion == MPEG1 ? NGRANS_MPEG1 : NGRANS_MPEG2); + m_MP3DecInfo->nGranSamps = ((int32_t)samplesPerFrameTab[m_MPEGVersion][m_FrameHeader->layer - 1]) / m_MP3DecInfo->nGrans; + m_MP3DecInfo->layer = m_FrameHeader->layer; + + /* get bitrate and nSlots from table, unless brIdx == 0 (free mode) in which case caller must figure it out himself + * question - do we want to overwrite mp3DecInfo->bitrate with 0 each time if it's free mode, and + * copy the pre-calculated actual free bitrate into it in mp3dec.c (according to the spec, + * this shouldn't be necessary, since it should be either all frames free or none free) + */ + if (m_FrameHeader->brIdx) { + m_MP3DecInfo->bitrate = ((int32_t)bitrateTab[m_MPEGVersion][m_FrameHeader->layer - 1][m_FrameHeader->brIdx]) * 1000; + /* nSlots = total frame bytes (from table) - sideInfo bytes - header - CRC (if present) + pad (if present) */ + m_MP3DecInfo->nSlots = (int32_t)slotTab[m_MPEGVersion][m_FrameHeader->srIdx][m_FrameHeader->brIdx] - (int32_t)sideBytesTab[m_MPEGVersion][(m_sMode == Mono ? 0 : 1)] - 4 - + (m_FrameHeader->crc ? 2 : 0) + (m_FrameHeader->paddingBit ? 1 : 0); + } + /* load crc word, if enabled, and return length of frame header (in bytes) */ + if (m_FrameHeader->crc) { + m_FrameHeader->CRCWord = ((int32_t)buf[4] << 8 | (int32_t)buf[5] << 0); + return 6; + } else { + m_FrameHeader->CRCWord = 0; + return 4; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::UnpackSideInfo(uint8_t* buf) { + int32_t gr, ch, bd, nBytes; + BitStreamInfo_t bitStreamInfo, *bsi; + + SideInfoSub_t* sis; + /* validate pointers and sync word */ + bsi = &bitStreamInfo; + if (m_MPEGVersion == MPEG1) { + /* MPEG 1 */ + nBytes = (m_sMode == Mono ? SIBYTES_MPEG1_MONO : SIBYTES_MPEG1_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + m_SideInfo->mainDataBegin = GetBits(bsi, 9); + m_SideInfo->privateBits = GetBits(bsi, (m_sMode == Mono ? 5 : 3)); + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) + for (bd = 0; bd < MAX_SCFBD; bd++) m_SideInfo->scfsi[ch][bd] = GetBits(bsi, 1); + } else { + /* MPEG 2, MPEG 2.5 */ + nBytes = (m_sMode == Mono ? SIBYTES_MPEG2_MONO : SIBYTES_MPEG2_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + m_SideInfo->mainDataBegin = GetBits(bsi, 8); + m_SideInfo->privateBits = GetBits(bsi, (m_sMode == Mono ? 1 : 2)); + } + for (gr = 0; gr < m_MP3DecInfo->nGrans; gr++) { + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + sis = &m_SideInfoSub[gr][ch]; /* side info subblock for this granule, channel */ + sis->part23Length = GetBits(bsi, 12); + sis->nBigvals = GetBits(bsi, 9); + sis->globalGain = GetBits(bsi, 8); + sis->sfCompress = GetBits(bsi, (m_MPEGVersion == MPEG1 ? 4 : 9)); + sis->winSwitchFlag = GetBits(bsi, 1); + if (sis->winSwitchFlag) { + /* this is a start, stop, short, or mixed block */ + sis->blockType = GetBits(bsi, 2); /* 0 = normal, 1 = start, 2 = short, 3 = stop */ + sis->mixedBlock = GetBits(bsi, 1); /* 0 = not mixed, 1 = mixed */ + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = 0; /* unused */ + sis->subBlockGain[0] = GetBits(bsi, 3); + sis->subBlockGain[1] = GetBits(bsi, 3); + sis->subBlockGain[2] = GetBits(bsi, 3); + if (sis->blockType == 0) { + /* this should not be allowed, according to spec */ + sis->nBigvals = 0; + sis->part23Length = 0; + sis->sfCompress = 0; + } else if (sis->blockType == 2 && sis->mixedBlock == 0) { + /* short block, not mixed */ + sis->region0Count = 8; + } else { + /* start, stop, or short-mixed */ + sis->region0Count = 7; + } + sis->region1Count = 20 - sis->region0Count; + } else { + /* this is a normal block */ + sis->blockType = 0; + sis->mixedBlock = 0; + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = GetBits(bsi, 5); + sis->region0Count = GetBits(bsi, 4); + sis->region1Count = GetBits(bsi, 3); + } + sis->preFlag = (m_MPEGVersion == MPEG1 ? GetBits(bsi, 1) : 0); + sis->sfactScale = GetBits(bsi, 1); + sis->count1TableSelect = GetBits(bsi, 1); + } + } + m_MP3DecInfo->mainDataBegin = m_SideInfo->mainDataBegin; /* needed by main decode loop */ + assert(nBytes == CalcBitsUsed(bsi, buf, 0) >> 3); + return nBytes; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: UnpackSFMPEG1 + * + * Description: unpack MPEG 1 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * vector of scfsi flags from side info, length = 4 (MAX_SCFBD) + * index of current granule + * ScaleFactorInfoSub from granule 0 (for granule 1, if scfsi[i] is set, + * then we just replicate the scale factors from granule 0 in the + * i'th set of scalefactor bands) + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * + * Return: none + * + * Notes: set order of short blocks to s[band][window] instead of s[window][band] + * so that we index through consectutive memory locations when unpacking + * (make sure dequantizer follows same convention) + * Illegal Intensity Position = 7 (always) for MPEG1 scale factors + */ +void MP3Decoder::UnpackSFMPEG1(BitStreamInfo_t* bsi, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, int32_t* scfsi, int32_t gr, ScaleFactorInfoSub_t* sfisGr0) { + int32_t sfb; + int32_t slen0, slen1; + /* these can be 0, so make sure GetBits(bsi, 0) returns 0 (no >> 32 or anything) */ + slen0 = (int32_t)m_SFLenTab[sis->sfCompress][0]; + slen1 = (int32_t)m_SFLenTab[sis->sfCompress][1]; + if (sis->blockType == 2) { + /* short block, type 2 (implies winSwitchFlag == 1) */ + if (sis->mixedBlock) { + /* do long block portion */ + for (sfb = 0; sfb < 8; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + sfb = 3; + } else { + /* all short blocks */ + sfb = 0; + } + for (; sfb < 6; sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen0); + sfis->s[sfb][1] = (char)GetBits(bsi, slen0); + sfis->s[sfb][2] = (char)GetBits(bsi, slen0); + } + for (; sfb < 12; sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen1); + sfis->s[sfb][1] = (char)GetBits(bsi, slen1); + sfis->s[sfb][2] = (char)GetBits(bsi, slen1); + } + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } else { + /* long blocks, type 0, 1, or 3 */ + if (gr == 0) { + /* first granule */ + for (sfb = 0; sfb < 11; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + for (sfb = 11; sfb < 21; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + return; + } else { + /* second granule + * scfsi: 0 = different scalefactors for each granule, + * 1 = copy sf's from granule 0 into granule 1 + * for block type == 2, scfsi is always 0 + */ + sfb = 0; + if (scfsi[0]) + for (; sfb < 6; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else + for (; sfb < 6; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if (scfsi[1]) + for (; sfb < 11; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else + for (; sfb < 11; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if (scfsi[2]) + for (; sfb < 16; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else + for (; sfb < 16; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + if (scfsi[3]) + for (; sfb < 21; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else + for (; sfb < 21; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + } + /* last sf band not transmitted */ + sfis->l[21] = 0; + sfis->l[22] = 0; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: UnpackSFMPEG2 + * + * Description: unpack MPEG 2 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * index of current granule and channel + * ScaleFactorInfoSub from this granule + * modeExt field from frame header, to tell whether intensity stereo is on + * ScaleFactorJS struct for storing IIP info used in Dequant() + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * updated intensityScale and preFlag flags + * + * Return: none + * + * Notes: Illegal Intensity Position = (2^slen) - 1 for MPEG2 scale factors + */ +void MP3Decoder::UnpackSFMPEG2(BitStreamInfo_t* bsi, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, int32_t gr, int32_t ch, int32_t modeExt, ScaleFactorJS_t* sfjs) { + + int32_t i, sfb, sfcIdx, btIdx, nrIdx; // iipTest; + int32_t slen[4], nr[4]; + int32_t sfCompress, preFlag, intensityScale; + (void)gr; + sfCompress = sis->sfCompress; + preFlag = 0; + intensityScale = 0; + + /* stereo mode bits (1 = on): bit 1 = mid-side on/off, bit 0 = intensity on/off */ + if (!((modeExt & 0x01) && (ch == 1))) { + /* in other words: if ((modeExt & 0x01) == 0 || ch == 0) */ + if (sfCompress < 400) { + /* max slen = floor[(399/16) / 5] = 4 */ + slen[0] = (sfCompress >> 4) / 5; + slen[1] = (sfCompress >> 4) % 5; + slen[2] = (sfCompress & 0x0f) >> 2; + slen[3] = (sfCompress & 0x03); + sfcIdx = 0; + } else if (sfCompress < 500) { + /* max slen = floor[(99/4) / 5] = 4 */ + sfCompress -= 400; + slen[0] = (sfCompress >> 2) / 5; + slen[1] = (sfCompress >> 2) % 5; + slen[2] = (sfCompress & 0x03); + slen[3] = 0; + sfcIdx = 1; + } else { + /* max slen = floor[11/3] = 3 (sfCompress = 9 bits in MPEG2) */ + sfCompress -= 500; + slen[0] = sfCompress / 3; + slen[1] = sfCompress % 3; + slen[2] = slen[3] = 0; + if (sis->mixedBlock) { + /* adjust for long/short mix logic (see comment above in NRTab[] definition) */ + slen[2] = slen[1]; + slen[1] = slen[0]; + } + preFlag = 1; + sfcIdx = 2; + } + } else { + /* intensity stereo ch = 1 (right) */ + intensityScale = sfCompress & 0x01; + sfCompress >>= 1; + if (sfCompress < 180) { + /* max slen = floor[35/6] = 5 (from mod 36) */ + slen[0] = (sfCompress / 36); + slen[1] = (sfCompress % 36) / 6; + slen[2] = (sfCompress % 36) % 6; + slen[3] = 0; + sfcIdx = 3; + } else if (sfCompress < 244) { + /* max slen = floor[63/16] = 3 */ + sfCompress -= 180; + slen[0] = (sfCompress & 0x3f) >> 4; + slen[1] = (sfCompress & 0x0f) >> 2; + slen[2] = (sfCompress & 0x03); + slen[3] = 0; + sfcIdx = 4; + } else { + /* max slen = floor[11/3] = 3 (max sfCompress >> 1 = 511/2 = 255) */ + sfCompress -= 244; + slen[0] = (sfCompress / 3); + slen[1] = (sfCompress % 3); + slen[2] = slen[3] = 0; + sfcIdx = 5; + } + } + /* set index based on block type: (0,1,3) --> 0, (2 non-mixed) --> 1, (2 mixed) ---> 2 */ + btIdx = 0; + if (sis->blockType == 2) btIdx = (sis->mixedBlock ? 2 : 1); + for (i = 0; i < 4; i++) nr[i] = (int32_t)NRTab[sfcIdx][btIdx][i]; + + /* save intensity stereo scale factor info */ + if ((modeExt & 0x01) && (ch == 1)) { + for (i = 0; i < 4; i++) { + sfjs->slen[i] = slen[i]; + sfjs->nr[i] = nr[i]; + } + sfjs->intensityScale = intensityScale; + } + sis->preFlag = preFlag; + + /* short blocks */ + if (sis->blockType == 2) { + if (sis->mixedBlock) { + /* do long block portion */ + // iipTest = (1 << slen[0]) - 1; + for (sfb = 0; sfb < 6; sfb++) { sfis->l[sfb] = (char)GetBits(bsi, slen[0]); } + sfb = 3; /* start sfb for short */ + nrIdx = 1; + } else { + /* all short blocks, so start nr, sfb at 0 */ + sfb = 0; + nrIdx = 0; + } + + /* remaining short blocks, sfb just keeps incrementing */ + for (; nrIdx <= 3; nrIdx++) { + // iipTest = (1 << slen[nrIdx]) - 1; + for (i = 0; i < nr[nrIdx]; i++, sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][1] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][2] = (char)GetBits(bsi, slen[nrIdx]); + } + } + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } else { + /* long blocks */ + sfb = 0; + for (nrIdx = 0; nrIdx <= 3; nrIdx++) { + // iipTest = (1 << slen[nrIdx]) - 1; + for (i = 0; i < nr[nrIdx]; i++, sfb++) { sfis->l[sfb] = (char)GetBits(bsi, slen[nrIdx]); } + } + /* last sf band not transmitted */ + sfis->l[21] = sfis->l[22] = 0; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: UnpackScaleFactors + * + * Description: parse the fields of the MP3 scale factor data section + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader() and UnpackSideInfo() + * buffer pointing to the MP3 scale factor data + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits available in data buffer + * index of current granule and channel + * + * Outputs: updated platform-specific ScaleFactorInfo struct + * updated bitOffset + * + * Return: length (in bytes) of scale factor data, -1 if null input pointers + */ +int32_t MP3Decoder::UnpackScaleFactors(uint8_t* buf, int32_t* bitOffset, int32_t bitsAvail, int32_t gr, int32_t ch) { + int32_t bitsUsed; + uint8_t* startBuf; + BitStreamInfo_t bitStreamInfo, *bsi; + + /* init GetBits reader */ + startBuf = buf; + bsi = &bitStreamInfo; + SetBitstreamPointer(bsi, (bitsAvail + *bitOffset + 7) / 8, buf); + if (*bitOffset) GetBits(bsi, *bitOffset); + + if (m_MPEGVersion == MPEG1) + UnpackSFMPEG1(bsi, &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], m_SideInfo->scfsi[ch], gr, &m_ScaleFactorInfoSub[0][ch]); + else + UnpackSFMPEG2(bsi, &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], gr, ch, m_FrameHeader->modeExt, m_ScaleFactorJS.get()); + + m_MP3DecInfo->part23Length[gr][ch] = m_SideInfoSub[gr][ch].part23Length; + + bitsUsed = CalcBitsUsed(bsi, buf, *bitOffset); + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + + return (buf - startBuf); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* M P 3 D E C */ +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3FindSyncWord + * + * Description: locate the next byte-alinged sync word in the raw mp3 stream + * + * Inputs: buffer to search for sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to first sync word (bytes from start of buf) + * -1 if sync not found after searching nBytes + */ +int32_t MP3Decoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + + // Auxiliary function for extracting bits, byte 'value', 'start_bit' is that bit from the left (0-7), 'num_bits' is the number of bits + // auto extract_bits = [&](uint8_t byte, uint8_t start_bit, uint8_t num_bits) { + // return (byte >> (8 - start_bit - num_bits)) & ((1 << num_bits) - 1); + // }; + + typedef struct { + uint8_t mpeg_version = 0; // 0=MPEG2.5, 1=reserved, 2=MPEG2, 3=MPEG1 + uint8_t layer = 0; // 0=reserved, 1=Layer III, 2=Layer II, 3=Layer I + bool crc_protected = 0; + uint8_t bitrate_idx = 0; + uint8_t sample_rate_idx = 0; + bool padding = 0; + uint8_t channel_mode = 0; + uint32_t frame_length = 0; // cytes + uint16_t sample_rate_hz = 0; // the actual sampling rate in Hz + uint16_t bitrate_kbps = 0; // the actual bit rate in Kbps + uint16_t samples_per_frame = 0; + } Mp3FrameHeader_sync_t; + + // SamplingFrequenz-Lookup tables(Beispiel für MPEG1, MPEG2, MPEG2.5) + const uint16_t sampling_rates[3][4] = { + {44100, 48000, 32000, 0}, // MPEG1 + {22050, 24000, 16000, 0}, // MPEG2 + {11025, 12000, 8000, 0} // MPEG2.5 + }; + + typedef enum { /* map to 0,1,2 to make table indexing easier */ + MPEG1 = 0, + MPEG2 = 1, + MPEG25 = 2 + } MPEGVersion_t; + + const uint16_t mpeg1_layer1_bitrates[16] = {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}; + + const uint16_t mpeg1_layer3_bitrates[16] = { + // Bitraten-Lookup tables (example for MPEG1 Layer III) + 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 // Attention: These tables must be complete and correct! + }; + // Define bitrate tables for MPEG1 Layer II and MPEG2/2.5 Layer II + // These tables are examples and need to be complete based on the MPEG standard + const uint16_t mpeg1_layer2_bitrates[] = {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}; + const uint16_t mpeg2_layer2_bitrates[] = {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}; + const uint16_t mpeg2_layer3_bitrates[] = { + 0, // "Free format" oder ungültig + 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, + 0 // Ungültig + }; + + // Funktion zum Parsen des Headers und Überprüfen der Gültigkeit + auto parseMp3Header = [&](const uint8_t* header_data, Mp3FrameHeader_sync_t* header_info) { + // Byte 0: Syncword H (bereits geprüft) + // Byte 1: Syncword L, MPEG Version, Layer + // Byte 2: Bitrate, Sampling Frequency, Padding, Private + // Byte 3: Channel Mode, Mode Extension, Copyright, Original, Emphasis + + // Syncword has already been checked, here we start with the other bits + header_info->mpeg_version = (header_data[1] >> 3) & 0b11; // Bits 12, 13 (A, B) + header_info->layer = (header_data[1] >> 1) & 0b11; // Bits 14, 15 (C, D) + header_info->crc_protected = !((header_data[1] >> 0) & 0b1); // Bit 16 (Schutzbit) + + header_info->bitrate_idx = (header_data[2] >> 4) & 0b1111; // Bits 17-20 + header_info->sample_rate_idx = (header_data[2] >> 2) & 0b11; // Bits 21-22 + header_info->padding = (header_data[2] >> 1) & 0b1; // Bit 23 + + header_info->channel_mode = (header_data[3] >> 6) & 0b11; // Bits 24-25 + + // Gültigkeitsprüfungen + if (header_info->mpeg_version == 1) { // Reserved + MP3_LOG_DEBUG("Reserved MPEG version"); + return false; + } + if (header_info->layer == 0) { // Reserved + MP3_LOG_DEBUG("Reserved Layer"); + return false; + } + // Modified part: Support for Layer II and Layer III + if (header_info->layer != 1 && header_info->layer != 2 && header_info->layer != 3) { // Allow Layer I (3) Layer II (2) and Layer III (1) + // MP3_LOG_WARN(""); + // for (int i = 0; i < 10; i++) MP3_LOG_WARN("0x{:02X} ", header_data[i]); + MP3_LOG_ERROR("Not Layer I or II or III"); + return false; + } + + if (header_info->bitrate_idx == 0 || header_info->bitrate_idx == 15) { // Invalid bit rate + MP3_LOG_DEBUG("Invalid bitrate index"); + return false; + } + if (header_info->sample_rate_idx == 3) { // Invalid sampling frequency + MP3_LOG_DEBUG("Invalid sampling rate index"); + return false; + } + + // Determine the actual bit rate and sampling frequency + uint16_t bitrate_kbps = 0; + uint16_t sample_rate_hz = 0; + + // Mapping from MPEG version to sampling rate table + uint8_t sr_table_idx = 0; + if (header_info->mpeg_version == 3) + sr_table_idx = 0; // MPEG 1 (0b11) + else if (header_info->mpeg_version == 2) + sr_table_idx = 1; // MPEG 2 (0b10) + else + sr_table_idx = 2; // MPEG 2.5 (da mpeg_version == 0) - Although Google TTS is likely MPEG 2.0 + + sample_rate_hz = sampling_rates[sr_table_idx][header_info->sample_rate_idx]; + + // Bitraten-Mapping für verschiedene MPEG-Versionen und Layer + if (header_info->mpeg_version == 3) { // MPEG 1 + if (header_info->layer == 1) { // Layer III + bitrate_kbps = mpeg1_layer3_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 2) { // Layer II + bitrate_kbps = mpeg1_layer2_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 3) { // Layer I + bitrate_kbps = mpeg1_layer1_bitrates[header_info->bitrate_idx]; + } + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2 or MPEG 2.5 + if (header_info->layer == 1) { // Layer III + bitrate_kbps = mpeg2_layer3_bitrates[header_info->bitrate_idx]; + } else if (header_info->layer == 2) { // Layer II + bitrate_kbps = mpeg2_layer2_bitrates[header_info->bitrate_idx]; + } + // If you also want to support MPEG 2/2.5 Layer I, you'd add another else if here + // e.g., else if (header_info->layer == 3) { bitrate_kbps = mpeg2_layer1_bitrates[header_info->bitrate_idx]; } + } + + if (bitrate_kbps == 0 || sample_rate_hz == 0) { + MP3_LOG_DEBUG("Could not determine valid bitrate or sample rate"); + return false; + } + + // Calculate frame length based on layer + // FrameSize = (1152 * BitRate / SampleRate) + Padding (for Layer III) + // FrameSize = (144 * BitRate / SampleRate) + Padding (for Layer I) + // FrameSize = (576 * BitRate / SampleRate) + Padding (for Layer II, MPEG 2.0/2.5) + // Note: For MPEG 1 Layer II, it's (1152 * BitRate / SampleRate) + Padding + // Need to be careful with the constant depending on MPEG version and layer + if (header_info->layer == 1) { // Layer III + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; // Assuming MPEG1 Layer III + if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG2/2.5 Layer III + header_info->frame_length = (72 * bitrate_kbps * 1000) / sample_rate_hz; // Correct constant for MPEG2/2.5 Layer III + } + } else if (header_info->layer == 2) { // Layer II + if (header_info->mpeg_version == 3) { // MPEG 1 Layer II + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2/2.5 Layer II + header_info->frame_length = (144 * bitrate_kbps * 1000) / sample_rate_hz; + } + } else if (header_info->layer == 3) { // Layer I + // For Layer I, the formula is (Bitrate * 12 / SampleRate) + Padding (in Bytes) + // Note: Bitrate is in kbps, so multiply by 1000 to get bps + if (header_info->mpeg_version == 3) { // MPEG 1 Layer I + header_info->frame_length = (bitrate_kbps * 1000 / 8 * 12) / sample_rate_hz; // Correct + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG 2/2.5 Layer I (if supported) + // You'd add the specific calculation for MPEG2/2.5 Layer I here + // For MPEG 2/2.5 Layer I, samples per frame is 576, so the constant is 6 + header_info->frame_length = (bitrate_kbps * 1000 / 8 * 6) / sample_rate_hz; // Hypothetical, verify constant + } + } + + if (header_info->padding) { + header_info->frame_length += 1; // Füge 1 Byte für Padding hinzu + } + + if (header_info->frame_length == 0) { + MP3_LOG_DEBUG("Calculated frame length is zero"); + return false; + } + header_info->sample_rate_hz = sample_rate_hz; + header_info->bitrate_kbps = bitrate_kbps; + + // Determine samples_per_frame based on the version and layer + if (header_info->mpeg_version == 3) { // MPEG-1 + if (header_info->layer == 1 || header_info->layer == 2) { // Layer III oder Layer II + header_info->samples_per_frame = 1152; + } else if (header_info->layer == 3) { // Layer I + header_info->samples_per_frame = 384; + } else { + header_info->samples_per_frame = 0; // Should be caught by previous checks + return false; + } + } else if (header_info->mpeg_version == 2 || header_info->mpeg_version == 0) { // MPEG-2 oder MPEG-2.5 + if (header_info->layer == 1) { // Layer III + header_info->samples_per_frame = 576; + } else if (header_info->layer == 2) { // Layer II + header_info->samples_per_frame = 1152; + } else if (header_info->layer == 3) { // Layer I + header_info->samples_per_frame = 576; // Correct for MPEG-2/2.5 Layer I + } else { + header_info->samples_per_frame = 0; // Should be caught by previous checks + return false; + } + } else { // header_info->mpeg_version == 1 (Reserved) + header_info->samples_per_frame = 0; + return false; + } + return true; // Header ist gültig + }; + + const uint8_t mp3FHsize = 4; // frame header size + + // Lambda for the fast syncword search + auto findSync = [&](uint8_t* search_buf, uint16_t offset, uint16_t len) { + for (int32_t i = 0; i < len - 1; i++) { + // Prüfe auf die 11 oder 12 Sync-Bits + if ((search_buf[i + offset] == SYNCWORDH) && ((search_buf[i + offset + 1] & SYNCWORDL) == SYNCWORDL)) { return i; } + } + return (int32_t)-1; + }; + + int32_t current_pos = 0; + + while (nBytes >= mp3FHsize) { // Make sure that there are enough bytes for a header + int32_t sync_offset = findSync(buf, current_pos, nBytes); + + if (sync_offset == -1) { + MP3_LOG_DEBUG("No syncword found in remaining buffer"); + return -1; // No more syncword found + } + + current_pos += sync_offset; + nBytes -= sync_offset; + + if (nBytes < mp3FHsize) { + MP3_LOG_DEBUG("Not enough bytes for a full header after syncword"); + return -1; // Not enough data for a full header + } + + Mp3FrameHeader_sync_t header; + if (parseMp3Header(&buf[current_pos], &header)) { + // This is where the crucial step comes: Check the next frame + if (current_pos + header.frame_length + mp3FHsize <= current_pos + nBytes) { + // Check whether there is a syncword at the expected next frame start and a valid header is (optional but very robust) + Mp3FrameHeader_sync_t next_header; + if (((buf[current_pos + header.frame_length] == SYNCWORDH) && ((buf[current_pos + header.frame_length + 1] & SYNCWORDL) == SYNCWORDL)) && + parseMp3Header(&buf[current_pos + header.frame_length], &next_header)) { + // MP3_LOG_DEBUG("Found reliable MP3 frame at pos: {}, length: {}", current_pos, header.frame_length); + + // s_samplerate = header.sample_rate_hz; // (suppose in the structure available) + // s_bitRate = header.bitrate_kbps; // (suppose in the structure available) + // s_mpeg_version = header.mpeg_version; + // s_layer = header.layer; + // s_channel_mode = header.channel_mode; + // s_samples_per_frame = header.samples_per_frame; + + // // s_channels (1 Mono, 2 Stereo) + // if (header.channel_mode == 0b11) { // 0b11 ist Mono + // s_channels = 1; + // } else { // 2 channels for all other (Stereo, Joint Stereo, Dual Channel) + // s_channels = 2; + // } + return current_pos; + } else { + MP3_LOG_DEBUG("Header valid, but next frame does not validate. False positive. Moving on."); + } + } else { + MP3_LOG_DEBUG("Header valid, but not enough data for next frame check. Possibly end of stream or false positive."); + // If not enough data for the next frame, it could still be the right one. + // This is a compromise.If in doubt, continue to search or return the current one. + // For robustness: search. + } + } else { + MP3_LOG_DEBUG("Found syncword but header is invalid. Moving to next possible syncword."); + } + + // If the current header was invalid or the next frame did not validate the current "SyncWord" and continue to search + current_pos += 1; // go a byte on and look for the Syncword again + nBytes -= 1; + } + + return -1; // no valid MP3 frame found +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3FindFreeSync + * + * Description: figure out number of bytes between adjacent sync words in "free" mode + * + * Inputs: buffer to search for next sync word + * the 4-byte frame header starting at the current sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to next sync word, minus any pad byte (i.e. nSlots) + * -1 if sync not found after searching nBytes + * + * Notes: this checks that the first 22 bits of the next frame header are the + * same as the current frame header, but it's still not foolproof + * (could accidentally find a sequence in the bitstream which + * appears to match but is not actually the next frame header) + * this could be made more error-resilient by checking several frames + * in a row and verifying that nSlots is the same in each case + * since free mode requires CBR (see spec) we generally only call + * this function once (first frame) then store the result (nSlots) + * and just use it from then on + */ +int32_t MP3Decoder::MP3FindFreeSync(uint8_t* buf, uint8_t firstFH[4], int32_t nBytes) { + int32_t offset = 0; + uint8_t* bufPtr = buf; + + /* loop until we either: + * - run out of nBytes (FindMP3SyncWord() returns -1) + * - find the next valid frame header (sync word, version, layer, CRC flag, bitrate, and sample rate + * in next header must match current header) + */ + while (1) { + offset = findSyncWord(bufPtr, nBytes); + bufPtr += offset; + if (offset < 0) { + return -1; + } else if ((bufPtr[0] == firstFH[0]) && (bufPtr[1] == firstFH[1]) && ((bufPtr[2] & 0xfc) == (firstFH[2] & 0xfc))) { + /* want to return number of bytes per frame, + * NOT counting the padding byte, so subtract one if padFlag == 1 */ + if ((firstFH[2] >> 1) & 0x01) bufPtr--; + return bufPtr - buf; + } + bufPtr += 3; + nBytes -= (offset + 3); + }; + + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3GetLastFrameInfo + * + * Description: get info about last MP3 frame decoded (number of sampled decoded, + * sample rate, bitrate, etc.) + * + * Inputs: + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: none + * + * Notes: call this right after calling MP3Decode + */ +void MP3Decoder::MP3GetLastFrameInfo() { + if (m_MP3DecInfo->layer != 3) { + m_MP3FrameInfo->bitrate = 0; + m_MP3FrameInfo->nChans = 0; + m_MP3FrameInfo->samprate = 0; + m_MP3FrameInfo->bitsPerSample = 0; + m_MP3FrameInfo->outputSamps = 0; + m_MP3FrameInfo->layer = 0; + m_MP3FrameInfo->version = 0; + } else { + m_MP3FrameInfo->bitrate = m_MP3DecInfo->bitrate; + m_MP3FrameInfo->nChans = m_MP3DecInfo->nChans; + m_MP3FrameInfo->samprate = m_MP3DecInfo->samprate; + m_MP3FrameInfo->bitsPerSample = 16; + m_MP3FrameInfo->outputSamps = (int32_t)samplesPerFrameTab[m_MPEGVersion][m_MP3DecInfo->layer - 1]; + m_MP3FrameInfo->layer = m_MP3DecInfo->layer; + m_MP3FrameInfo->version = m_MPEGVersion; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::getSampleRate() { + return m_MP3FrameInfo->samprate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t MP3Decoder::getChannels() { + return m_MP3FrameInfo->nChans; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t MP3Decoder::getBitsPerSample() { + return m_MP3FrameInfo->bitsPerSample; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::getBitRate() { + return m_MP3FrameInfo->bitrate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::getOutputSamples() { + return m_MP3FrameInfo->outputSamps; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* MP3Decoder::arg1() { + m_mpeg_version_str.assign(mpeg_version_table[m_MP3FrameInfo->version]); // 0: MPEG-2.5, 1: Reserviert, 2: MPEG-2 (ISO/IEC 13818-3), 3: MPEG-1 (ISO/IEC 11172-3) + m_mpeg_version_str.appendf(" {}", layer_table[m_MP3FrameInfo->layer]); + return m_mpeg_version_str.get(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::getAudioDataStart() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t MP3Decoder::getAudioFileDuration() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* MP3Decoder::getStreamTitle() { + return nullptr; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* MP3Decoder::whoIsIt() { + return "MP3"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) { + return; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector MP3Decoder::getMetadataBlockPicture() { + return {}; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* MP3Decoder::arg2() { + return ""; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::val1() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::val2() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3GetNextFrameInfo + * + * Description: parse MP3 frame header + * + * Inputs: pointer to buffer containing valid MP3 frame header (located using + * MP3FindSyncWord(), above) + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + */ +int32_t MP3Decoder::MP3GetNextFrameInfo(uint8_t* buf) { + + if (UnpackFrameHeader(buf) == -1 || m_MP3DecInfo->layer != 3) { + MP3_LOG_ERROR("MP3 invalid frameheader"); + return MP3_ERR; + } + MP3GetLastFrameInfo(); + + return MP3_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3ClearBadFrame + * + * Description: zero out pcm buffer if error decoding MP3 frame + * + * Inputs: mp3DecInfo struct with correct frame size parameters filled in + * pointer pcm output buffer + * + * Outputs: zeroed out pcm buffer + * + * Return: none + */ +void MP3Decoder::MP3ClearBadFrame(int16_t* outbuf) { + int32_t i; + for (i = 0; i < m_MP3DecInfo->nGrans * m_MP3DecInfo->nGranSamps * m_MP3DecInfo->nChans; i++) outbuf[i] = 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IsLikelyRealFrame + * + * Description: Detection of valid MP3 frames + * + * Return: true, if valid + * false if ID3 padding fragments, LAME Info, Xing Header, VBRI Header, Repeater-Frames, Encoder Delay Blocks + * LAME Info + */ +int32_t MP3Decoder::IsLikelyRealFrame(const uint8_t* p, int32_t bytesLeft) { + + auto CalcFrameLength = [](const uint8_t* h) -> int { + static const int bitrateTable[2][16] = { + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, // MPEG2/2.5 + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} // MPEG1 + }; + + static const int samplerateTable[3][3] = { + {11025, 12000, 8000}, // MPEG 2.5 + {22050, 24000, 16000}, // MPEG 2 + {44100, 48000, 32000} // MPEG 1 + }; + + uint8_t verID = (h[1] >> 3) & 0x03; + uint8_t layer = (h[1] >> 1) & 0x03; + uint8_t brIdx = (h[2] >> 4) & 0x0F; + uint8_t srIdx = (h[2] >> 2) & 0x03; + uint8_t padding = (h[2] >> 1) & 0x01; + + if (layer != 1) return -1; + if (srIdx == 3) return -1; + if (brIdx == 0 || brIdx == 15) return -1; + + int verGroup = (verID == 3) ? 2 : (verID == 2 ? 1 : 0); + int samplerate = samplerateTable[verGroup][srIdx]; + if (samplerate == 0) return -1; + + int br = bitrateTable[(verID == 3)][brIdx] * 1000; + + int frameLength = (verID == 3) ? (144 * br / samplerate + padding) : (72 * br / samplerate + padding); + + return frameLength; + }; + + // 1) Sync? + if (p[0] != 0xFF || (p[1] & 0xE0) != 0xE0) return 0; // no header + + int frameLen = CalcFrameLength(p); + if (frameLen <= 0 || frameLen > bytesLeft) return -frameLen; // Fake frame + + // 2) Hard limits + if (frameLen > 2880) return -frameLen; // is fake + + // 3) Check next header + const uint8_t* next = p + frameLen; + if (bytesLeft == frameLen) { + return frameLen; // letzter Frame der Datei + } + + if (bytesLeft >= frameLen + 4 && next[0] == 0xFF && (next[1] & 0xE0) == 0xE0) { return frameLen; } + + return -frameLen; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: MP3Decode + * + * Description: decode one frame of MP3 data + * + * Inputs: number of valid bytes remaining in inbuf + * pointer to outbuf, big enough to hold one frame of decoded PCM samples + * flag indicating whether MP3 data is normal MPEG format (useSize = 0) + * or reformatted as "self-contained" frames (useSize = 1) + * + * Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo + * number of output samples = nGrans * nGranSamps * nChans + * updated inbuf pointer, updated bytesLeft + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + * + * Notes: switching useSize on and off between frames in the same stream + * is not supported (bit reservoir is not maintained if useSize on) + */ + +int32_t MP3Decoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + // Skip fake frames + int frameLen = IsLikelyRealFrame(inbuf, *bytesLeft); + if (frameLen == 0) { + if (memcmp(inbuf, "APETAGEX", 8) == 0) { + MP3_LOG_DEBUG("APETAGEX gefunden"); + uint32_t version = inbuf[8] | (inbuf[9] << 8) | (inbuf[10] << 16) | (inbuf[11] << 24); + uint32_t size = inbuf[12] | (inbuf[13] << 8) | (inbuf[14] << 16) | (inbuf[15] << 24); + MP3_LOG_DEBUG("version {} size {}", version, size); + *bytesLeft -= min(*bytesLeft, (int32_t)size); + return MP3_NEXT_FRAME; + } + } + + if (m_invalid_frame.start == true && m_invalid_frame.timer + 3000 > millis()) m_invalid_frame.start = false; + + if (frameLen <= 0) { + int skip = abs(frameLen); + if (skip > 0 && skip <= *bytesLeft) { + *bytesLeft -= skip; + MP3_LOG_DEBUG("Fakeframe, size {}", abs(frameLen)); + + if (m_invalid_frame.start == false) { // fake frames control + m_invalid_frame.start = true; + m_invalid_frame.timer = millis(); + m_invalid_frame.count1 = 0; + m_invalid_frame.count2 = 0; + } else { + m_invalid_frame.count1++; + if (m_invalid_frame.start && m_invalid_frame.timer + 1000 < millis()) { m_invalid_frame.count2++; } + if (m_invalid_frame.start && m_invalid_frame.timer + 2000 < millis()) { + if (m_invalid_frame.count1 > 5 && m_invalid_frame.count2 > 5) { + // network error + m_invalid_frame.start = false; + return MP3_NEED_RESTART; + } + } + } + + return MP3_NONE; // fakeframe + } + // inbuf empty or unusable + return MP3_ERR; + } + + int32_t offset, bitOffset, mainBits, gr, ch, fhBytes, siBytes, freeFrameBytes; + int32_t prevBitOffset, sfBlockBits, huffBlockBits; + uint8_t* mainPtr; + static uint8_t underflowCounter = 0; // http://macslons-irish-pub-radio.stream.laut.fm/macslons-irish-pub-radio + /* unpack frame header */ + fhBytes = UnpackFrameHeader(inbuf); + if (fhBytes < 0) { + MP3_LOG_ERROR("MP3 invalid frameheader"); /* don't clear out16 since we don't know size (failed to parse header) */ + return MP3_ERR; + } + inbuf += fhBytes; + /* unpack side info */ + siBytes = UnpackSideInfo(inbuf); + if (siBytes < 0) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3 invalid sideinfo"); + return MP3_ERR; + } + inbuf += siBytes; + *bytesLeft -= (fhBytes + siBytes); + + /* if free mode, need to calculate bitrate and nSlots manually, based on frame size */ + if (m_MP3DecInfo->bitrate == 0 || m_MP3DecInfo->freeBitrateFlag) { + if (!m_MP3DecInfo->freeBitrateFlag) { + /* first time through, need to scan for next sync word and figure out frame size */ + m_MP3DecInfo->freeBitrateFlag = 1; + m_MP3DecInfo->freeBitrateSlots = MP3FindFreeSync(inbuf, inbuf - fhBytes - siBytes, *bytesLeft); + if (m_MP3DecInfo->freeBitrateSlots < 0) { + MP3ClearBadFrame(m_out16.get()); + m_MP3DecInfo->freeBitrateFlag = 0; + MP3_LOG_ERROR("MP3, ca'nt find free bitrate slot"); + return MP3_ERR; + } + freeFrameBytes = m_MP3DecInfo->freeBitrateSlots + fhBytes + siBytes; + m_MP3DecInfo->bitrate = (freeFrameBytes * m_MP3DecInfo->samprate * 8) / (m_MP3DecInfo->nGrans * m_MP3DecInfo->nGranSamps); + } + m_MP3DecInfo->nSlots = m_MP3DecInfo->freeBitrateSlots + CheckPadBit(); /* add pad byte, if required */ + } + + if (m_MP3DecInfo->nSlots > *bytesLeft) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_DEBUG("MP3, indata underflow"); + return MP3_MAIN_DATA_UNDERFLOW; + } + + /* fill main data buffer with enough new data for this frame */ + if (m_MP3DecInfo->mainDataBytes >= m_MP3DecInfo->mainDataBegin) { + /* adequate "old" main data available (i.e. bit reservoir) */ + underflowCounter = 0; + memmove(m_MP3DecInfo->mainBuf, m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBytes - m_MP3DecInfo->mainDataBegin, m_MP3DecInfo->mainDataBegin); + memcpy(m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBegin, inbuf, m_MP3DecInfo->nSlots); + + m_MP3DecInfo->mainDataBytes = m_MP3DecInfo->mainDataBegin + m_MP3DecInfo->nSlots; + inbuf += m_MP3DecInfo->nSlots; + *bytesLeft -= (m_MP3DecInfo->nSlots); + mainPtr = m_MP3DecInfo->mainBuf; + } else { + /* not enough data in bit reservoir from previous frames (perhaps starting in middle of file) */ + underflowCounter++; + memcpy(m_MP3DecInfo->mainBuf + m_MP3DecInfo->mainDataBytes, inbuf, m_MP3DecInfo->nSlots); + m_MP3DecInfo->mainDataBytes += m_MP3DecInfo->nSlots; + inbuf += m_MP3DecInfo->nSlots; + *bytesLeft -= (m_MP3DecInfo->nSlots); + if (underflowCounter < 4) { return MP3_NONE; } + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_DEBUG("MP3, maindata underflow"); + return MP3_NONE; + } + // } + bitOffset = 0; + mainBits = m_MP3DecInfo->mainDataBytes * 8; + + /* decode one complete frame */ + for (gr = 0; gr < m_MP3DecInfo->nGrans; gr++) { + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + /* unpack scale factors and compute size of scale factor block */ + prevBitOffset = bitOffset; + offset = UnpackScaleFactors(mainPtr, &bitOffset, mainBits, gr, ch); + sfBlockBits = 8 * offset - prevBitOffset + bitOffset; + huffBlockBits = m_MP3DecInfo->part23Length[gr][ch] - sfBlockBits; + mainPtr += offset; + mainBits -= sfBlockBits; + + if (offset < 0 || mainBits < huffBlockBits) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3, invalid scalefact"); + return MP3_ERR; + } + /* decode Huffman code words */ + prevBitOffset = bitOffset; + offset = DecodeHuffman(mainPtr, &bitOffset, huffBlockBits, gr, ch); + if (offset < 0) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3, invalid Huffman code words"); + return MP3_ERR; + } + mainPtr += offset; + mainBits -= (8 * offset - prevBitOffset + bitOffset); + } + /* dequantize coefficients, decode stereo, reorder int16_t blocks */ + if (MP3Dequantize(gr) < 0) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3, invalid dequantize coefficients"); + return MP3_ERR; + } + + /* alias reduction, inverse MDCT, overlap-add, frequency inversion */ + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + if (IMDCT(gr, ch) < 0) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3, invalid inverse MDCT"); + return MP3_ERR; + } + } + /* subband transform - if stereo, interleaves pcm LRLRLR */ + if (Subband(m_out16.get() + gr * m_MP3DecInfo->nGranSamps * m_MP3DecInfo->nChans) < 0) { + MP3ClearBadFrame(m_out16.get()); + MP3_LOG_ERROR("MP3, invalid subband"); + return MP3_ERR; + } + } + MP3GetLastFrameInfo(); + + if (m_MP3FrameInfo->nChans == 1) { + for (int i = 0; i < m_MP3FrameInfo->outputSamps; i++) { + outbuf[i * 2] = m_out16[i] << 16; + outbuf[i * 2 + 1] = m_out16[i] << 16; + } + } + + if (m_MP3FrameInfo->nChans == 2) { + for (int i = 0; i < m_MP3FrameInfo->outputSamps * 2; i++) { outbuf[i] = m_out16[i] << 16; } + } + + return MP3_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * H U F F M A N N + */ + +/* + * Function: DecodeHuffmanPairs + * + * Description: decode 2-way vector Huffman codes in the "bigValues" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of pair-wise codes + * pointer to xy buffer to received decoded values + * number of codewords to decode + * index of Huffman table to use + * number of bits remaining in bitstream + * + * Outputs: pairs of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: number of bits used, or -1 if out of bits + * + * Notes: assumes that nVals is an even number + * si_huff.bit tests every Huffman codeword in every table (though not + * necessarily all linBits outputs for x,y > 15) + */ +// no improvement with section=data + +int32_t MP3Decoder::DecodeHuffmanPairs(int32_t* xy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t* buf, int32_t bitOffset) { + int32_t i, x, y; + int32_t cachedBits, padBits, len, startBits, linBits, maxBits, minBits; + HuffTabType_t tabType; + uint16_t cw, *tBase, *tCurr; + uint32_t cache; + + if (nVals <= 0) return 0; + + if (bitsLeft < 0) return -1; + startBits = bitsLeft; + + tBase = (uint16_t*)(huffTable + huffTabOffset[tabIdx]); + linBits = huffTabLookup[tabIdx].linBits; + tabType = (HuffTabType_t)huffTabLookup[tabIdx].tabType; + + // assert(!(nVals & 0x01)); + // assert(tabIdx < m_HUFF_PAIRTABS); + // assert(tabIdx >= 0); + // assert(tabType != invalidTab); + + if ((nVals & 0x01)) { + MP3_LOG_DEBUG("assert(!(nVals & 0x01))"); + return -1; + } + if (!(tabIdx < HUFF_PAIRTABS)) { + MP3_LOG_DEBUG("assert(tabIdx < m_HUFF_PAIRTABS)"); + return -1; + } + if (!(tabIdx >= 0)) { + MP3_LOG_DEBUG("(tabIdx >= 0)"); + return -1; + } + if (!(tabType != invalidTab)) { + MP3_LOG_DEBUG("(tabType != invalidTab)"); + return -1; + } + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits = (8 - bitOffset) & 0x07; + if (cachedBits) cache = (uint32_t)(*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + if (tabType == noBits) { + /* table 0, no data, x = y = 0 */ + for (i = 0; i < nVals; i += 2) { + xy[i + 0] = 0; + xy[i + 1] = 0; + } + return 0; + } else if (tabType == oneShot) { + /* single lookup, no escapes */ + + maxBits = (int32_t)((((uint16_t)(pgm_read_word(&tBase[0])) >> 0) & 0x000f)); + tBase++; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t)(*buf++) << (24 - cachedBits); + cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) { return -1; } + if (bitsLeft > 0) cache |= (uint32_t)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t)0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11) { + cw = pgm_read_word(&tBase[cache >> (32 - maxBits)]); + + len = (int32_t)((((uint16_t)(cw)) >> 12) & 0x000f); + cachedBits -= len; + cache <<= len; + + x = (int32_t)((((uint16_t)(cw)) >> 4) & 0x000f); + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + y = (int32_t)((((uint16_t)(cw)) >> 8) & 0x000f); + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits) { + MP3_LOG_ERROR("MP3, error - overran end of bitstream"); // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + return MP3_ERR; + } + + *xy++ = x; + *xy++ = y; + nVals -= 2; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } else if (tabType == loopLinbits || tabType == loopNoLinbits) { + tCurr = tBase; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t)(*buf++) << (24 - cachedBits); + cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) { return -1; } + if (bitsLeft > 0) cache |= (uint32_t)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t)0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11) { + maxBits = (int32_t)((((uint16_t)(pgm_read_word(&tCurr[0]))) >> 0) & 0x000f); + cw = pgm_read_word(&tCurr[(cache >> (32 - maxBits)) + 1]); + len = (int32_t)((((uint16_t)(cw)) >> 12) & 0x000f); + if (!len) { + cachedBits -= maxBits; + cache <<= maxBits; + tCurr += cw; + continue; + } + cachedBits -= len; + cache <<= len; + + x = (int32_t)((((uint16_t)(cw)) >> 4) & 0x000f); + y = (int32_t)((((uint16_t)(cw)) >> 8) & 0x000f); + + if (x == 15 && tabType == loopLinbits) { + minBits = linBits + 1 + (y ? 1 : 0); + if (cachedBits + bitsLeft < minBits) return -1; + while (cachedBits < minBits) { + cache |= (uint32_t)(*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (int32_t)0x80000000 >> (cachedBits - 1); + } + x += (int32_t)(cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + if (y == 15 && tabType == loopLinbits) { + minBits = linBits + 1; + if (cachedBits + bitsLeft < minBits) { + MP3_LOG_ERROR("MP3, error - overran end of bitstream"); // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + return MP3_ERR; + } + // return -1; + while (cachedBits < minBits) { + cache |= (uint32_t)(*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (int32_t)0x80000000 >> (cachedBits - 1); + } + y += (int32_t)(cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits) { + break; // https://bestof80s.stream.laut.fm/best_of_80s (after advertising) + // return -1; + } + + *xy++ = x; + *xy++ = y; + nVals -= 2; + tCurr = tBase; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } + + /* error in bitstream - trying to access unused Huffman table */ + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: DecodeHuffmanQuads + * + * Description: decode 4-way vector Huffman codes in the "count1" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of quadword codes + * pointer to vwxy buffer to received decoded values + * maximum number of codewords to decode + * index of quadword table (0 = table A, 1 = table B) + * number of bits remaining in bitstream + * + * Outputs: quadruples of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: index of the first "zero_part" value (index of the first sample + * of the quad word after which all samples are 0) + * + * Notes: si_huff.bit tests every vwxy output in both quad tables + */ +// no improvement with section=data +int32_t MP3Decoder::DecodeHuffmanQuads(int32_t* vwxy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t* buf, int32_t bitOffset) { + int32_t i, v, w, x, y; + int32_t len, maxBits, cachedBits, padBits; + uint32_t cache; + uint8_t cw, *tBase; + + if (bitsLeft <= 0) return 0; + + tBase = (uint8_t*)quadTable + quadTabOffset[tabIdx]; + maxBits = quadTabMaxBits[tabIdx]; + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits = (8 - bitOffset) & 0x07; + if (cachedBits) cache = (uint32_t)(*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + i = padBits = 0; + while (i < (nVals - 3)) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (uint32_t)(*buf++) << (24 - cachedBits); + cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) return i; + if (bitsLeft > 0) cache |= (uint32_t)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (uint32_t)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (int32_t)0x80000000 >> (cachedBits - 1); + padBits = 10; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 6, plus 4 for sign bits, so make sure cache has at least 10 bits */ + while (i < (nVals - 3) && cachedBits >= 10) { + cw = pgm_read_byte(&tBase[cache >> (32 - maxBits)]); + len = (int32_t)((((uint8_t)(cw)) >> 4) & 0x0f); + cachedBits -= len; + cache <<= len; + + v = (int32_t)((((uint8_t)(cw)) >> 3) & 0x01); + if (v) { + (v) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + w = (int32_t)((((uint8_t)(cw)) >> 2) & 0x01); + if (w) { + (w) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + x = (int32_t)((((uint8_t)(cw)) >> 1) & 0x01); + if (x) { + (x) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + y = (int32_t)((((uint8_t)(cw)) >> 0) & 0x01); + if (y) { + (y) |= ((cache) & 0x80000000); + cache <<= 1; + cachedBits--; + } + + /* ran out of bits - okay (means we're done) */ + if (cachedBits < padBits) return i; + + *vwxy++ = v; + *vwxy++ = w; + *vwxy++ = x; + *vwxy++ = y; + i += 4; + } + } + + /* decoded max number of quad values */ + return i; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: DecodeHuffman + * + * Description: decode one granule, one channel worth of Huffman codes + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * and UnpackScaleFactors() (for this granule) + * buffer pointing to start of Huffman data in MP3 frame + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits in the Huffman data section of the frame + * (could include padding bits) + * index of current granule and channel + * + * Outputs: decoded coefficients in hi->huffDecBuf[ch] (hi pointer in mp3DecInfo) + * updated bitOffset + * + * Return: length (in bytes) of Huffman codes + * bitOffset also returned in parameter (0 = MSB, 7 = LSB of + * byte located at buf + offset) + * -1 if null input pointers, huffBlockBits < 0, or decoder runs + * out of bits prematurely (invalid bitstream) + */ +// .data about 1ms faster per frame +int32_t MP3Decoder::DecodeHuffman(uint8_t* buf, int32_t* bitOffset, int32_t huffBlockBits, int32_t gr, int32_t ch) { + + int32_t r1Start, r2Start, rEnd[4]; /* region boundaries */ + int32_t i, w, bitsUsed, bitsLeft; + uint8_t* startBuf = buf; + + SideInfoSub_t* sis; + sis = &m_SideInfoSub[gr][ch]; + // hi = (HuffmanInfo_t*) (m_MP3DecInfo->HuffmanInfoPS); + + if (huffBlockBits < 0) { return -1; } + + /* figure out region boundaries (the first 2*bigVals coefficients divided into 3 regions) */ + if (sis->winSwitchFlag && sis->blockType == 2) { + if (sis->mixedBlock == 0) { + r1Start = m_SFBandTable.s[(sis->region0Count + 1) / 3] * 3; + } else { + if (m_MPEGVersion == MPEG1) { + r1Start = m_SFBandTable.l[sis->region0Count + 1]; + } else { + /* see MPEG2 spec for explanation */ + w = m_SFBandTable.s[4] - m_SFBandTable.s[3]; + r1Start = m_SFBandTable.l[6] + 2 * w; + } + } + r2Start = MAX_NSAMP; /* short blocks don't have region 2 */ + } else { + r1Start = m_SFBandTable.l[sis->region0Count + 1]; + r2Start = m_SFBandTable.l[sis->region0Count + 1 + sis->region1Count + 1]; + } + + /* offset rEnd index by 1 so first region = rEnd[1] - rEnd[0], etc. */ + rEnd[3] = (MAX_NSAMP < (2 * sis->nBigvals) ? MAX_NSAMP : (2 * sis->nBigvals)); + rEnd[2] = (r2Start < rEnd[3] ? r2Start : rEnd[3]); + rEnd[1] = (r1Start < rEnd[3] ? r1Start : rEnd[3]); + rEnd[0] = 0; + + /* rounds up to first all-zero pair (we don't check last pair for (x,y) == (non-zero, zero)) */ + m_HuffmanInfo->nonZeroBound[ch] = rEnd[3]; + + /* decode Huffman pairs (rEnd[i] are always even numbers) */ + bitsLeft = huffBlockBits; + for (i = 0; i < 3; i++) { + bitsUsed = DecodeHuffmanPairs(m_HuffmanInfo->huffDecBuf[ch] + rEnd[i], rEnd[i + 1] - rEnd[i], sis->tableSelect[i], bitsLeft, buf, *bitOffset); + if (bitsUsed < 0 || bitsUsed > bitsLeft) { /* error - overran end of bitstream */ + return -1; + } + /* update bitstream position */ + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + bitsLeft -= bitsUsed; + } + + /* decode Huffman quads (if any) */ + m_HuffmanInfo->nonZeroBound[ch] += DecodeHuffmanQuads(m_HuffmanInfo->huffDecBuf[ch] + rEnd[3], MAX_NSAMP - rEnd[3], sis->count1TableSelect, bitsLeft, buf, *bitOffset); + + assert(m_HuffmanInfo->nonZeroBound[ch] <= MAX_NSAMP); + for (i = m_HuffmanInfo->nonZeroBound[ch]; i < MAX_NSAMP; i++) m_HuffmanInfo->huffDecBuf[ch][i] = 0; + + /* If bits used for 576 samples < huffBlockBits, then the extras are considered + * to be stuffing bits (throw away, but need to return correct bitstream position) + */ + buf += (bitsLeft + *bitOffset) >> 3; + *bitOffset = (bitsLeft + *bitOffset) & 0x07; + + return (buf - startBuf); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * D E Q U A N T + */ + +/* + * Function: MP3Dequantize + * + * Description: dequantize coefficients, decode stereo, reorder short blocks + * (one granule-worth) + * + * Inputs: index of current granule + * + * Outputs: dequantized and reordered coefficients in hi->huffDecBuf + * (one granule-worth, all channels), format = Q26 + * operates in-place on huffDecBuf but also needs di->workBuf + * updated hi->nonZeroBound index for both channels + * + * Return: 0 on success, -1 if null input pointers + * + * Notes: In calling output Q(DQ_FRACBITS_OUT), we assume an implicit bias + * of 2^15. Some (floating-point) reference implementations factor this + * into the 2^(0.25 * gain) scaling explicitly. But to avoid MP3Decoder:: precision + * loss, we don't do that. Instead take it into account in the final + * round to PCM (>> by 15 less than we otherwise would have). + * Equivalently, we can think of the dequantized coefficients as + * Q(DQ_FRACBITS_OUT - 15) with no implicit bias. + */ +int32_t MP3Decoder::MP3Dequantize(int32_t gr) { + int32_t i, ch, nSamps, mOut[2]; + CriticalBandInfo_t* cbi; + cbi = &m_CriticalBandInfo[0]; + mOut[0] = mOut[1] = 0; + + /* dequantize all the samples in each channel */ + for (ch = 0; ch < m_MP3DecInfo->nChans; ch++) { + m_HuffmanInfo->gb[ch] = + DequantChannel(m_HuffmanInfo->huffDecBuf[ch], m_DequantInfo->workBuf, &m_HuffmanInfo->nonZeroBound[ch], &m_SideInfoSub[gr][ch], &m_ScaleFactorInfoSub[gr][ch], &cbi[ch]); + } + + /* joint stereo processing assumes one guard bit in input samples + * it's extremely rare not to have at least one gb, so if this is the case + * just make a pass over the data and clip to [-2^30+1, 2^30-1] + * in practice this may never happen + */ + if (m_FrameHeader->modeExt && (m_HuffmanInfo->gb[0] < 1 || m_HuffmanInfo->gb[1] < 1)) { + for (i = 0; i < m_HuffmanInfo->nonZeroBound[0]; i++) { + if (m_HuffmanInfo->huffDecBuf[0][i] < -0x3fffffff) m_HuffmanInfo->huffDecBuf[0][i] = -0x3fffffff; + if (m_HuffmanInfo->huffDecBuf[0][i] > 0x3fffffff) m_HuffmanInfo->huffDecBuf[0][i] = 0x3fffffff; + } + for (i = 0; i < m_HuffmanInfo->nonZeroBound[1]; i++) { + if (m_HuffmanInfo->huffDecBuf[1][i] < -0x3fffffff) m_HuffmanInfo->huffDecBuf[1][i] = -0x3fffffff; + if (m_HuffmanInfo->huffDecBuf[1][i] > 0x3fffffff) m_HuffmanInfo->huffDecBuf[1][i] = 0x3fffffff; + } + } + + /* do mid-side stereo processing, if enabled */ + if (m_FrameHeader->modeExt >> 1) { + if (m_FrameHeader->modeExt & 0x01) { + /* intensity stereo enabled - run mid-side up to start of right zero region */ + if (cbi[1].cbType == 0) + nSamps = m_SFBandTable.l[cbi[1].cbEndL + 1]; + else + nSamps = 3 * m_SFBandTable.s[cbi[1].cbEndSMax + 1]; + } else { + /* intensity stereo disabled - run mid-side on whole spectrum */ + nSamps = (m_HuffmanInfo->nonZeroBound[0] > m_HuffmanInfo->nonZeroBound[1] ? m_HuffmanInfo->nonZeroBound[0] : m_HuffmanInfo->nonZeroBound[1]); + } + MidSideProc(m_HuffmanInfo->huffDecBuf, nSamps, mOut); + } + + /* do intensity stereo processing, if enabled */ + if (m_FrameHeader->modeExt & 0x01) { + nSamps = m_HuffmanInfo->nonZeroBound[0]; + if (m_MPEGVersion == MPEG1) { + IntensityProcMPEG1(m_HuffmanInfo->huffDecBuf, nSamps, &m_ScaleFactorInfoSub[gr][1], &m_CriticalBandInfo[0], m_FrameHeader->modeExt >> 1, m_SideInfoSub[gr][1].mixedBlock, mOut); + } else { + IntensityProcMPEG2(m_HuffmanInfo->huffDecBuf, nSamps, &m_ScaleFactorInfoSub[gr][1], &m_CriticalBandInfo[0], m_ScaleFactorJS.get(), m_FrameHeader->modeExt >> 1, + m_SideInfoSub[gr][1].mixedBlock, mOut); + } + } + + /* adjust guard bit count and nonZeroBound if we did any stereo processing */ + if (m_FrameHeader->modeExt) { + m_HuffmanInfo->gb[0] = CLZ(mOut[0]) - 1; + m_HuffmanInfo->gb[1] = CLZ(mOut[1]) - 1; + nSamps = (m_HuffmanInfo->nonZeroBound[0] > m_HuffmanInfo->nonZeroBound[1] ? m_HuffmanInfo->nonZeroBound[0] : m_HuffmanInfo->nonZeroBound[1]); + m_HuffmanInfo->nonZeroBound[0] = nSamps; + m_HuffmanInfo->nonZeroBound[1] = nSamps; + } + + /* output format Q(DQ_FRACBITS_OUT) */ + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * D Q C H A N + */ + +/* + * Function: DequantBlock + * + * Description: Ken's highly-optimized, low memory dequantizer performing the operation + * y = pow(x, 4.0/3.0) * pow(2, 25 - scale/4.0) + * + * Inputs: input buffer of decode Huffman codewords (signed-magnitude) + * output buffer of same length (in-place (outbuf = inbuf) is allowed) + * number of samples + * + * Outputs: dequantized samples in Q25 format + * + * Return: bitwise-OR of the unsigned outputs (for guard bit calculations) + */ +int32_t MP3Decoder::DequantBlock(int32_t* inbuf, int32_t* outbuf, int32_t num, int32_t scale) { + int32_t tab4[4]; + int32_t scalef, scalei, shift; + int32_t sx, x, y; + int32_t mask = 0; + const int32_t* tab16; + const uint32_t* coef; + + tab16 = pow43_14[scale & 0x3]; + scalef = pow14[scale & 0x3]; + scalei = ((scale >> 2) < 31 ? (scale >> 2) : 31); + // scalei = MIN(scale >> 2, 31); /* smallest input scale = -47, so smallest scalei = -12 */ + + /* cache first 4 values */ + shift = (scalei + 3 < 31 ? scalei + 3 : 31); + shift = (shift > 0 ? shift : 0); + + tab4[0] = 0; + tab4[1] = tab16[1] >> shift; + tab4[2] = tab16[2] >> shift; + tab4[3] = tab16[3] >> shift; + + do { + sx = *inbuf++; + x = sx & 0x7fffffff; /* sx = sign|mag */ + if (x < 4) { + y = tab4[x]; + } else if (x < 16) { + y = tab16[x]; + y = (scalei < 0) ? y << -scalei : y >> scalei; + } else { + if (x < 64) { + y = pow43[x - 16]; + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - 3; + } else { + /* normalize to [0x40000000, 0x7fffffff] */ + x <<= 17; + shift = 0; + if (x < 0x08000000) x <<= 4, shift += 4; + if (x < 0x20000000) x <<= 2, shift += 2; + if (x < 0x40000000) x <<= 1, shift += 1; + + coef = (x < SQRTHALF) ? poly43lo : poly43hi; + + /* polynomial */ + y = coef[0]; + y = MULSHIFT32(y, x) + coef[1]; + y = MULSHIFT32(y, x) + coef[2]; + y = MULSHIFT32(y, x) + coef[3]; + y = MULSHIFT32(y, x) + coef[4]; + y = MULSHIFT32(y, pow2frac[shift]) << 3; + + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - pow2exp[shift]; + } + + /* integer scale */ + if (shift < 0) { + shift = -shift; + if (y > (0x7fffffff >> shift)) + y = 0x7fffffff; /* clip */ + else + y <<= shift; + } else { + y >>= shift; + } + } + + /* sign and store */ + mask |= y; + *outbuf++ = (sx < 0) ? -y : y; + + } while (--num); + + return mask; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: DequantChannel + * + * Description: dequantize one granule, one channel worth of decoded Huffman codewords + * + * Inputs: sample buffer (decoded Huffman codewords), length = m_MAX_NSAMP samples + * work buffer for reordering short-block, length = m_MAX_REORDER_SAMPS + * samples (3 * width of largest short-block critical band) + * non-zero bound for this channel/granule + * valid FrameHeader, SideInfoSub, ScaleFactorInfoSub, and CriticalBandInfo + * structures for this channel/granule + * + * Outputs: MAX_NSAMP dequantized samples in sampleBuf + * updated non-zero bound (indicating which samples are != 0 after DQ) + * filled-in cbi structure indicating start and end critical bands + * + * Return: minimum number of guard bits in dequantized sampleBuf + * + * Notes: dequantized samples in Q(DQ_FRACBITS_OUT) format + */ +int32_t MP3Decoder::DequantChannel(int32_t* sampleBuf, int32_t* workBuf, int32_t* nonZeroBound, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi) { + int32_t i, j, w, cb; + int32_t /* cbStartL, */ cbEndL, cbStartS, cbEndS; + int32_t nSamps, nonZero, sfactMultiplier, gbMask; + int32_t globalGain, gainI; + int32_t cbMax[3]; + typedef int32_t ARRAY3[3]; /* for short-block reordering */ + ARRAY3* buf; /* short block reorder */ + + /* set default start/end points for short/long blocks - will update with non-zero cb info */ + if (sis->blockType == 2) { + // cbStartL = 0; + if (sis->mixedBlock) { + cbEndL = (m_MPEGVersion == MPEG1 ? 8 : 6); + cbStartS = 3; + } else { + cbEndL = 0; + cbStartS = 0; + } + cbEndS = 13; + } else { + /* long block */ + // cbStartL = 0; + cbEndL = 22; + cbStartS = 13; + cbEndS = 13; + } + cbMax[2] = cbMax[1] = cbMax[0] = 0; + gbMask = 0; + i = 0; + + /* sfactScale = 0 --> quantizer step size = 2 + * sfactScale = 1 --> quantizer step size = sqrt(2) + * so sfactMultiplier = 2 or 4 (jump through globalGain by powers of 2 or sqrt(2)) + */ + sfactMultiplier = 2 * (sis->sfactScale + 1); + + /* offset globalGain by -2 if midSide enabled, for 1/sqrt(2) used in MidSideProc() + * (DequantBlock() does 0.25 * gainI so knocking it down by two is the same as + * dividing every sample by sqrt(2) = multiplying by 2^-.5) + */ + globalGain = sis->globalGain; + if (m_FrameHeader->modeExt >> 1) globalGain -= 2; + globalGain += IMDCT_SCALE; /* scale everything by sqrt(2), for fast IMDCT36 */ + + /* long blocks */ + for (cb = 0; cb < cbEndL; cb++) { + + nonZero = 0; + nSamps = m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + gainI = 210 - globalGain + sfactMultiplier * (sfis->l[cb] + (sis->preFlag ? (int32_t)preTab[cb] : 0)); + + nonZero |= DequantBlock(sampleBuf + i, sampleBuf + i, nSamps, gainI); + i += nSamps; + + /* update highest non-zero critical band */ + if (nonZero) cbMax[0] = cb; + gbMask |= nonZero; + + if (i >= *nonZeroBound) break; + } + + /* set cbi (Type, EndS[], EndSMax will be overwritten if we proceed to do short blocks) */ + cbi->cbType = 0; /* long only */ + cbi->cbEndL = cbMax[0]; + cbi->cbEndS[0] = cbi->cbEndS[1] = cbi->cbEndS[2] = 0; + cbi->cbEndSMax = 0; + + /* early exit if no short blocks */ + if (cbStartS >= 12) return CLZ(gbMask) - 1; + + /* short blocks */ + cbMax[2] = cbMax[1] = cbMax[0] = cbStartS; + for (cb = cbStartS; cb < cbEndS; cb++) { + + nSamps = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + for (w = 0; w < 3; w++) { + nonZero = 0; + gainI = 210 - globalGain + 8 * sis->subBlockGain[w] + sfactMultiplier * (sfis->s[cb][w]); + + nonZero |= DequantBlock(sampleBuf + i + nSamps * w, workBuf + nSamps * w, nSamps, gainI); + + /* update highest non-zero critical band */ + if (nonZero) cbMax[w] = cb; + gbMask |= nonZero; + } + + /* reorder blocks */ + buf = (ARRAY3*)(sampleBuf + i); + i += 3 * nSamps; + for (j = 0; j < nSamps; j++) { + buf[j][0] = workBuf[0 * nSamps + j]; + buf[j][1] = workBuf[1 * nSamps + j]; + buf[j][2] = workBuf[2 * nSamps + j]; + } + + assert(3 * nSamps <= MAX_REORDER_SAMPS); + + if (i >= *nonZeroBound) break; + } + + /* i = last non-zero INPUT sample processed, which corresponds to highest possible non-zero + * OUTPUT sample (after reorder) + * however, the original nzb is no longer necessarily true + * for each cb, buf[][] is updated with 3*nSamps samples (i increases 3*nSamps each time) + * (buf[j + 1][0] = 3 (input) samples ahead of buf[j][0]) + * so update nonZeroBound to i + */ + *nonZeroBound = i; + + assert(*nonZeroBound <= MAX_NSAMP); + + cbi->cbType = (sis->mixedBlock ? 2 : 1); /* 2 = mixed short/long, 1 = short only */ + + cbi->cbEndS[0] = cbMax[0]; + cbi->cbEndS[1] = cbMax[1]; + cbi->cbEndS[2] = cbMax[2]; + + cbi->cbEndSMax = cbMax[0]; + cbi->cbEndSMax = (cbi->cbEndSMax > cbMax[1] ? cbi->cbEndSMax : cbMax[1]); + cbi->cbEndSMax = (cbi->cbEndSMax > cbMax[2] ? cbi->cbEndSMax : cbMax[2]); + + return CLZ(gbMask) - 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * S T P R O C + */ + +/* + * Function: MidSideProc + * + * Description: sum-difference stereo reconstruction + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples (MAX of left and right) + * assume 1 guard bit in input + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + */ +void MP3Decoder::MidSideProc(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, int32_t mOut[2]) { + int32_t i, xr, xl, mOutL, mOutR; + + /* L = (M+S)/sqrt(2), R = (M-S)/sqrt(2) + * NOTE: 1/sqrt(2) done in DequantChannel() - see comments there + */ + mOutL = mOutR = 0; + for (i = 0; i < nSamps; i++) { + xl = x[0][i]; + xr = x[1][i]; + x[0][i] = xl + xr; + x[1][i] = xl - xr; + mOutL |= FASTABS(x[0][i]); + mOutR |= FASTABS(x[1][i]); + } + mOut[0] |= mOutL; + mOut[1] |= mOutR; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IntensityProcMPEG1 + * + * Description: intensity stereo processing for MPEG1 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + */ +void MP3Decoder::IntensityProcMPEG1(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]) { + int32_t i = 0, j = 0, n = 0, cb = 0, w = 0; + int32_t sampsLeft, isf, mOutL, mOutR, xl, xr; + int32_t fl, fr, fls[3], frs[3]; + int32_t cbStartL = 0, cbStartS = 0, cbEndL = 0, cbEndS = 0; + int32_t* isfTab; + (void)mixFlag; + + /* NOTE - this works fine for mixed blocks, as long as the switch point starts in the + * short block section (i.e. on or after sample 36 = sfBand->l[8] = 3*sfBand->s[3] + * is this a safe assumption? + */ + if (cbi[1].cbType == 0) { + /* long block */ + cbStartL = cbi[1].cbEndL + 1; + cbEndL = cbi[0].cbEndL + 1; + cbStartS = cbEndS = 0; + i = m_SFBandTable.l[cbStartL]; + } else if (cbi[1].cbType == 1 || cbi[1].cbType == 2) { + /* short or mixed block */ + cbStartS = cbi[1].cbEndSMax + 1; + cbEndS = cbi[0].cbEndSMax + 1; + cbStartL = cbEndL = 0; + i = 3 * m_SFBandTable.s[cbStartS]; + } + sampsLeft = nSamps - i; /* process to length of left */ + isfTab = (int32_t*)ISFMpeg1[midSideFlag]; + mOutL = mOutR = 0; + + /* long blocks */ + for (cb = cbStartL; cb < cbEndL && sampsLeft > 0; cb++) { + isf = sfis->l[cb]; + if (isf == 7) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + fl = isfTab[isf]; + fr = isfTab[6] - isfTab[isf]; + } + + n = m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + for (j = 0; j < n && sampsLeft > 0; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + sampsLeft--; + } + } + /* short blocks */ + for (cb = cbStartS; cb < cbEndS && sampsLeft >= 3; cb++) { + for (w = 0; w < 3; w++) { + isf = sfis->s[cb][w]; + if (isf == 7) { + fls[w] = ISFIIP[midSideFlag][0]; + frs[w] = ISFIIP[midSideFlag][1]; + } else { + fls[w] = isfTab[isf]; + frs[w] = isfTab[6] - isfTab[isf]; + } + } + n = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + for (j = 0; j < n && sampsLeft >= 3; j++, i += 3) { + xr = MULSHIFT32(frs[0], x[0][i + 0]) << 2; + x[1][i + 0] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[0], x[0][i + 0]) << 2; + x[0][i + 0] = xl; + mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[1], x[0][i + 1]) << 2; + x[1][i + 1] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[1], x[0][i + 1]) << 2; + x[0][i + 1] = xl; + mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[2], x[0][i + 2]) << 2; + x[1][i + 2] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[2], x[0][i + 2]) << 2; + x[0][i + 2] = xl; + mOutL |= FASTABS(xl); + sampsLeft -= 3; + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IntensityProcMPEG2 + * + * Description: intensity stereo processing for MPEG2 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * ScaleFactorJS struct with joint stereo info from UnpackSFMPEG2() + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + */ +void MP3Decoder::IntensityProcMPEG2(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi, ScaleFactorJS_t* sfjs, int32_t midSideFlag, int32_t mixFlag, + int32_t mOut[2]) { + int32_t i, j, k, n, r, cb, w; + int32_t fl, fr, mOutL, mOutR, xl, xr; + int32_t sampsLeft; + int32_t isf, sfIdx, tmp, il[23]; + int32_t* isfTab; + int32_t cbStartL, cbStartS, cbEndL, cbEndS; + + (void)mixFlag; + + isfTab = (int32_t*)ISFMpeg2[sfjs->intensityScale][midSideFlag]; + mOutL = mOutR = 0; + + /* fill buffer with illegal intensity positions (depending on slen) */ + for (k = r = 0; r < 4; r++) { + tmp = (1 << sfjs->slen[r]) - 1; + for (j = 0; j < sfjs->nr[r]; j++, k++) il[k] = tmp; + } + + if (cbi[1].cbType == 0) { + /* long blocks */ + il[21] = il[22] = 1; + cbStartL = cbi[1].cbEndL + 1; /* start at end of right */ + cbEndL = cbi[0].cbEndL + 1; /* process to end of left */ + i = m_SFBandTable.l[cbStartL]; + sampsLeft = nSamps - i; + + for (cb = cbStartL; cb < cbEndL; cb++) { + sfIdx = sfis->l[cb]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->l[cb] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + int32_t r = m_SFBandTable.l[cb + 1] - m_SFBandTable.l[cb]; + n = (r < sampsLeft ? r : sampsLeft); + // n = MIN(fh->sfBand->l[cb + 1] - fh->sfBand->l[cb], sampsLeft); + for (j = 0; j < n; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + } + /* early exit once we've used all the non-zero samples */ + sampsLeft -= n; + if (sampsLeft == 0) break; + } + } else { + /* short or mixed blocks */ + il[12] = 1; + + for (w = 0; w < 3; w++) { + cbStartS = cbi[1].cbEndS[w] + 1; /* start at end of right */ + cbEndS = cbi[0].cbEndS[w] + 1; /* process to end of left */ + i = 3 * m_SFBandTable.s[cbStartS] + w; + + /* skip through sample array by 3, so early-exit logic would be more tricky */ + for (cb = cbStartS; cb < cbEndS; cb++) { + sfIdx = sfis->s[cb][w]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->s[cb][w] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + n = m_SFBandTable.s[cb + 1] - m_SFBandTable.s[cb]; + + for (j = 0; j < n; j++, i += 3) { + xr = MULSHIFT32(fr, x[0][i]) << 2; + x[1][i] = xr; + mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; + x[0][i] = xl; + mOutL |= FASTABS(xl); + } + } + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * I M D C T + */ + +/* + * Function: AntiAlias + * + * Description: smooth transition across DCT block boundaries (every 18 coefficients) + * + * Inputs: vector of dequantized coefficients, length = (nBfly+1) * 18 + * number of "butterflies" to perform (one butterfly means one + * inter-block smoothing operation) + * + * Outputs: updated coefficient vector x + * + * Return: none + * + * Notes: weighted average of opposite bands (pairwise) from the 8 samples + * before and after each block boundary + * nBlocks = (nonZeroBound + 7) / 18, since nZB is the first ZERO sample + * above which all other samples are also zero + * max gain per sample = 1.372 + * MAX(i) (abs(csa[i][0]) + abs(csa[i][1])) + * bits gained = 0 + * assume at least 1 guard bit in x[] to avoid MP3Decoder:: overflow + * (should be guaranteed from dequant, and max gain from stproc * max + * gain from AntiAlias < 2.0) + */ +// a little bit faster in RAM (< 1 ms per block) +/* __attribute__ ((section (".data"))) */ +void MP3Decoder::AntiAlias(int32_t* x, int32_t nBfly) { + int32_t k, a0, b0, c0, c1; + const uint32_t* c; + + /* csa = Q31 */ + for (k = nBfly; k > 0; k--) { + c = csa[0]; + x += 18; + a0 = x[-1]; + c0 = *c; + c++; + b0 = x[0]; + c1 = *c; + c++; + x[-1] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[0] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-2]; + c0 = *c; + c++; + b0 = x[1]; + c1 = *c; + c++; + x[-2] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[1] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-3]; + c0 = *c; + c++; + b0 = x[2]; + c1 = *c; + c++; + x[-3] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[2] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-4]; + c0 = *c; + c++; + b0 = x[3]; + c1 = *c; + c++; + x[-4] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[3] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-5]; + c0 = *c; + c++; + b0 = x[4]; + c1 = *c; + c++; + x[-5] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[4] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-6]; + c0 = *c; + c++; + b0 = x[5]; + c1 = *c; + c++; + x[-6] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[5] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-7]; + c0 = *c; + c++; + b0 = x[6]; + c1 = *c; + c++; + x[-7] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[6] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-8]; + c0 = *c; + c++; + b0 = x[7]; + c1 = *c; + c++; + x[-8] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[7] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: WinPrevious + * + * Description: apply specified window to second half of previous IMDCT (overlap part) + * + * Inputs: vector of 9 coefficients (xPrev) + * + * Outputs: 18 windowed output coefficients (gain 1 integer bit) + * window type (0, 1, 2, 3) + * + * Return: none + * + * Notes: produces 9 output samples from 18 input samples via symmetry + * all blocks gain at least 1 guard bit via window (long blocks get extra + * sign bit, short blocks can have one addition but max gain < 1.0) + */ + +void MP3Decoder::WinPrevious(int32_t* xPrev, int32_t* xPrevWin, int32_t btPrev) { + int32_t i, x, *xp, *xpwLo, *xpwHi, wLo, wHi; + const uint32_t *wpLo, *wpHi; + + xp = xPrev; + /* mapping (see IMDCT12x3): xPrev[0-2] = sum[6-8], xPrev[3-8] = sum[12-17] */ + if (btPrev == 2) { + /* this could be reordered for minimum loads/stores */ + wpLo = imdctWin[btPrev]; + xPrevWin[0] = MULSHIFT32(wpLo[6], xPrev[2]) + MULSHIFT32(wpLo[0], xPrev[6]); + xPrevWin[1] = MULSHIFT32(wpLo[7], xPrev[1]) + MULSHIFT32(wpLo[1], xPrev[7]); + xPrevWin[2] = MULSHIFT32(wpLo[8], xPrev[0]) + MULSHIFT32(wpLo[2], xPrev[8]); + xPrevWin[3] = MULSHIFT32(wpLo[9], xPrev[0]) + MULSHIFT32(wpLo[3], xPrev[8]); + xPrevWin[4] = MULSHIFT32(wpLo[10], xPrev[1]) + MULSHIFT32(wpLo[4], xPrev[7]); + xPrevWin[5] = MULSHIFT32(wpLo[11], xPrev[2]) + MULSHIFT32(wpLo[5], xPrev[6]); + xPrevWin[6] = MULSHIFT32(wpLo[6], xPrev[5]); + xPrevWin[7] = MULSHIFT32(wpLo[7], xPrev[4]); + xPrevWin[8] = MULSHIFT32(wpLo[8], xPrev[3]); + xPrevWin[9] = MULSHIFT32(wpLo[9], xPrev[3]); + xPrevWin[10] = MULSHIFT32(wpLo[10], xPrev[4]); + xPrevWin[11] = MULSHIFT32(wpLo[11], xPrev[5]); + xPrevWin[12] = xPrevWin[13] = xPrevWin[14] = xPrevWin[15] = xPrevWin[16] = xPrevWin[17] = 0; + } else { + /* use ARM-style pointers (*ptr++) so that ADS compiles well */ + wpLo = imdctWin[btPrev] + 18; + wpHi = wpLo + 17; + xpwLo = xPrevWin; + xpwHi = xPrevWin + 17; + for (i = 9; i > 0; i--) { + x = *xp++; + wLo = *wpLo++; + wHi = *wpHi--; + *xpwLo++ = MULSHIFT32(wLo, x); + *xpwHi-- = MULSHIFT32(wHi, x); + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: FreqInvertRescale + * + * Description: do frequency inversion (odd samples of odd blocks) and rescale + * if necessary (extra guard bits added before IMDCT) + * + * Inputs: output vector y (18 new samples, spaced NBANDS apart) + * previous sample vector xPrev (9 samples) + * index of current block + * number of extra shifts added before IMDCT (usually 0) + * + * Outputs: inverted and rescaled (as necessary) outputs + * rescaled (as necessary) previous samples + * + * Return: updated mOut (from new outputs y) + */ + +int32_t MP3Decoder::FreqInvertRescale(int32_t* y, int32_t* xPrev, int32_t blockIdx, int32_t es) { + + if (es == 0) { + /* fast case - frequency invert only (no rescaling) */ + if (blockIdx & 0x01) { + y += NBANDS; + for (int32_t i = 0; i < 9; i++) { + *y = -*y; + y += 2 * NBANDS; + } + } + return 0; + } + + int32_t d, mOut; + /* undo pre-IMDCT scaling, clipping if necessary */ + mOut = 0; + if (blockIdx & 0x01) { + /* frequency invert */ + for (int32_t i = 0; i < 9; i++) { + d = *y; + CLIP_2N(d, (31 - es)); + *y = d << es; + mOut |= FASTABS(*y); + y += NBANDS; + d = -*y; + CLIP_2N(d, (31 - es)); + *y = d << es; + mOut |= FASTABS(*y); + y += NBANDS; + d = *xPrev; + CLIP_2N(d, (31 - es)); + *xPrev++ = d << es; + } + } else { + for (int32_t i = 0; i < 9; i++) { + d = *y; + CLIP_2N(d, (31 - es)); + *y = d << es; + mOut |= FASTABS(*y); + y += NBANDS; + d = *y; + CLIP_2N(d, (31 - es)); + *y = d << es; + mOut |= FASTABS(*y); + y += NBANDS; + d = *xPrev; + CLIP_2N(d, (31 - es)); + *xPrev++ = d << es; + } + } + return mOut; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* require at least 3 guard bits in x[] to ensure no overflow */ +void MP3Decoder::idct9(int32_t* x) { + int32_t a1, a2, a3, a4, a5, a6, a7, a8, a9; + int32_t a10, a11, a12, a13, a14, a15, a16, a17, a18; + int32_t a19, a20, a21, a22, a23, a24, a25, a26, a27; + int32_t m1, m3, m5, m6, m7, m8, m9, m10, m11, m12; + int32_t x0, x1, x2, x3, x4, x5, x6, x7, x8; + + x0 = x[0]; + x1 = x[1]; + x2 = x[2]; + x3 = x[3]; + x4 = x[4]; + x5 = x[5]; + x6 = x[6]; + x7 = x[7]; + x8 = x[8]; + + a1 = x0 - x6; + a2 = x1 - x5; + a3 = x1 + x5; + a4 = x2 - x4; + a5 = x2 + x4; + a6 = x2 + x8; + a7 = x1 + x7; + + a8 = a6 - a5; /* ie x[8] - x[4] */ + a9 = a3 - a7; /* ie x[5] - x[7] */ + a10 = a2 - x7; /* ie x[1] - x[5] - x[7] */ + a11 = a4 - x8; /* ie x[2] - x[4] - x[8] */ + + /* do the << 1 as constant shifts where mX is actually used (free, no stall or extra inst.) */ + m1 = MULSHIFT32(c9_0, x3); + m3 = MULSHIFT32(c9_0, a10); + m5 = MULSHIFT32(c9_1, a5); + m6 = MULSHIFT32(c9_2, a6); + m7 = MULSHIFT32(c9_1, a8); + m8 = MULSHIFT32(c9_2, a5); + m9 = MULSHIFT32(c9_3, a9); + m10 = MULSHIFT32(c9_4, a7); + m11 = MULSHIFT32(c9_3, a3); + m12 = MULSHIFT32(c9_4, a9); + + a12 = x[0] + (x[6] >> 1); + a13 = a12 + (m1 << 1); + a14 = a12 - (m1 << 1); + a15 = a1 + (a11 >> 1); + a16 = (m5 << 1) + (m6 << 1); + a17 = (m7 << 1) - (m8 << 1); + a18 = a16 + a17; + a19 = (m9 << 1) + (m10 << 1); + a20 = (m11 << 1) - (m12 << 1); + + a21 = a20 - a19; + a22 = a13 + a16; + a23 = a14 + a16; + a24 = a14 + a17; + a25 = a13 + a17; + a26 = a14 - a18; + a27 = a13 - a18; + + x0 = a22 + a19; + x[0] = x0; + x1 = a15 + (m3 << 1); + x[1] = x1; + x2 = a24 + a20; + x[2] = x2; + x3 = a26 - a21; + x[3] = x3; + x4 = a1 - a11; + x[4] = x4; + x5 = a27 + a21; + x[5] = x5; + x6 = a25 - a20; + x[6] = x6; + x7 = a15 - (m3 << 1); + x[7] = x7; + x8 = a23 - a19; + x[8] = x8; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IMDCT36 + * + * Description: 36-point modified DCT, with windowing and overlap-add (50% overlap) + * + * Inputs: vector of 18 coefficients (N/2 inputs produces N outputs, by symmetry) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of current and previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: 18 output samples, after windowing and overlap-add with last frame + * second half of (unwindowed) 36-point IMDCT - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Notes: this is Ken's hyper-fast algorithm, including symmetric sin window + * optimization, if applicable + * total number of multiplies, general case: + * 2*10 (idct9) + 9 (last stage imdct) + 36 (for windowing) = 65 + * total number of multiplies, btCurr == 0 && btPrev == 0: + * 2*10 (idct9) + 9 (last stage imdct) + 18 (for windowing) = 47 + * + * blockType == 0 is by far the most common case, so it should be + * possible to use the fast path most of the time + * this is the fastest known algorithm for performing + * long IMDCT + windowing + overlap-add in MP3 + * + * Return: mOut (OR of abs(y) for all y calculated here) + */ +// barely faster in RAM + +int32_t MP3Decoder::IMDCT36(int32_t* xCurr, int32_t* xPrev, int32_t* y, int32_t btCurr, int32_t btPrev, int32_t blockIdx, int32_t gb) { + int32_t i, es, xBuf[18], xPrevWin[18]; + int32_t acc1, acc2, s, d, t, mOut; + int32_t xo, xe, c, *xp, yLo, yHi; + const uint32_t *cp, *wp; + acc1 = acc2 = 0; + xCurr += 17; + /* 7 gb is always adequate for antialias + accumulator loop + idct9 */ + if (gb < 7) { + /* rarely triggered - 5% to 10% of the time on normal clips (with Q25 input) */ + es = 7 - gb; + for (i = 8; i >= 0; i--) { + acc1 = ((*xCurr--) >> es) - acc1; + acc2 = acc1 - acc2; + acc1 = ((*xCurr--) >> es) - acc1; + xBuf[i + 9] = acc2; /* odd */ + xBuf[i + 0] = acc1; /* even */ + xPrev[i] >>= es; + } + } else { + es = 0; + /* max gain = 18, assume adequate guard bits */ + for (i = 8; i >= 0; i--) { + acc1 = (*xCurr--) - acc1; + acc2 = acc1 - acc2; + acc1 = (*xCurr--) - acc1; + xBuf[i + 9] = acc2; /* odd */ + xBuf[i + 0] = acc1; /* even */ + } + } + /* xEven[0] and xOdd[0] scaled by 0.5 */ + xBuf[9] >>= 1; + xBuf[0] >>= 1; + + /* do 9-point IDCT on even and odd */ + idct9(xBuf + 0); /* even */ + idct9(xBuf + 9); /* odd */ + + xp = xBuf + 8; + cp = c18 + 8; + mOut = 0; + if (btPrev == 0 && btCurr == 0) { + /* fast path - use symmetry of sin window to reduce windowing multiplies to 18 (N/2) */ + wp = fastWin36; + for (i = 0; i < 9; i++) { + /* do ARM-style pointer arithmetic (i still needed for y[] indexing - compiler spills if 2 y pointers) */ + c = *cp--; + xo = *(xp + 9); + xe = *xp--; + /* gain 2int32_t bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + s = -(*xPrev); /* sum from last block (always at least 2 guard bits) */ + d = -(xe - xo); /* gain 2int32_t bits, don't shift xo (effective << 1 to eat sign bit, << 1 for mul by 2) */ + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + t = s - d; + + yLo = (d + (MULSHIFT32(t, *wp++) << 2)); + yHi = (s + (MULSHIFT32(t, *wp++) << 2)); + y[(i)*NBANDS] = yLo; + y[(17 - i) * NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } else { + /* slower method - either prev or curr is using window type != 0 so do full 36-point window + * output xPrevWin has at least 3 guard bits (xPrev has 2, gain 1 in WinPrevious) + */ + WinPrevious(xPrev, xPrevWin, btPrev); + + wp = imdctWin[btCurr]; + for (i = 0; i < 9; i++) { + c = *cp--; + xo = *(xp + 9); + xe = *xp--; + /* gain 2int32_t bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + d = xe - xo; + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + + yLo = (xPrevWin[i] + MULSHIFT32(d, wp[i])) << 2; + yHi = (xPrevWin[17 - i] + MULSHIFT32(d, wp[17 - i])) << 2; + y[(i)*NBANDS] = yLo; + y[(17 - i) * NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 12-point inverse DCT, used in IMDCT12x3() + * 4 input guard bits will ensure no overflow + */ +void MP3Decoder::imdct12(int32_t* x, int32_t* out) { + int32_t a0, a1, a2; + int32_t x0, x1, x2, x3, x4, x5; + + x0 = *x; + x += 3; + x1 = *x; + x += 3; + x2 = *x; + x += 3; + x3 = *x; + x += 3; + x4 = *x; + x += 3; + x5 = *x; + x += 3; + + x4 -= x5; + x3 -= x4; + x2 -= x3; + x3 -= x5; + x1 -= x2; + x0 -= x1; + x1 -= x3; + + x0 >>= 1; + x1 >>= 1; + + a0 = MULSHIFT32(c3_0, x2) << 1; + a1 = x0 + (x4 >> 1); + a2 = x0 - x4; + x0 = a1 + a0; + x2 = a2; + x4 = a1 - a0; + + a0 = MULSHIFT32(c3_0, x3) << 1; + a1 = x1 + (x5 >> 1); + a2 = x1 - x5; + + /* cos window odd samples, mul by 2, eat sign bit */ + x1 = MULSHIFT32(c6[0], a1 + a0) << 2; + x3 = MULSHIFT32(c6[1], a2) << 2; + x5 = MULSHIFT32(c6[2], a1 - a0) << 2; + + *out = x0 + x1; + out++; + *out = x2 + x3; + out++; + *out = x4 + x5; + out++; + *out = x4 - x5; + out++; + *out = x2 - x3; + out++; + *out = x0 - x1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IMDCT12x3 + * + * Description: three 12-point modified DCT's for short blocks, with windowing, + * short block concatenation, and overlap-add + * + * Inputs: 3 interleaved vectors of 6 samples each + * (block0[0], block1[0], block2[0], block0[1], block1[1]....) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: updated sample vector x, net gain of 1 integer bit + * second half of (unwindowed) IMDCT's - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Return: mOut (OR of abs(y) for all y calculated here) + */ +// barely faster in RAM +int32_t MP3Decoder::IMDCT12x3(int32_t* xCurr, int32_t* xPrev, int32_t* y, int32_t btPrev, int32_t blockIdx, int32_t gb) { + int32_t i, es, mOut, yLo, xBuf[18], xPrevWin[18]; /* need temp buffer for reordering short blocks */ + const uint32_t* wp; + es = 0; + /* 7 gb is always adequate for accumulator loop + idct12 + window + overlap */ + if (gb < 7) { + es = 7 - gb; + for (i = 0; i < 18; i += 2) { + xCurr[i + 0] >>= es; + xCurr[i + 1] >>= es; + *xPrev++ >>= es; + } + xPrev -= 9; + } + + /* requires 4 input guard bits for each imdct12 */ + imdct12(xCurr + 0, xBuf + 0); + imdct12(xCurr + 1, xBuf + 6); + imdct12(xCurr + 2, xBuf + 12); + + /* window previous from last time */ + WinPrevious(xPrev, xPrevWin, btPrev); + + /* could unroll this for speed, minimum loads (short blocks usually rare, so doesn't make much overall difference) + * xPrevWin[i] << 2 still has 1 gb always, max gain of windowed xBuf stuff also < 1.0 and gain the sign bit + * so y calculations won't overflow + */ + wp = imdctWin[2]; + mOut = 0; + for (i = 0; i < 3; i++) { + yLo = (xPrevWin[0 + i] << 2); + mOut |= FASTABS(yLo); + y[(0 + i) * NBANDS] = yLo; + yLo = (xPrevWin[3 + i] << 2); + mOut |= FASTABS(yLo); + y[(3 + i) * NBANDS] = yLo; + yLo = (xPrevWin[6 + i] << 2) + (MULSHIFT32(wp[0 + i], xBuf[3 + i])); + mOut |= FASTABS(yLo); + y[(6 + i) * NBANDS] = yLo; + yLo = (xPrevWin[9 + i] << 2) + (MULSHIFT32(wp[3 + i], xBuf[5 - i])); + mOut |= FASTABS(yLo); + y[(9 + i) * NBANDS] = yLo; + yLo = (xPrevWin[12 + i] << 2) + (MULSHIFT32(wp[6 + i], xBuf[2 - i]) + MULSHIFT32(wp[0 + i], xBuf[(6 + 3) + i])); + mOut |= FASTABS(yLo); + y[(12 + i) * NBANDS] = yLo; + yLo = (xPrevWin[15 + i] << 2) + (MULSHIFT32(wp[9 + i], xBuf[0 + i]) + MULSHIFT32(wp[3 + i], xBuf[(6 + 5) - i])); + mOut |= FASTABS(yLo); + y[(15 + i) * NBANDS] = yLo; + } + + /* save previous (unwindowed) for overlap - only need samples 6-8, 12-17 */ + for (i = 6; i < 9; i++) *xPrev++ = xBuf[i] >> 2; + for (i = 12; i < 18; i++) *xPrev++ = xBuf[i] >> 2; + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: HybridTransform + * + * Description: IMDCT's, windowing, and overlap-add on long/short/mixed blocks + * + * Inputs: vector of input coefficients, length = nBlocksTotal * 18) + * vector of overlap samples from last time, length = nBlocksPrev * 9) + * buffer for output samples, length = MAXNSAMP + * SideInfoSub struct for this granule/channel + * BlockCount struct with necessary info + * number of non-zero input and overlap blocks + * number of long blocks in input vector (rest assumed to be short blocks) + * number of blocks which use long window (type) 0 in case of mixed block + * (bc->currWinSwitch, 0 for non-mixed blocks) + * + * Outputs: transformed, windowed, and overlapped sample buffer + * does frequency inversion on odd blocks + * updated buffer of samples for overlap + * + * Return: number of non-zero IMDCT blocks calculated in this call + * (including overlap-add) + */ +int32_t MP3Decoder::HybridTransform(int32_t* xCurr, int32_t* xPrev, int32_t y[BLOCK_SIZE][NBANDS], SideInfoSub_t* sis, BlockCount_t* bc) { + int32_t xPrevWin[18], currWinIdx, prevWinIdx; + int32_t i, j, nBlocksOut, nonZero, mOut; + int32_t fiBit, xp; + + assert(bc->nBlocksLong <= NBANDS); + assert(bc->nBlocksTotal <= NBANDS); + assert(bc->nBlocksPrev <= NBANDS); + + mOut = 0; + + /* do long blocks, if any */ + for (i = 0; i < bc->nBlocksLong; i++) { + /* currWinIdx picks the right window for long blocks (if mixed, long blocks use window type 0) */ + currWinIdx = sis->blockType; + if (sis->mixedBlock && i < bc->currWinSwitch) currWinIdx = 0; + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) prevWinIdx = 0; + + /* do 36-point IMDCT, including windowing and overlap-add */ + mOut |= IMDCT36(xCurr, xPrev, &(y[0][i]), currWinIdx, prevWinIdx, i, bc->gbIn); + xCurr += 18; + xPrev += 9; + } + + /* do short blocks (if any) */ + for (; i < bc->nBlocksTotal; i++) { + assert(sis->blockType == 2); + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) prevWinIdx = 0; + + mOut |= IMDCT12x3(xCurr, xPrev, &(y[0][i]), prevWinIdx, i, bc->gbIn); + xCurr += 18; + xPrev += 9; + } + nBlocksOut = i; + + /* window and overlap prev if prev longer that current */ + for (; i < bc->nBlocksPrev; i++) { + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) prevWinIdx = 0; + WinPrevious(xPrev, xPrevWin, prevWinIdx); + + nonZero = 0; + fiBit = i << 31; + for (j = 0; j < 9; j++) { + xp = xPrevWin[2 * j + 0] << 2; /* << 2 temp for scaling */ + nonZero |= xp; + y[2 * j + 0][i] = xp; + mOut |= FASTABS(xp); + + /* frequency inversion on odd blocks/odd samples (flip sign if i odd, j odd) */ + xp = xPrevWin[2 * j + 1] << 2; + xp = (xp ^ (fiBit >> 31)) + (i & 0x01); + nonZero |= xp; + y[2 * j + 1][i] = xp; + mOut |= FASTABS(xp); + + xPrev[j] = 0; + } + xPrev += 9; + if (nonZero) nBlocksOut = i; + } + + /* clear rest of blocks */ + for (; i < 32; i++) { + for (j = 0; j < 18; j++) y[j][i] = 0; + } + + bc->gbOut = CLZ(mOut) - 1; + + return nBlocksOut; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: IMDCT + * + * Description: do alias reduction, inverse MDCT, overlap-add, and frequency inversion + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * UnpackScaleFactors(), and DecodeHuffman() (for this granule, channel) + * includes PCM samples in overBuf (from last call to IMDCT) for OLA + * index of current granule and channel + * + * Outputs: PCM samples in outBuf, for input to subband transform + * PCM samples in overBuf, for OLA next time + * updated hi->nonZeroBound index for this channel + * + * Return: 0 on success, -1 if null input pointers + */ +// a bit faster in RAM +/*__attribute__ ((section (".data")))*/ +int32_t MP3Decoder::IMDCT(int32_t gr, int32_t ch) { + int32_t nBfly, blockCutoff; + BlockCount_t bc; + + /* m_SideInfo is an array of up to 4 structs, stored as gr0ch0, gr0ch1, gr1ch0, gr1ch1 */ + /* anti-aliasing done on whole long blocks only + * for mixed blocks, nBfly always 1, except 3 for 8 kHz MPEG 2.5 (see sfBandTab) + * nLongBlocks = number of blocks with (possibly) non-zero power + * nBfly = number of butterflies to do (nLongBlocks - 1, unless no long blocks) + */ + blockCutoff = m_SFBandTable.l[(m_MPEGVersion == MPEG1 ? 8 : 6)] / 18; /* same as 3* num short sfb's in spec */ + if (m_SideInfoSub[gr][ch].blockType != 2) { + /* all long transforms */ + int32_t x = (m_HuffmanInfo->nonZeroBound[ch] + 7) / 18 + 1; + bc.nBlocksLong = (x < 32 ? x : 32); + // bc.nBlocksLong = min((hi->nonZeroBound[ch] + 7) / 18 + 1, 32); + nBfly = bc.nBlocksLong - 1; + } else if (m_SideInfoSub[gr][ch].blockType == 2 && m_SideInfoSub[gr][ch].mixedBlock) { + /* mixed block - long transforms until cutoff, then short transforms */ + bc.nBlocksLong = blockCutoff; + nBfly = bc.nBlocksLong - 1; + } else { + /* all short transforms */ + bc.nBlocksLong = 0; + nBfly = 0; + } + + AntiAlias(m_HuffmanInfo->huffDecBuf[ch], nBfly); + int32_t x = m_HuffmanInfo->nonZeroBound[ch]; + int32_t y = nBfly * 18 + 8; + m_HuffmanInfo->nonZeroBound[ch] = (x > y ? x : y); + + assert(m_HuffmanInfo->nonZeroBound[ch] <= MAX_NSAMP); + + /* for readability, use a struct instead of passing a million parameters to HybridTransform() */ + bc.nBlocksTotal = (m_HuffmanInfo->nonZeroBound[ch] + 17) / 18; + bc.nBlocksPrev = m_IMDCTInfo->numPrevIMDCT[ch]; + bc.prevType = m_IMDCTInfo->prevType[ch]; + bc.prevWinSwitch = m_IMDCTInfo->prevWinSwitch[ch]; + /* where WINDOW switches (not nec. transform) */ + bc.currWinSwitch = (m_SideInfoSub[gr][ch].mixedBlock ? blockCutoff : 0); + bc.gbIn = m_HuffmanInfo->gb[ch]; + + m_IMDCTInfo->numPrevIMDCT[ch] = HybridTransform(m_HuffmanInfo->huffDecBuf[ch], m_IMDCTInfo->overBuf[ch], m_IMDCTInfo->outBuf[ch], &m_SideInfoSub[gr][ch], &bc); + m_IMDCTInfo->prevType[ch] = m_SideInfoSub[gr][ch].blockType; + m_IMDCTInfo->prevWinSwitch[ch] = bc.currWinSwitch; /* 0 means not a mixed block (either all short or all long) */ + m_IMDCTInfo->gb[ch] = bc.gbOut; + + assert(m_IMDCTInfo->numPrevIMDCT[ch] <= NBANDS); + + /* output has gained 2int32_t bits */ + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * S U B B A N D + */ + +/* + * Function: Subband + * + * Description: do subband transform on all the blocks in one granule, all channels + * + * Inputs: filled MP3DecInfo structure, after calling IMDCT for all channels + * vbuf[ch] and vindex[ch] must be preserved between calls + * + * Outputs: decoded PCM data, interleaved LRLRLR... if stereo + * + * Return: 0 on success, -1 if null input pointers + */ +int32_t MP3Decoder::Subband(int16_t* pcmBuf) { + int32_t b; + if (m_MP3DecInfo->nChans == 2) { + /* stereo */ + for (b = 0; b < BLOCK_SIZE; b++) { + FDCT32(m_IMDCTInfo->outBuf[0][b], m_SubbandInfo->vbuf + 0 * 32, m_SubbandInfo->vindex, (b & 0x01), m_IMDCTInfo->gb[0]); + FDCT32(m_IMDCTInfo->outBuf[1][b], m_SubbandInfo->vbuf + 1 * 32, m_SubbandInfo->vindex, (b & 0x01), m_IMDCTInfo->gb[1]); + PolyphaseStereo(pcmBuf, m_SubbandInfo->vbuf + m_SubbandInfo->vindex + VBUF_LENGTH * (b & 0x01), polyCoef); + m_SubbandInfo->vindex = (m_SubbandInfo->vindex - (b & 0x01)) & 7; + pcmBuf += (2 * NBANDS); + } + } else { + /* mono */ + for (b = 0; b < BLOCK_SIZE; b++) { + FDCT32(m_IMDCTInfo->outBuf[0][b], m_SubbandInfo->vbuf + 0 * 32, m_SubbandInfo->vindex, (b & 0x01), m_IMDCTInfo->gb[0]); + PolyphaseMono(pcmBuf, m_SubbandInfo->vbuf + m_SubbandInfo->vindex + VBUF_LENGTH * (b & 0x01), polyCoef); + m_SubbandInfo->vindex = (m_SubbandInfo->vindex - (b & 0x01)) & 7; + pcmBuf += NBANDS; + } + } + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void MP3Decoder::FDCT32(int32_t* buf, int32_t* dest, int32_t offset, int32_t oddBlock, int32_t gb) { + int32_t i, s, tmp, es; + const int32_t* cptr = (const int32_t*)m_dcttab; + int32_t a0, a1, a2, a3, a4, a5, a6, a7; + int32_t b0, b1, b2, b3, b4, b5, b6, b7; + int32_t* d; + + /* scaling - ensure at least 6 guard bits for DCT + * (in practice this is already true 99% of time, so this code is + * almost never triggered) + */ + es = 0; + if (gb < 6) { + es = 6 - gb; + for (i = 0; i < 32; i++) buf[i] >>= es; + } + + /* first pass */ + for (unsigned i = 0; i < 8; i++) { D32FP(i, FDCT32s1s2[0 + i], FDCT32s1s2[8 + i]); } + + /* second pass */ + for (i = 4; i > 0; i--) { + a0 = buf[0]; + a7 = buf[7]; + a3 = buf[3]; + a4 = buf[4]; + b0 = a0 + a7; + b7 = MULSHIFT32(*cptr++, a0 - a7) << 1; + b3 = a3 + a4; + b4 = MULSHIFT32(*cptr++, a3 - a4) << 3; + a0 = b0 + b3; + a3 = MULSHIFT32(*cptr, b0 - b3) << 1; + a4 = b4 + b7; + a7 = MULSHIFT32(*cptr++, b7 - b4) << 1; + + a1 = buf[1]; + a6 = buf[6]; + a2 = buf[2]; + a5 = buf[5]; + b1 = a1 + a6; + b6 = MULSHIFT32(*cptr++, a1 - a6) << 1; + b2 = a2 + a5; + b5 = MULSHIFT32(*cptr++, a2 - a5) << 1; + a1 = b1 + b2; + a2 = MULSHIFT32(*cptr, b1 - b2) << 2; + a5 = b5 + b6; + a6 = MULSHIFT32(*cptr++, b6 - b5) << 2; + + b0 = a0 + a1; + b1 = MULSHIFT32(m_COS4_0, a0 - a1) << 1; + b2 = a2 + a3; + b3 = MULSHIFT32(m_COS4_0, a3 - a2) << 1; + buf[0] = b0; + buf[1] = b1; + buf[2] = b2 + b3; + buf[3] = b3; + + b4 = a4 + a5; + b5 = MULSHIFT32(m_COS4_0, a4 - a5) << 1; + b6 = a6 + a7; + b7 = MULSHIFT32(m_COS4_0, a7 - a6) << 1; + b6 += b7; + buf[4] = b4 + b6; + buf[5] = b5 + b7; + buf[6] = b5 + b6; + buf[7] = b7; + + buf += 8; + } + buf -= 32; /* reset */ + + /* sample 0 - always delayed one block */ + d = dest + 64 * 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + s = buf[0]; + d[0] = d[8] = s; + + /* samples 16 to 31 */ + d = dest + offset + (oddBlock ? VBUF_LENGTH : 0); + + s = buf[1]; + d[0] = d[8] = s; + d += 64; + + tmp = buf[25] + buf[29]; + s = buf[17] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[9] + buf[13]; + d[0] = d[8] = s; + d += 64; + s = buf[21] + tmp; + d[0] = d[8] = s; + d += 64; + + tmp = buf[29] + buf[27]; + s = buf[5]; + d[0] = d[8] = s; + d += 64; + s = buf[21] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[13] + buf[11]; + d[0] = d[8] = s; + d += 64; + s = buf[19] + tmp; + d[0] = d[8] = s; + d += 64; + + tmp = buf[27] + buf[31]; + s = buf[3]; + d[0] = d[8] = s; + d += 64; + s = buf[19] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[11] + buf[15]; + d[0] = d[8] = s; + d += 64; + s = buf[23] + tmp; + d[0] = d[8] = s; + d += 64; + + tmp = buf[31]; + s = buf[7]; + d[0] = d[8] = s; + d += 64; + s = buf[23] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[15]; + d[0] = d[8] = s; + d += 64; + s = tmp; + d[0] = d[8] = s; + + /* samples 16 to 1 (sample 16 used again) */ + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + + s = buf[1]; + d[0] = d[8] = s; + d += 64; + + tmp = buf[30] + buf[25]; + s = buf[17] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[14] + buf[9]; + d[0] = d[8] = s; + d += 64; + s = buf[22] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[6]; + d[0] = d[8] = s; + d += 64; + + tmp = buf[26] + buf[30]; + s = buf[22] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[10] + buf[14]; + d[0] = d[8] = s; + d += 64; + s = buf[18] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[2]; + d[0] = d[8] = s; + d += 64; + + tmp = buf[28] + buf[26]; + s = buf[18] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[12] + buf[10]; + d[0] = d[8] = s; + d += 64; + s = buf[20] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[4]; + d[0] = d[8] = s; + d += 64; + + tmp = buf[24] + buf[28]; + s = buf[20] + tmp; + d[0] = d[8] = s; + d += 64; + s = buf[8] + buf[12]; + d[0] = d[8] = s; + d += 64; + s = buf[16] + tmp; + d[0] = d[8] = s; + + /* this is so rarely invoked that it's not worth making two versions of the output + * shuffle code (one for no shift, one for clip + variable shift) like in IMDCT + * here we just load, clip, shift, and store on the rare instances that es != 0 + */ + if (es) { + d = dest + 64 * 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + s = d[0]; + CLIP_2N(s, (31 - es)); + d[0] = d[8] = (s << es); + + d = dest + offset + (oddBlock ? VBUF_LENGTH : 0); + for (i = 16; i <= 31; i++) { + s = d[0]; + CLIP_2N(s, (31 - es)); + d[0] = d[8] = (s << es); + d += 64; + } + + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + for (i = 15; i >= 0; i--) { + s = d[0]; + CLIP_2N(s, (31 - es)); + d[0] = d[8] = (s << es); + d += 64; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * P O L Y P H A S E + */ +int16_t MP3Decoder::ClipToShort(int32_t x, int32_t fracBits) { +#if (defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32S3) + /* assumes you've already rounded (x += (1 << (fracBits-1))) */ + x >>= fracBits; + // this is better on xtensa (fb) + asm("clamps %0, %1, 15" : "=a"(x) : "a"(x) :); + return x; +#endif + +#if (defined CONFIG_IDF_TARGET_ESP32P4) + int32_t sign; + + /* assumes you've already rounded (x += (1 << (fracBits-1))) */ + x >>= fracBits; + + /* Ken's trick: clips to [-32768, 32767] */ + sign = x >> 31; + if (sign != (x >> 15)) { x = sign ^ ((1 << 15) - 1); } + + return (int16_t)x; +#endif +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: PolyphaseMono + * + * Description: filter one subband and produce 32 output PCM samples for one channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of one channel of decoded PCM data, (i.e. Q16.0) + * + * Return: none + */ +void MP3Decoder::PolyphaseMono(int16_t* pcm, int32_t* vbuf, const uint32_t* coefBase) { + int32_t i; + const uint32_t* coef; + int32_t* vb1; + int32_t vLo, vHi, c1, c2; + uint64_t sum1L, sum2L, rndVal; + + rndVal = (uint64_t)(1ULL << ((DQ_FRACBITS_OUT - 2 - 2 - 15) - 1 + (32 - CSHIFT))); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = rndVal; + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + c2 = *coef; + coef++; + vLo = *(vb1 + (j)); + vHi = *(vb1 + (23 - (j))); // 0...7 + sum1L = MADD64(sum1L, vLo, c1); + sum1L = MADD64(sum1L, vHi, -c2); + } + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64 * 16; + sum1L = rndVal; + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + vLo = *(vb1 + (j)); + sum1L = MADD64(sum1L, vLo, c1); // 0...7 + } + *(pcm + 16) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm++; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + c2 = *coef; + coef++; + vLo = *(vb1 + (j)); + vHi = *(vb1 + (23 - (j))); + sum1L = MADD64(sum1L, vLo, c1); + sum2L = MADD64(sum2L, vLo, c2); + sum1L = MADD64(sum1L, vHi, -c2); + sum2L = MADD64(sum2L, vHi, c1); + } + vb1 += 64; + *(pcm) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2 * i) = ClipToShort((int32_t)SAR64(sum2L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + pcm++; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: PolyphaseStereo + * + * Description: filter one subband and produce 32 output PCM samples for each channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of two channels of decoded PCM data, (i.e. Q16.0) + * + * Return: none + * + * Notes: interleaves PCM samples LRLRLR... + */ +void MP3Decoder::PolyphaseStereo(int16_t* pcm, int32_t* vbuf, const uint32_t* coefBase) { + int32_t i; + const uint32_t* coef; + int32_t* vb1; + int32_t vLo, vHi, c1, c2; + uint64_t sum1L, sum2L, sum1R, sum2R, rndVal; + + rndVal = (uint64_t)(1 << ((DQ_FRACBITS_OUT - 2 - 2 - 15) - 1 + (32 - CSHIFT))); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = sum1R = rndVal; + + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + c2 = *coef; + coef++; + vLo = *(vb1 + (j)); + vHi = *(vb1 + (23 - (j))); + sum1L = MADD64(sum1L, vLo, c1); + sum1L = MADD64(sum1L, vHi, -c2); + vLo = *(vb1 + 32 + (j)); + vHi = *(vb1 + 32 + (23 - (j))); + sum1R = MADD64(sum1R, vLo, c1); + sum1R = MADD64(sum1R, vHi, -c2); + } + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 1) = ClipToShort((int32_t)SAR64(sum1R, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64 * 16; + sum1L = sum1R = rndVal; + + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + vLo = *(vb1 + (j)); + sum1L = MADD64(sum1L, vLo, c1); + vLo = *(vb1 + 32 + (j)); + sum1R = MADD64(sum1R, vLo, c1); + } + *(pcm + 2 * 16 + 0) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2 * 16 + 1) = ClipToShort((int32_t)SAR64(sum1R, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm += 2; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + sum1R = sum2R = rndVal; + + for (int32_t j = 0; j < 8; j++) { + c1 = *coef; + coef++; + c2 = *coef; + coef++; + vLo = *(vb1 + (j)); + vHi = *(vb1 + (23 - (j))); + sum1L = MADD64(sum1L, vLo, c1); + sum2L = MADD64(sum2L, vLo, c2); + sum1L = MADD64(sum1L, vHi, -c2); + sum2L = MADD64(sum2L, vHi, c1); + vLo = *(vb1 + 32 + (j)); + vHi = *(vb1 + 32 + (23 - (j))); + sum1R = MADD64(sum1R, vLo, c1); + sum2R = MADD64(sum2R, vLo, c2); + sum1R = MADD64(sum1R, vHi, -c2); + sum2R = MADD64(sum2R, vHi, c1); + } + vb1 += 64; + *(pcm + 0) = ClipToShort((int32_t)SAR64(sum1L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 1) = ClipToShort((int32_t)SAR64(sum1R, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2 * 2 * i + 0) = ClipToShort((int32_t)SAR64(sum2L, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + *(pcm + 2 * 2 * i + 1) = ClipToShort((int32_t)SAR64(sum2R, (32 - CSHIFT)), DQ_FRACBITS_OUT - 2 - 2 - 15); + pcm += 2; + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* + * Function: AnalyzeFrame + * + * Description: filter one subband and produce 32 output PCM samples for each channel + * + * Inputs: pointer to inpit buffer and length + * + * Outputs: MPEG_VERSION + * LAYER + * CHANNEL_MODE + * + * Return: main_data_begin + * + */ +int MP3Decoder::MP3_AnalyzeFrame(const uint8_t* frame_data, size_t frame_len) { + if (frame_len < 4) { + MP3_LOG_ERROR("Error: Frame data too short for header (need 4 bytes, got {}).", frame_len); + return -3; // Frame too short for header + } + + // Define constants for better readability + const uint8_t MPEG_VERSION_2_5 = 0; // 00 - unofficial, but often so coded + const uint8_t MPEG_VERSION_RESERVED = 1; // 01 + const uint8_t MPEG_VERSION_2 = 2; // 10 + const uint8_t MPEG_VERSION_1 = 3; // 11 + + const uint8_t LAYER_RESERVED = 0; // 00 + const uint8_t LAYER_III = 1; // 01 + const uint8_t LAYER_II = 2; // 10 + const uint8_t LAYER_I = 3; // 11 + + const uint8_t CHANNEL_MODE_STEREO = 0; // 00 + const uint8_t CHANNEL_MODE_JOINT_STEREO = 1; // 01 + const uint8_t CHANNEL_MODE_DUAL_CHANNEL = 2; // 10 + const uint8_t CHANNEL_MODE_MONO = 3; // 11 + + (void)MPEG_VERSION_RESERVED; + (void)LAYER_III; + (void)LAYER_II; + (void)LAYER_I; + (void)CHANNEL_MODE_STEREO; + (void)CHANNEL_MODE_JOINT_STEREO; + (void)CHANNEL_MODE_DUAL_CHANNEL; + (void)LAYER_RESERVED; + + // ---- 1. Analyze frame header (first 4 bytes) --- + // combine the first 4 bytes into a 32-bit integer (Big Endian) + uint32_t header = ((uint32_t)frame_data[0] << 24) | ((uint32_t)frame_data[1] << 16) | ((uint32_t)frame_data[2] << 8) | ((uint32_t)frame_data[3]); + + // check sync word (first 11 bits must be 1) + // MPEG 2.5 Layer III often uses 12 bits (0xfff), other 11 bits (0xffe) + // simple check: data [0] == 0xff and (data [1] & 0xe0) == 0xe0 + if (!(frame_data[0] == 0xFF && (frame_data[1] & 0xE0) == 0xE0)) { + MP3_LOG_ERROR("Error: Invalid MP3 sync word."); + return -4; + } + + // MPEG version ID (Bits 11-12 of the header, or Bits 19-20 from right in the Uint32_t) + // Header: SSSS SSSS SSSV Vllp PBBB BFFM MCCE (S = Sync, V = version, L = layer, p = Protection ...) + // In our `Header` Uint32_t: + // Bit 31..21: Sync word (11 bits) + // Bit 20..19: MPEG Audio version ID + // Bit 18..17: Layer description + // Bit 16: Protection bit + // Bit 15..12: Bitrate index + // Bit 11..10: Sampling rate frequency index + // Bit 9: Padding bit + // Bit 8: Private bit + // Bit 7..6: Channel mode + // Bit 5..4: Mode extension (for Joint Stereo) + // Bit 3: Copyright + // Bit 2: Original + // Bit 1..0: Emphasis + + uint8_t mpeg_version_id = (header >> 19) & 0x03; + uint8_t layer_description = (header >> 17) & 0x03; + uint8_t protection_bit = (header >> 16) & 0x01; + uint8_t channel_mode = (header >> 6) & 0x03; + + // Debug output(optional) + // MP3_LOG_DEBUG("MPEG Version ID raw: {}", mpeg_version_id); + // MP3_LOG_DEBUG("Layer Description raw: {}", layer_description); + // MP3_LOG_DEBUG("Protection Bit: {}", protection_bit); + // MP3_LOG_DEBUG("Channel Mode raw: {}", channel_mode); + + // --- 2. Check whether it is Layer III --- + if (layer_description != LAYER_III) { + // MP3_LOG_DEBUG("Info: Not an MPEG Layer III frame (Layer: {}).", layer_description); + return -1; // no Layer III + } + + // --- 3. Side Information, Determine offset and size --- + int side_info_offset = 4; // after the 4-Byte Header + if (protection_bit == 0) { // 0 means CRC is available + side_info_offset += 2; // Skip 16-bit CRC + } + + int side_info_size; + (void)side_info_size; + // Derive MPEG versions from the ID (according to ISO/IEC 13818-3 Table B.1) + // ID '00' -> MPEG 2.5 + // ID '01' -> reserved + // ID '10' -> MPEG 2 + // ID '11' -> MPEG 1 + if (mpeg_version_id == MPEG_VERSION_1) { // MPEG-1 + if (channel_mode == CHANNEL_MODE_MONO) { + side_info_size = 17; // Mono + } else { + side_info_size = 32; // Stereo, Joint Stereo, Dual Channel + } + } else if (mpeg_version_id == MPEG_VERSION_2 || mpeg_version_id == MPEG_VERSION_2_5) { // MPEG-2 oder MPEG-2.5 + if (channel_mode == CHANNEL_MODE_MONO) { + side_info_size = 9; // Mono + } else { + side_info_size = 17; // Stereo, Joint Stereo, Dual Channel + } + } else { + MP3_LOG_ERROR("Error: Reserved or unknown MPEG version ID: {}", mpeg_version_id); + return -2; // Unknown/reserved MPEG version + } + + // ensure that the frame is long enough for the side information + // We need at least 2 bytes of the side info for Main_data_begin + if (frame_len < (size_t)(side_info_offset + 2)) { + MP3_LOG_ERROR("Error: Frame data too short for side information (need {} bytes, got {}).", side_info_offset + 2, frame_len); + return -3; + } + // (optional) Check whether the entire Side Information is available + /* + if (frame_len < (size_t)(side_info_offset + side_info_size)) { + MP3_LOG_ERROR("Warning: Frame data might be too short for full side information (expected {}, got {} available after header/CRC).", side_info_size, frame_len - side_info_offset); + // Fortfahren, da main_data_begin am Anfang ist, aber es ist ein Hinweis + } + */ + + // --- 4. Main_data_begin extract from the Side Information --- + // Main_data_begin are the first 9 bits of the Side Information + // Side information begins with frame_data [side_info_offset] + const uint8_t* side_info_ptr = frame_data + side_info_offset; + + // The 9 bits consist of: + // - the complete 8 bits of the first bytes of the Side Information + // - the MSB (highest quality bit) of the second bytes of the Side Information + uint16_t main_data_begin_val = ((uint16_t)side_info_ptr[0] << 1) | (side_info_ptr[1] >> 7); + + return main_data_begin_val; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint64_t MP3Decoder::SAR64(uint64_t x, int32_t n) { + return x >> n; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::MULSHIFT32(int32_t x, int32_t y) { + int32_t z; + z = (uint64_t)x * (uint64_t)y >> 32; + return z; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint64_t MP3Decoder::MADD64(uint64_t sum64, int32_t x, int32_t y) { + sum64 += (uint64_t)x * (uint64_t)y; + return sum64; +} /* returns 64-bit value in [edx:eax] */ +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint64_t MP3Decoder::xSAR64(uint64_t x, int32_t n) { + return x >> n; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t MP3Decoder::FASTABS(int32_t x) { + return __builtin_abs(x); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.h b/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.h new file mode 100644 index 0000000..39bf9df --- /dev/null +++ b/libraries/ESP32-audioI2S/src/mp3_decoder/mp3_decoder.h @@ -0,0 +1,123 @@ +// based om helix mp3 decoder +#pragma once + +#include "../Audio.h" +#include "structs.h" +#include "tables.h" + +class MP3Decoder : public Decoder { + + public: + MP3Decoder(Audio& audioRef) : Decoder(audioRef), audio(audioRef) {} + ~MP3Decoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; // MPEG Version and Layer + const char* arg2() override; + virtual int32_t val1() override; + virtual int32_t val2() override; + + enum { + MP3_NONE = 0, + MP3_ERR = -1, + MP3_MAIN_DATA_UNDERFLOW = -2, + MP3_NEED_RESTART = -3, + MP3_STOP = -100, + MP3_NEXT_FRAME = 100, + }; + + private: + Audio& audio; + + SFBandTable_t m_SFBandTable; + StereoMode_t m_sMode; /* mono/stereo mode */ + MPEGVersion_t m_MPEGVersion; /* version ID */ + SideInfoSub_t m_SideInfoSub[MAX_NGRAN][MAX_NCHAN]; + CriticalBandInfo_t m_CriticalBandInfo[MAX_NCHAN]; /* filled in dequantizer, used in joint stereo reconstruction */ + ScaleFactorInfoSub_t m_ScaleFactorInfoSub[MAX_NGRAN][MAX_NCHAN]; + + ps_ptr m_MP3DecInfo; + ps_ptr m_FrameHeader; + ps_ptr m_SideInfo; + ps_ptr m_ScaleFactorJS; + ps_ptr m_HuffmanInfo; + ps_ptr m_DequantInfo; + ps_ptr m_IMDCTInfo; + ps_ptr m_SubbandInfo; + ps_ptr m_MP3FrameInfo; + ps_ptr m_mpeg_version_str; + ps_ptr m_out16; + + invalid_frame m_invalid_frame; + + // internally used + int32_t IsLikelyRealFrame(const uint8_t* p, int32_t bytesLeft); + void MP3GetLastFrameInfo(); + int32_t MP3GetNextFrameInfo(uint8_t* buf); + int MP3_AnalyzeFrame(const uint8_t* frame_data, size_t frame_len); + void PolyphaseMono(int16_t* pcm, int32_t* vbuf, const uint32_t* coefBase); + void PolyphaseStereo(int16_t* pcm, int32_t* vbuf, const uint32_t* coefBase); + void SetBitstreamPointer(BitStreamInfo_t* bsi, int32_t nBytes, uint8_t* buf); + uint32_t GetBits(BitStreamInfo_t* bsi, int32_t nBits); + int32_t CalcBitsUsed(BitStreamInfo_t* bsi, uint8_t* startBuf, int32_t startOffset); + int32_t DequantChannel(int32_t* sampleBuf, int32_t* workBuf, int32_t* nonZeroBound, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi); + void MidSideProc(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, int32_t mOut[2]); + void IntensityProcMPEG1(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi, int32_t midSideFlag, int32_t mixFlag, int32_t mOut[2]); + void IntensityProcMPEG2(int32_t x[MAX_NCHAN][MAX_NSAMP], int32_t nSamps, ScaleFactorInfoSub_t* sfis, CriticalBandInfo_t* cbi, ScaleFactorJS_t* sfjs, int32_t midSideFlag, int32_t mixFlag, + int32_t mOut[2]); + void FDCT32(int32_t* x, int32_t* d, int32_t offset, int32_t oddBlock, int32_t gb); // __attribute__ ((section (".data"))); + int32_t CheckPadBit(); + int32_t UnpackFrameHeader(uint8_t* buf); + int32_t UnpackSideInfo(uint8_t* buf); + int32_t DecodeHuffman(uint8_t* buf, int32_t* bitOffset, int32_t huffBlockBits, int32_t gr, int32_t ch); + int32_t MP3Dequantize(int32_t gr); + int32_t IMDCT(int32_t gr, int32_t ch); + int32_t UnpackScaleFactors(uint8_t* buf, int32_t* bitOffset, int32_t bitsAvail, int32_t gr, int32_t ch); + int32_t Subband(int16_t* pcmBuf); + int16_t ClipToShort(int32_t x, int32_t fracBits); + void RefillBitstreamCache(BitStreamInfo_t* bsi); + void UnpackSFMPEG1(BitStreamInfo_t* bsi, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, int32_t* scfsi, int32_t gr, ScaleFactorInfoSub_t* sfisGr0); + void UnpackSFMPEG2(BitStreamInfo_t* bsi, SideInfoSub_t* sis, ScaleFactorInfoSub_t* sfis, int32_t gr, int32_t ch, int32_t modeExt, ScaleFactorJS_t* sfjs); + int32_t MP3FindFreeSync(uint8_t* buf, uint8_t firstFH[4], int32_t nBytes); + void MP3ClearBadFrame(int16_t* outbuf); + int32_t DecodeHuffmanPairs(int32_t* xy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t* buf, int32_t bitOffset); + int32_t DecodeHuffmanQuads(int32_t* vwxy, int32_t nVals, int32_t tabIdx, int32_t bitsLeft, uint8_t* buf, int32_t bitOffset); + int32_t DequantBlock(int32_t* inbuf, int32_t* outbuf, int32_t num, int32_t scale); + void AntiAlias(int32_t* x, int32_t nBfly); + void WinPrevious(int32_t* xPrev, int32_t* xPrevWin, int32_t btPrev); + int32_t FreqInvertRescale(int32_t* y, int32_t* xPrev, int32_t blockIdx, int32_t es); + void idct9(int32_t* x); + int32_t IMDCT36(int32_t* xCurr, int32_t* xPrev, int32_t* y, int32_t btCurr, int32_t btPrev, int32_t blockIdx, int32_t gb); + void imdct12(int32_t* x, int32_t* out); + int32_t IMDCT12x3(int32_t* xCurr, int32_t* xPrev, int32_t* y, int32_t btPrev, int32_t blockIdx, int32_t gb); + int32_t HybridTransform(int32_t* xCurr, int32_t* xPrev, int32_t y[BLOCK_SIZE][NBANDS], SideInfoSub_t* sis, BlockCount_t* bc); + uint64_t SAR64(uint64_t x, int32_t n); + int32_t MULSHIFT32(int32_t x, int32_t y); + uint64_t MADD64(uint64_t sum64, int32_t x, int32_t y); /* returns 64-bit value in [edx:eax] */ + uint64_t xSAR64(uint64_t x, int32_t n); + int32_t FASTABS(int32_t x); // xtensa has a fast abs instruction //fb + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// Macro for comfortable calls +#define MP3_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define MP3_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define MP3_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define MP3_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define MP3_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/mp3_decoder/structs.h b/libraries/ESP32-audioI2S/src/mp3_decoder/structs.h new file mode 100644 index 0000000..06b7be0 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/mp3_decoder/structs.h @@ -0,0 +1,233 @@ +#pragma once + +#include "stdint-gcc.h" + +#define SYNCWORDH 0xFF +#define SYNCWORDL 0xE0 +#define DQ_FRACBITS_OUT 25 // number of fraction bits in output of dequant +#define CSHIFT 12 // coefficients have 12 leading sign bits for early-terminating mulitplies +#define SIBYTES_MPEG1_MONO 17 +#define SIBYTES_MPEG1_STEREO 32 +#define SIBYTES_MPEG2_MONO 9 +#define SIBYTES_MPEG2_STEREO 17 +#define IMDCT_SCALE 2 // additional scaling (by sqrt(2)) for fast IMDCT36 +#define NGRANS_MPEG1 2 +#define NGRANS_MPEG2 1 +#define SQRTHALF 0x5a82799a // sqrt(0.5) in Q31 format +#define MAX_NGRAN 2 /* max granules */ +#define MAX_NCHAN 2 /* max channels */ +#define MAX_NSAMP 576 /* max samples per channel, per granule */ +#define MAX_SCFBD 4 /* max scalefactor bands per channel */ +#define NGRANS_MPEG1 2 +#define NGRANS_MPEG2 1 +#define HUFF_PAIRTABS 32 +#define BLOCK_SIZE 18 +#define NBANDS 32 +#define MAX_REORDER_SAMPS (192 - 126) * 3 // largest critical band for short blocks (see sfBandTable) +#define VBUF_LENGTH 17 * 2 * NBANDS // for double-sized vbuf FIFO +#define MAX_SCFBD 4 // max scalefactor bands per channel +#define MAINBUF_SIZE 1940 +#define MAX_NGRAN 2 // max granules +#define MAX_NCHAN 2 // max channels +#define MAX_NSAMP 576 // max samples per channel, per granule +#define CLZ(x) __builtin_clz(x) // fb + +#define CLIP_2N(y, n) \ + { \ + int32_t x = 1 << n; \ + if (y < -x) y = -x; \ + x--; \ + if (y > x) y = x; \ + } + +#define D32FP(i, s1, s2) \ + { \ + a0 = buf[i]; \ + a3 = buf[31 - i]; \ + a1 = buf[15 - i]; \ + a2 = buf[16 + i]; \ + b0 = a0 + a3; \ + b3 = MULSHIFT32(*cptr++, a0 - a3) << 1; \ + b1 = a1 + a2; \ + b2 = MULSHIFT32(*cptr++, a1 - a2) << (s1); \ + buf[i] = b0 + b1; \ + buf[15 - i] = MULSHIFT32(*cptr, b0 - b1) << (s2); \ + buf[16 + i] = b2 + b3; \ + buf[31 - i] = MULSHIFT32(*cptr++, b3 - b2) << (s2); \ + } + + +typedef struct MP3FrameInfo { + int32_t bitrate; + int32_t nChans; + int32_t samprate; + int32_t bitsPerSample; + int32_t outputSamps; + int32_t layer; + int32_t version; +} MP3FrameInfo_t; + +typedef struct SFBandTable { + int32_t l[23]; + int32_t s[14]; +} SFBandTable_t; + +typedef struct BitStreamInfo { + uint8_t* bytePtr; + uint32_t iCache; + int32_t cachedBits; + int32_t nBytes; +} BitStreamInfo_t; + +typedef enum { /* map these to the corresponding 2-bit values in the frame header */ + Stereo = 0x00, /* two independent channels, but L and R frames might have different # of bits */ + Joint = 0x01, /* coupled channels - layer III: mix of M-S and intensity, Layers I/II: intensity and direct coding only */ + Dual = 0x02, /* two independent channels, L and R always have exactly 1/2 the total bitrate */ + Mono = 0x03 /* one channel */ +} StereoMode_t; + +typedef enum { /* map to 0,1,2 to make table indexing easier */ + MPEG1 = 0, + MPEG2 = 1, + MPEG25 = 2 +} MPEGVersion_t; + +typedef struct FrameHeader { + int32_t layer; /* layer index (1, 2, or 3) */ + int32_t crc; /* CRC flag: 0 = disabled, 1 = enabled */ + int32_t brIdx; /* bitrate index (0 - 15) */ + int32_t srIdx; /* sample rate index (0 - 2) */ + int32_t paddingBit; /* padding flag: 0 = no padding, 1 = single pad byte */ + int32_t privateBit; /* unused */ + int32_t modeExt; /* used to decipher joint stereo mode */ + int32_t copyFlag; /* copyright flag: 0 = no, 1 = yes */ + int32_t origFlag; /* original flag: 0 = copy, 1 = original */ + int32_t emphasis; /* deemphasis mode */ + int32_t CRCWord; /* CRC word (16 bits, 0 if crc not enabled) */ +} FrameHeader_t; + +typedef struct SideInfoSub { + int32_t part23Length; /* number of bits in main data */ + int32_t nBigvals; /* 2x this = first set of Huffman cw's (maximum amplitude can be > 1) */ + int32_t globalGain; /* overall gain for dequantizer */ + int32_t sfCompress; /* unpacked to figure out number of bits in scale factors */ + int32_t winSwitchFlag; /* window switching flag */ + int32_t blockType; /* block type */ + int32_t mixedBlock; /* 0 = regular block (all short or long), 1 = mixed block */ + int32_t tableSelect[3]; /* index of Huffman tables for the big values regions */ + int32_t subBlockGain[3]; /* subblock gain offset, relative to global gain */ + int32_t region0Count; /* 1+region0Count = num scale factor bands in first region of bigvals */ + int32_t region1Count; /* 1+region1Count = num scale factor bands in second region of bigvals */ + int32_t preFlag; /* for optional high frequency boost */ + int32_t sfactScale; /* scaling of the scalefactors */ + int32_t count1TableSelect; /* index of Huffman table for quad codewords */ +} SideInfoSub_t; + +typedef struct SideInfo { + int32_t mainDataBegin; + int32_t privateBits; + int32_t scfsi[MAX_NCHAN][MAX_SCFBD]; /* 4 scalefactor bands per channel */ +} SideInfo_t; + +typedef struct { + int32_t cbType; /* pure long = 0, pure short = 1, mixed = 2 */ + int32_t cbEndS[3]; /* number nonzero short cb's, per subbblock */ + int32_t cbEndSMax; /* max of cbEndS[] */ + int32_t cbEndL; /* number nonzero long cb's */ +} CriticalBandInfo_t; + +typedef struct DequantInfo { + int32_t workBuf[MAX_REORDER_SAMPS]; /* workbuf for reordering short blocks */ +} DequantInfo_t; + +typedef struct HuffmanInfo { + int32_t huffDecBuf[MAX_NCHAN][MAX_NSAMP]; /* used both for decoded Huffman values and dequantized coefficients */ + int32_t nonZeroBound[MAX_NCHAN]; /* number of coeffs in huffDecBuf[ch] which can be > 0 */ + int32_t gb[MAX_NCHAN]; /* minimum number of guard bits in huffDecBuf[ch] */ +} HuffmanInfo_t; + +typedef enum HuffTabType { noBits, oneShot, loopNoLinbits, loopLinbits, quadA, quadB, invalidTab } HuffTabType_t; + +typedef struct HuffTabLookup { + int32_t linBits; + int32_t tabType; /*HuffTabType*/ +} HuffTabLookup_t; + +typedef struct IMDCTInfo { + int32_t outBuf[MAX_NCHAN][BLOCK_SIZE][NBANDS]; /* output of IMDCT */ + int32_t overBuf[MAX_NCHAN][MAX_NSAMP / 2]; /* overlap-add buffer (by symmetry, only need 1/2 size) */ + int32_t numPrevIMDCT[MAX_NCHAN]; /* how many IMDCT's calculated in this channel on prev. granule */ + int32_t prevType[MAX_NCHAN]; + int32_t prevWinSwitch[MAX_NCHAN]; + int32_t gb[MAX_NCHAN]; +} IMDCTInfo_t; + +typedef struct BlockCount { + int32_t nBlocksLong; + int32_t nBlocksTotal; + int32_t nBlocksPrev; + int32_t prevType; + int32_t prevWinSwitch; + int32_t currWinSwitch; + int32_t gbIn; + int32_t gbOut; +} BlockCount_t; + +typedef struct ScaleFactorInfoSub { /* max bits in scalefactors = 5, so use char's to save space */ + char l[23]; /* [band] */ + char s[13][3]; /* [band][window] */ +} ScaleFactorInfoSub_t; + +typedef struct ScaleFactorJS { /* used in MPEG 2, 2.5 intensity (joint) stereo only */ + int32_t intensityScale; + int32_t slen[4]; + int32_t nr[4]; +} ScaleFactorJS_t; + +/* NOTE - could get by with smaller vbuf if memory is more important than speed + * (in Subband, instead of replicating each block in FDCT32 you would do a memmove on the + * last 15 blocks to shift them down one, a hardware style FIFO) + */ +typedef struct SubbandInfo { + int32_t vbuf[MAX_NCHAN * VBUF_LENGTH]; /* vbuf for fast DCT-based synthesis PQMF - double size for speed (no modulo indexing) */ + int32_t vindex; /* internal index for tracking position in vbuf */ +} SubbandInfo_t; + +typedef struct MP3DecInfo { + /* buffer which must be large enough to hold largest possible main_data section */ + uint8_t mainBuf[MAINBUF_SIZE]; + /* special info for "free" bitrate files */ + int32_t freeBitrateFlag; + int32_t freeBitrateSlots; + /* user-accessible info */ + int32_t bitrate; + int32_t nChans; + int32_t samprate; + int32_t nGrans; /* granules per frame */ + int32_t nGranSamps; /* samples per granule */ + int32_t nSlots; + int32_t layer; + + int32_t mainDataBegin; + int32_t mainDataBytes; + int32_t part23Length[MAX_NGRAN][MAX_NCHAN]; +} MP3DecInfo_t; + +typedef struct { + uint8_t mpeg_version; // 0=MPEG2.5, 1=reserved, 2=MPEG2, 3=MPEG1 + uint8_t layer; // 0=reserved, 1=Layer III, 2=Layer II, 3=Layer I + bool crc_protected; + uint8_t bitrate_idx; + uint8_t sample_rate_idx; + bool padding; + uint8_t channel_mode; + uint32_t frame_length; // In Bytes +} Mp3FrameHeader; + +struct invalid_frame { + uint32_t timer = 0; + bool start = true; + uint32_t count1 = 0; + uint32_t count2 = 0; + +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/mp3_decoder/tables.h b/libraries/ESP32-audioI2S/src/mp3_decoder/tables.h new file mode 100644 index 0000000..5c6008d --- /dev/null +++ b/libraries/ESP32-audioI2S/src/mp3_decoder/tables.h @@ -0,0 +1,662 @@ +#pragma once + +#include "stdint-gcc.h" +#include "structs.h" + +static const uint16_t huffTable[4242] = { + 0xf003, 0x3112, 0x3101, 0x2011, 0x2011, 0x1000, 0x1000, 0x1000, 0x1000, 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, 0x5021, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, + 0x2101, 0x2101, 0x2101, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0xf008, 0x8332, 0x8322, 0x7232, 0x7232, + 0x6132, 0x6132, 0x6132, 0x6132, 0x7312, 0x7312, 0x7301, 0x7301, 0x7031, 0x7031, 0x7222, 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, + 0x6021, 0x6021, 0x6021, 0x6021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf007, 0x7332, 0x7301, 0x6322, 0x6322, 0x6232, 0x6232, 0x6031, 0x6031, 0x5312, 0x5312, 0x5312, + 0x5312, 0x5132, 0x5132, 0x5132, 0x5132, 0x5222, 0x5222, 0x5222, 0x5222, 0x5201, 0x5201, 0x5201, 0x5201, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0xf006, 0x0041, 0x0052, + 0x005b, 0x0060, 0x0063, 0x0068, 0x006b, 0x6212, 0x5122, 0x5122, 0x6201, 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf004, 0x4552, 0x4542, 0x4452, 0x4352, 0x3532, 0x3532, 0x3442, 0x3442, 0x3522, + 0x3522, 0x3252, 0x3252, 0x2512, 0x2512, 0x2512, 0x2512, 0xf003, 0x2152, 0x2152, 0x3501, 0x3432, 0x2051, 0x2051, 0x3342, 0x3332, 0xf002, 0x2422, 0x2242, 0x1412, 0x1412, 0xf001, 0x1142, 0x1041, + 0xf002, 0x2401, 0x2322, 0x2232, 0x2301, 0xf001, 0x1312, 0x1132, 0xf001, 0x1031, 0x1222, 0xf008, 0x0101, 0x010a, 0x010f, 0x8512, 0x8152, 0x0112, 0x0115, 0x8422, 0x8242, 0x8412, 0x7142, 0x7142, + 0x8401, 0x8041, 0x8322, 0x8232, 0x8312, 0x8132, 0x8301, 0x8031, 0x6222, 0x6222, 0x6222, 0x6222, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0xf003, 0x3552, 0x3452, 0x2542, 0x2542, 0x1352, 0x1352, 0x1352, 0x1352, 0xf002, 0x2532, 0x2442, 0x1522, 0x1522, 0xf001, 0x1252, 0x1501, 0xf001, 0x1432, 0x1342, + 0xf001, 0x1051, 0x1332, 0xf006, 0x0041, 0x004a, 0x004f, 0x0052, 0x0057, 0x005a, 0x6412, 0x6142, 0x6322, 0x6232, 0x5312, 0x5312, 0x5132, 0x5132, 0x6301, 0x6031, 0x5222, 0x5222, 0x5201, 0x5201, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4021, 0x4021, 0x4021, 0x4021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0xf003, 0x3552, 0x3542, 0x2532, + 0x2532, 0x2352, 0x2352, 0x3452, 0x3501, 0xf002, 0x2442, 0x2522, 0x2252, 0x2512, 0xf001, 0x1152, 0x1432, 0xf002, 0x1342, 0x1342, 0x2051, 0x2401, 0xf001, 0x1422, 0x1242, 0xf001, 0x1332, 0x1041, + 0xf008, 0x0101, 0x010a, 0x010f, 0x0118, 0x011b, 0x0120, 0x0125, 0x8712, 0x8172, 0x012a, 0x012d, 0x0132, 0x8612, 0x8162, 0x8061, 0x0137, 0x013a, 0x013d, 0x8412, 0x8142, 0x8041, 0x8322, 0x8232, + 0x8301, 0x7312, 0x7312, 0x7132, 0x7132, 0x7031, 0x7031, 0x7222, 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf003, 0x3772, 0x3762, 0x3672, 0x3752, 0x3572, 0x3662, + 0x2742, 0x2742, 0xf002, 0x2472, 0x2652, 0x2562, 0x2732, 0xf003, 0x2372, 0x2372, 0x2642, 0x2642, 0x3552, 0x3452, 0x2362, 0x2362, 0xf001, 0x1722, 0x1272, 0xf002, 0x2462, 0x2701, 0x1071, 0x1071, + 0xf002, 0x1262, 0x1262, 0x2542, 0x2532, 0xf002, 0x1601, 0x1601, 0x2352, 0x2442, 0xf001, 0x1632, 0x1622, 0xf002, 0x2522, 0x2252, 0x1512, 0x1512, 0xf002, 0x1152, 0x1152, 0x2432, 0x2342, 0xf001, + 0x1501, 0x1051, 0xf001, 0x1422, 0x1242, 0xf001, 0x1332, 0x1401, 0xf008, 0x0101, 0x0106, 0x010f, 0x0114, 0x0117, 0x8722, 0x8272, 0x011c, 0x7172, 0x7172, 0x8712, 0x8071, 0x8632, 0x8362, 0x8061, + 0x011f, 0x0122, 0x8512, 0x7262, 0x7262, 0x8622, 0x8601, 0x7612, 0x7612, 0x7162, 0x7162, 0x8152, 0x8432, 0x8051, 0x0125, 0x8422, 0x8242, 0x8412, 0x8142, 0x8401, 0x8041, 0x7322, 0x7322, 0x7232, + 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x7301, 0x7301, 0x7031, 0x7031, 0x6222, 0x6222, 0x6222, 0x6222, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, + 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0xf002, 0x2772, 0x2762, 0x2672, 0x2572, 0xf003, 0x2662, 0x2662, 0x2742, 0x2742, 0x2472, 0x2472, 0x3752, 0x3552, 0xf002, 0x2652, 0x2562, 0x1732, 0x1732, 0xf001, 0x1372, 0x1642, 0xf002, + 0x2542, 0x2452, 0x2532, 0x2352, 0xf001, 0x1462, 0x1701, 0xf001, 0x1442, 0x1522, 0xf001, 0x1252, 0x1501, 0xf001, 0x1342, 0x1332, 0xf007, 0x0081, 0x008a, 0x008f, 0x0092, 0x0097, 0x009a, 0x009d, + 0x00a2, 0x00a5, 0x00a8, 0x7622, 0x7262, 0x7162, 0x00ad, 0x00b0, 0x00b3, 0x7512, 0x7152, 0x7432, 0x7342, 0x00b6, 0x7422, 0x7242, 0x7412, 0x6332, 0x6332, 0x6142, 0x6142, 0x6322, 0x6322, 0x6232, + 0x6232, 0x7041, 0x7301, 0x6031, 0x6031, 0x5312, 0x5312, 0x5312, 0x5312, 0x5132, 0x5132, 0x5132, 0x5132, 0x5222, 0x5222, 0x5222, 0x5222, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0xf003, 0x3772, 0x3762, 0x2672, 0x2672, 0x2752, 0x2752, 0x2572, 0x2572, 0xf002, 0x2662, 0x2742, 0x2472, 0x2562, 0xf001, 0x1652, 0x1732, 0xf002, 0x2372, 0x2552, 0x1722, 0x1722, 0xf001, + 0x1272, 0x1642, 0xf001, 0x1462, 0x1712, 0xf002, 0x1172, 0x1172, 0x2701, 0x2071, 0xf001, 0x1632, 0x1362, 0xf001, 0x1542, 0x1452, 0xf002, 0x1442, 0x1442, 0x2601, 0x2501, 0xf001, 0x1612, 0x1061, + 0xf001, 0x1532, 0x1352, 0xf001, 0x1522, 0x1252, 0xf001, 0x1051, 0x1401, 0xf006, 0x0041, 0x0082, 0x00c3, 0x00e4, 0x0105, 0x0116, 0x011f, 0x0130, 0x0139, 0x013e, 0x0143, 0x0146, 0x6212, 0x6122, + 0x6201, 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0xf006, 0x0108, 0x0111, 0x011a, 0x0123, 0x012c, 0x0131, 0x0136, 0x013f, 0x0144, 0x0147, 0x014c, 0x0151, 0x0156, 0x015b, 0x6f12, 0x61f2, 0x60f1, 0x0160, 0x0163, 0x0166, 0x62e2, + 0x0169, 0x6e12, 0x61e2, 0x016c, 0x016f, 0x0172, 0x0175, 0x0178, 0x017b, 0x66c2, 0x6d32, 0x017e, 0x6d22, 0x62d2, 0x6d12, 0x67b2, 0x0181, 0x0184, 0x63c2, 0x0187, 0x6b42, 0x51d2, 0x51d2, 0x6d01, + 0x60d1, 0x6a82, 0x68a2, 0x6c42, 0x64c2, 0x6b62, 0x66b2, 0x5c32, 0x5c32, 0x5c22, 0x5c22, 0x52c2, 0x52c2, 0x5b52, 0x5b52, 0x65b2, 0x6982, 0x5c12, 0x5c12, 0xf006, 0x51c2, 0x51c2, 0x6892, 0x6c01, + 0x50c1, 0x50c1, 0x64b2, 0x6a62, 0x66a2, 0x6972, 0x5b32, 0x5b32, 0x53b2, 0x53b2, 0x6882, 0x6a52, 0x5b22, 0x5b22, 0x65a2, 0x6962, 0x54a2, 0x54a2, 0x6872, 0x6782, 0x5492, 0x5492, 0x6772, 0x6672, + 0x42b2, 0x42b2, 0x42b2, 0x42b2, 0x4b12, 0x4b12, 0x4b12, 0x4b12, 0x41b2, 0x41b2, 0x41b2, 0x41b2, 0x5b01, 0x5b01, 0x50b1, 0x50b1, 0x5692, 0x5692, 0x5a42, 0x5a42, 0x5a32, 0x5a32, 0x53a2, 0x53a2, + 0x5952, 0x5952, 0x5592, 0x5592, 0x4a22, 0x4a22, 0x4a22, 0x4a22, 0x42a2, 0x42a2, 0x42a2, 0x42a2, 0xf005, 0x4a12, 0x4a12, 0x41a2, 0x41a2, 0x5a01, 0x5862, 0x40a1, 0x40a1, 0x5682, 0x5942, 0x4392, + 0x4392, 0x5932, 0x5852, 0x5582, 0x5762, 0x4922, 0x4922, 0x4292, 0x4292, 0x5752, 0x5572, 0x4832, 0x4832, 0x4382, 0x4382, 0x5662, 0x5742, 0x5472, 0x5652, 0x5562, 0x5372, 0xf005, 0x3912, 0x3912, + 0x3912, 0x3912, 0x3192, 0x3192, 0x3192, 0x3192, 0x4901, 0x4901, 0x4091, 0x4091, 0x4842, 0x4842, 0x4482, 0x4482, 0x4272, 0x4272, 0x5642, 0x5462, 0x3822, 0x3822, 0x3822, 0x3822, 0x3282, 0x3282, + 0x3282, 0x3282, 0x3812, 0x3812, 0x3812, 0x3812, 0xf004, 0x4732, 0x4722, 0x3712, 0x3712, 0x3172, 0x3172, 0x4552, 0x4701, 0x4071, 0x4632, 0x4362, 0x4542, 0x4452, 0x4622, 0x4262, 0x4532, 0xf003, + 0x2182, 0x2182, 0x3801, 0x3081, 0x3612, 0x3162, 0x3601, 0x3061, 0xf004, 0x4352, 0x4442, 0x3522, 0x3522, 0x3252, 0x3252, 0x3501, 0x3501, 0x2512, 0x2512, 0x2512, 0x2512, 0x2152, 0x2152, 0x2152, + 0x2152, 0xf003, 0x3432, 0x3342, 0x3051, 0x3422, 0x3242, 0x3332, 0x2412, 0x2412, 0xf002, 0x1142, 0x1142, 0x2401, 0x2041, 0xf002, 0x2322, 0x2232, 0x1312, 0x1312, 0xf001, 0x1132, 0x1301, 0xf001, + 0x1031, 0x1222, 0xf003, 0x0082, 0x008b, 0x008e, 0x0091, 0x0094, 0x0097, 0x3ce2, 0x3dd2, 0xf003, 0x0093, 0x3eb2, 0x3be2, 0x3f92, 0x39f2, 0x3ae2, 0x3db2, 0x3bd2, 0xf003, 0x3f82, 0x38f2, 0x3cc2, + 0x008d, 0x3e82, 0x0090, 0x27f2, 0x27f2, 0xf003, 0x2ad2, 0x2ad2, 0x3da2, 0x3cb2, 0x3bc2, 0x36f2, 0x2f62, 0x2f62, 0xf002, 0x28e2, 0x2f52, 0x2d92, 0x29d2, 0xf002, 0x25f2, 0x27e2, 0x2ca2, 0x2bb2, + 0xf003, 0x2f42, 0x2f42, 0x24f2, 0x24f2, 0x3ac2, 0x36e2, 0x23f2, 0x23f2, 0xf002, 0x1f32, 0x1f32, 0x2d82, 0x28d2, 0xf001, 0x1f22, 0x12f2, 0xf002, 0x2e62, 0x2c92, 0x1f01, 0x1f01, 0xf002, 0x29c2, + 0x2e52, 0x1ba2, 0x1ba2, 0xf002, 0x2d72, 0x27d2, 0x1e42, 0x1e42, 0xf002, 0x28c2, 0x26d2, 0x1e32, 0x1e32, 0xf002, 0x19b2, 0x19b2, 0x2b92, 0x2aa2, 0xf001, 0x1ab2, 0x15e2, 0xf001, 0x14e2, 0x1c82, + 0xf001, 0x1d62, 0x13e2, 0xf001, 0x1e22, 0x1e01, 0xf001, 0x10e1, 0x1d52, 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, 0x1b82, 0x18b2, 0xf001, 0x14d2, 0x1a92, 0xf001, 0x19a2, 0x1c62, + 0xf001, 0x13d2, 0x1b72, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1992, 0x1a72, 0xf001, 0x17a2, 0x1792, 0xf003, 0x0023, 0x3df2, 0x2de2, 0x2de2, 0x1ff2, 0x1ff2, 0x1ff2, 0x1ff2, 0xf001, 0x1fe2, 0x1fd2, + 0xf001, 0x1ee2, 0x1fc2, 0xf001, 0x1ed2, 0x1fb2, 0xf001, 0x1bf2, 0x1ec2, 0xf002, 0x1cd2, 0x1cd2, 0x2fa2, 0x29e2, 0xf001, 0x1af2, 0x1dc2, 0xf001, 0x1ea2, 0x1e92, 0xf001, 0x1f72, 0x1e72, 0xf001, + 0x1ef2, 0x1cf2, 0xf008, 0x0101, 0x0122, 0x0143, 0x0154, 0x0165, 0x0176, 0x017f, 0x0188, 0x0199, 0x01a2, 0x01ab, 0x01b4, 0x01bd, 0x01c2, 0x01cb, 0x01d4, 0x01d9, 0x01de, 0x01e3, 0x01e8, 0x01ed, + 0x01f2, 0x01f7, 0x01fc, 0x0201, 0x0204, 0x0207, 0x020a, 0x020f, 0x0212, 0x0215, 0x021a, 0x021d, 0x0220, 0x8192, 0x0223, 0x0226, 0x0229, 0x022c, 0x022f, 0x8822, 0x8282, 0x8812, 0x8182, 0x0232, + 0x0235, 0x0238, 0x023b, 0x8722, 0x8272, 0x8462, 0x8712, 0x8552, 0x8172, 0x023e, 0x8632, 0x8362, 0x8542, 0x8452, 0x8622, 0x8262, 0x8612, 0x0241, 0x8532, 0x7162, 0x7162, 0x8352, 0x8442, 0x7522, + 0x7522, 0x7252, 0x7252, 0x7512, 0x7512, 0x7152, 0x7152, 0x8501, 0x8051, 0x7432, 0x7432, 0x7342, 0x7342, 0x7422, 0x7422, 0x7242, 0x7242, 0x7332, 0x7332, 0x6142, 0x6142, 0x6142, 0x6142, 0x7412, + 0x7412, 0x7401, 0x7401, 0x6322, 0x6322, 0x6322, 0x6322, 0x6232, 0x6232, 0x6232, 0x6232, 0x7041, 0x7041, 0x7301, 0x7301, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6031, + 0x6031, 0x6031, 0x6031, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5122, 0x5122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0xf005, 0x5ff2, 0x5fe2, 0x5ef2, 0x5fd2, + 0x4ee2, 0x4ee2, 0x5df2, 0x5fc2, 0x5cf2, 0x5ed2, 0x5de2, 0x5fb2, 0x4bf2, 0x4bf2, 0x5ec2, 0x5ce2, 0x4dd2, 0x4dd2, 0x4fa2, 0x4fa2, 0x4af2, 0x4af2, 0x4eb2, 0x4eb2, 0x4be2, 0x4be2, 0x4dc2, 0x4dc2, + 0x4cd2, 0x4cd2, 0x4f92, 0x4f92, 0xf005, 0x49f2, 0x49f2, 0x4ae2, 0x4ae2, 0x4db2, 0x4db2, 0x4bd2, 0x4bd2, 0x4f82, 0x4f82, 0x48f2, 0x48f2, 0x4cc2, 0x4cc2, 0x4e92, 0x4e92, 0x49e2, 0x49e2, 0x4f72, + 0x4f72, 0x47f2, 0x47f2, 0x4da2, 0x4da2, 0x4ad2, 0x4ad2, 0x4cb2, 0x4cb2, 0x4f62, 0x4f62, 0x5ea2, 0x5f01, 0xf004, 0x3bc2, 0x3bc2, 0x36f2, 0x36f2, 0x4e82, 0x48e2, 0x4f52, 0x4d92, 0x35f2, 0x35f2, + 0x3e72, 0x3e72, 0x37e2, 0x37e2, 0x3ca2, 0x3ca2, 0xf004, 0x3ac2, 0x3ac2, 0x3bb2, 0x3bb2, 0x49d2, 0x4d82, 0x3f42, 0x3f42, 0x34f2, 0x34f2, 0x3f32, 0x3f32, 0x33f2, 0x33f2, 0x38d2, 0x38d2, 0xf004, + 0x36e2, 0x36e2, 0x3f22, 0x3f22, 0x32f2, 0x32f2, 0x4e62, 0x40f1, 0x3f12, 0x3f12, 0x31f2, 0x31f2, 0x3c92, 0x3c92, 0x39c2, 0x39c2, 0xf003, 0x3e52, 0x3ba2, 0x3ab2, 0x35e2, 0x3d72, 0x37d2, 0x3e42, + 0x34e2, 0xf003, 0x3c82, 0x38c2, 0x3e32, 0x3d62, 0x36d2, 0x33e2, 0x3b92, 0x39b2, 0xf004, 0x3e22, 0x3e22, 0x3aa2, 0x3aa2, 0x32e2, 0x32e2, 0x3e12, 0x3e12, 0x31e2, 0x31e2, 0x4e01, 0x40e1, 0x3d52, + 0x3d52, 0x35d2, 0x35d2, 0xf003, 0x3c72, 0x37c2, 0x3d42, 0x3b82, 0x24d2, 0x24d2, 0x38b2, 0x3a92, 0xf003, 0x39a2, 0x3c62, 0x36c2, 0x3d32, 0x23d2, 0x23d2, 0x22d2, 0x22d2, 0xf003, 0x3d22, 0x3d01, + 0x2d12, 0x2d12, 0x2b72, 0x2b72, 0x27b2, 0x27b2, 0xf003, 0x21d2, 0x21d2, 0x3c52, 0x30d1, 0x25c2, 0x25c2, 0x2a82, 0x2a82, 0xf002, 0x28a2, 0x2c42, 0x24c2, 0x2b62, 0xf003, 0x26b2, 0x26b2, 0x3992, + 0x3c01, 0x2c32, 0x2c32, 0x23c2, 0x23c2, 0xf003, 0x2a72, 0x2a72, 0x27a2, 0x27a2, 0x26a2, 0x26a2, 0x30c1, 0x3b01, 0xf002, 0x12c2, 0x12c2, 0x2c22, 0x2b52, 0xf002, 0x25b2, 0x2c12, 0x2982, 0x2892, + 0xf002, 0x21c2, 0x2b42, 0x24b2, 0x2a62, 0xf002, 0x2b32, 0x2972, 0x13b2, 0x13b2, 0xf002, 0x2792, 0x2882, 0x2b22, 0x2a52, 0xf002, 0x12b2, 0x12b2, 0x25a2, 0x2b12, 0xf002, 0x11b2, 0x11b2, 0x20b1, + 0x2962, 0xf002, 0x2692, 0x2a42, 0x24a2, 0x2872, 0xf002, 0x2782, 0x2a32, 0x13a2, 0x13a2, 0xf001, 0x1952, 0x1592, 0xf001, 0x1a22, 0x12a2, 0xf001, 0x1a12, 0x11a2, 0xf002, 0x2a01, 0x20a1, 0x1862, + 0x1862, 0xf001, 0x1682, 0x1942, 0xf001, 0x1492, 0x1932, 0xf002, 0x1392, 0x1392, 0x2772, 0x2901, 0xf001, 0x1852, 0x1582, 0xf001, 0x1922, 0x1762, 0xf001, 0x1672, 0x1292, 0xf001, 0x1912, 0x1091, + 0xf001, 0x1842, 0x1482, 0xf001, 0x1752, 0x1572, 0xf001, 0x1832, 0x1382, 0xf001, 0x1662, 0x1742, 0xf001, 0x1472, 0x1801, 0xf001, 0x1081, 0x1652, 0xf001, 0x1562, 0x1732, 0xf001, 0x1372, 0x1642, + 0xf001, 0x1701, 0x1071, 0xf001, 0x1601, 0x1061, 0xf008, 0x0101, 0x010a, 0x0113, 0x8ff2, 0x0118, 0x011d, 0x0120, 0x82f2, 0x0131, 0x8f12, 0x81f2, 0x0134, 0x0145, 0x0156, 0x0167, 0x0178, 0x0189, + 0x019a, 0x01a3, 0x01ac, 0x01b5, 0x01be, 0x01c7, 0x01d0, 0x01d9, 0x01de, 0x01e3, 0x01e6, 0x01eb, 0x01f0, 0x8152, 0x01f3, 0x01f6, 0x01f9, 0x01fc, 0x8412, 0x8142, 0x01ff, 0x8322, 0x8232, 0x7312, + 0x7312, 0x7132, 0x7132, 0x8301, 0x8031, 0x7222, 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xf003, + 0x3fe2, 0x3ef2, 0x3fd2, 0x3df2, 0x3fc2, 0x3cf2, 0x3fb2, 0x3bf2, 0xf003, 0x2fa2, 0x2fa2, 0x3af2, 0x3f92, 0x39f2, 0x38f2, 0x2f82, 0x2f82, 0xf002, 0x2f72, 0x27f2, 0x2f62, 0x26f2, 0xf002, 0x2f52, + 0x25f2, 0x1f42, 0x1f42, 0xf001, 0x14f2, 0x13f2, 0xf004, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x2f32, 0x2f32, 0x2f32, 0x2f32, 0x00e2, 0x00f3, 0x00fc, 0x0105, 0xf001, + 0x1f22, 0x1f01, 0xf004, 0x00fa, 0x00ff, 0x0104, 0x0109, 0x010c, 0x0111, 0x0116, 0x0119, 0x011e, 0x0123, 0x0128, 0x43e2, 0x012d, 0x0130, 0x0133, 0x0136, 0xf004, 0x0128, 0x012b, 0x012e, 0x4d01, + 0x0131, 0x0134, 0x0137, 0x4c32, 0x013a, 0x4c12, 0x40c1, 0x013d, 0x32e2, 0x32e2, 0x4e22, 0x4e12, 0xf004, 0x43d2, 0x4d22, 0x42d2, 0x41d2, 0x4b32, 0x012f, 0x3d12, 0x3d12, 0x44c2, 0x4b62, 0x43c2, + 0x47a2, 0x3c22, 0x3c22, 0x42c2, 0x45b2, 0xf004, 0x41c2, 0x4c01, 0x4b42, 0x44b2, 0x4a62, 0x46a2, 0x33b2, 0x33b2, 0x4a52, 0x45a2, 0x3b22, 0x3b22, 0x32b2, 0x32b2, 0x3b12, 0x3b12, 0xf004, 0x31b2, + 0x31b2, 0x4b01, 0x40b1, 0x4962, 0x4692, 0x4a42, 0x44a2, 0x4872, 0x4782, 0x33a2, 0x33a2, 0x4a32, 0x4952, 0x3a22, 0x3a22, 0xf004, 0x4592, 0x4862, 0x31a2, 0x31a2, 0x4682, 0x4772, 0x3492, 0x3492, + 0x4942, 0x4752, 0x3762, 0x3762, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0xf003, 0x2a12, 0x2a12, 0x3a01, 0x30a1, 0x3932, 0x3392, 0x3852, 0x3582, 0xf003, 0x2922, 0x2922, 0x2292, 0x2292, 0x3672, 0x3901, + 0x2912, 0x2912, 0xf003, 0x2192, 0x2192, 0x3091, 0x3842, 0x3482, 0x3572, 0x3832, 0x3382, 0xf003, 0x3662, 0x3822, 0x2282, 0x2282, 0x3742, 0x3472, 0x2812, 0x2812, 0xf003, 0x2182, 0x2182, 0x2081, + 0x2081, 0x3801, 0x3652, 0x2732, 0x2732, 0xf003, 0x2372, 0x2372, 0x3562, 0x3642, 0x2722, 0x2722, 0x2272, 0x2272, 0xf003, 0x3462, 0x3552, 0x2701, 0x2701, 0x1712, 0x1712, 0x1712, 0x1712, 0xf002, + 0x1172, 0x1172, 0x2071, 0x2632, 0xf002, 0x2362, 0x2542, 0x2452, 0x2622, 0xf001, 0x1262, 0x1612, 0xf002, 0x1162, 0x1162, 0x2601, 0x2061, 0xf002, 0x1352, 0x1352, 0x2532, 0x2442, 0xf001, 0x1522, + 0x1252, 0xf001, 0x1512, 0x1501, 0xf001, 0x1432, 0x1342, 0xf001, 0x1051, 0x1422, 0xf001, 0x1242, 0x1332, 0xf001, 0x1401, 0x1041, 0xf004, 0x4ec2, 0x0086, 0x3ed2, 0x3ed2, 0x39e2, 0x39e2, 0x4ae2, + 0x49d2, 0x2ee2, 0x2ee2, 0x2ee2, 0x2ee2, 0x3de2, 0x3de2, 0x3be2, 0x3be2, 0xf003, 0x2eb2, 0x2eb2, 0x2dc2, 0x2dc2, 0x3cd2, 0x3bd2, 0x2ea2, 0x2ea2, 0xf003, 0x2cc2, 0x2cc2, 0x3da2, 0x3ad2, 0x3e72, + 0x3ca2, 0x2ac2, 0x2ac2, 0xf003, 0x39c2, 0x3d72, 0x2e52, 0x2e52, 0x1db2, 0x1db2, 0x1db2, 0x1db2, 0xf002, 0x1e92, 0x1e92, 0x2cb2, 0x2bc2, 0xf002, 0x2e82, 0x28e2, 0x2d92, 0x27e2, 0xf002, 0x2bb2, + 0x2d82, 0x28d2, 0x2e62, 0xf001, 0x16e2, 0x1c92, 0xf002, 0x2ba2, 0x2ab2, 0x25e2, 0x27d2, 0xf002, 0x1e42, 0x1e42, 0x24e2, 0x2c82, 0xf001, 0x18c2, 0x1e32, 0xf002, 0x1d62, 0x1d62, 0x26d2, 0x2b92, + 0xf002, 0x29b2, 0x2aa2, 0x11e2, 0x11e2, 0xf002, 0x14d2, 0x14d2, 0x28b2, 0x29a2, 0xf002, 0x1b72, 0x1b72, 0x27b2, 0x20d1, 0xf001, 0x1e01, 0x10e1, 0xf001, 0x1d52, 0x15d2, 0xf001, 0x1c72, 0x17c2, + 0xf001, 0x1d42, 0x1b82, 0xf001, 0x1a92, 0x1c62, 0xf001, 0x16c2, 0x1d32, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1a82, 0x18a2, 0xf001, 0x1992, 0x1c42, 0xf001, 0x16b2, 0x1a72, 0xf001, 0x1b52, 0x1982, + 0xf001, 0x1892, 0x1972, 0xf001, 0x1792, 0x1882, 0xf001, 0x1ce2, 0x1dd2, 0xf009, 0x8fe2, 0x8fe2, 0x8ef2, 0x8ef2, 0x8fd2, 0x8fd2, 0x8df2, 0x8df2, 0x8fc2, 0x8fc2, 0x8cf2, 0x8cf2, 0x8fb2, 0x8fb2, + 0x8bf2, 0x8bf2, 0x7af2, 0x7af2, 0x7af2, 0x7af2, 0x8fa2, 0x8fa2, 0x8f92, 0x8f92, 0x79f2, 0x79f2, 0x79f2, 0x79f2, 0x78f2, 0x78f2, 0x78f2, 0x78f2, 0x8f82, 0x8f82, 0x8f72, 0x8f72, 0x77f2, 0x77f2, + 0x77f2, 0x77f2, 0x7f62, 0x7f62, 0x7f62, 0x7f62, 0x76f2, 0x76f2, 0x76f2, 0x76f2, 0x7f52, 0x7f52, 0x7f52, 0x7f52, 0x75f2, 0x75f2, 0x75f2, 0x75f2, 0x7f42, 0x7f42, 0x7f42, 0x7f42, 0x74f2, 0x74f2, + 0x74f2, 0x74f2, 0x7f32, 0x7f32, 0x7f32, 0x7f32, 0x73f2, 0x73f2, 0x73f2, 0x73f2, 0x7f22, 0x7f22, 0x7f22, 0x7f22, 0x72f2, 0x72f2, 0x72f2, 0x72f2, 0x71f2, 0x71f2, 0x71f2, 0x71f2, 0x8f12, 0x8f12, + 0x80f1, 0x80f1, 0x9f01, 0x0201, 0x0206, 0x020b, 0x0210, 0x0215, 0x021a, 0x021f, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x0224, 0x0229, 0x0232, 0x0237, 0x023a, 0x023f, + 0x0242, 0x0245, 0x024a, 0x024d, 0x0250, 0x0253, 0x0256, 0x0259, 0x025c, 0x025f, 0x0262, 0x0265, 0x0268, 0x026b, 0x026e, 0x0271, 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0283, 0x0288, 0x028b, + 0x028e, 0x0291, 0x0294, 0x0297, 0x029a, 0x029f, 0x94b2, 0x02a4, 0x02a7, 0x02aa, 0x93b2, 0x9882, 0x02af, 0x92b2, 0x02b2, 0x02b5, 0x9692, 0x94a2, 0x02b8, 0x9782, 0x9a32, 0x93a2, 0x9952, 0x9592, + 0x9a22, 0x92a2, 0x91a2, 0x9862, 0x9682, 0x9772, 0x9942, 0x9492, 0x9932, 0x9392, 0x9852, 0x9582, 0x9922, 0x9762, 0x9672, 0x9292, 0x9912, 0x9192, 0x9842, 0x9482, 0x9752, 0x9572, 0x9832, 0x9382, + 0x9662, 0x9822, 0x9282, 0x9812, 0x9742, 0x9472, 0x9182, 0x02bb, 0x9652, 0x9562, 0x9712, 0x02be, 0x8372, 0x8372, 0x9732, 0x9722, 0x8272, 0x8272, 0x8642, 0x8642, 0x8462, 0x8462, 0x8552, 0x8552, + 0x8172, 0x8172, 0x8632, 0x8632, 0x8362, 0x8362, 0x8542, 0x8542, 0x8452, 0x8452, 0x8622, 0x8622, 0x8262, 0x8262, 0x8612, 0x8612, 0x8162, 0x8162, 0x9601, 0x9061, 0x8532, 0x8532, 0x8352, 0x8352, + 0x8442, 0x8442, 0x8522, 0x8522, 0x8252, 0x8252, 0x8512, 0x8512, 0x9501, 0x9051, 0x7152, 0x7152, 0x7152, 0x7152, 0x8432, 0x8432, 0x8342, 0x8342, 0x7422, 0x7422, 0x7422, 0x7422, 0x7242, 0x7242, + 0x7242, 0x7242, 0x7332, 0x7332, 0x7332, 0x7332, 0x7412, 0x7412, 0x7412, 0x7412, 0x7142, 0x7142, 0x7142, 0x7142, 0x8401, 0x8401, 0x8041, 0x8041, 0x7322, 0x7322, 0x7322, 0x7322, 0x7232, 0x7232, + 0x7232, 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x7301, 0x7301, 0x7301, 0x7301, 0x7031, 0x7031, + 0x7031, 0x7031, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, + 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0xf002, 0x2ee2, 0x2ed2, 0x2de2, 0x2ec2, 0xf002, + 0x2ce2, 0x2dd2, 0x2eb2, 0x2be2, 0xf002, 0x2dc2, 0x2cd2, 0x2ea2, 0x2ae2, 0xf002, 0x2db2, 0x2bd2, 0x2cc2, 0x2e92, 0xf002, 0x29e2, 0x2da2, 0x2ad2, 0x2cb2, 0xf002, 0x2bc2, 0x2e82, 0x28e2, 0x2d92, + 0xf002, 0x29d2, 0x2e72, 0x27e2, 0x2ca2, 0xf002, 0x2ac2, 0x2bb2, 0x2d82, 0x28d2, 0xf003, 0x3e01, 0x30e1, 0x2d01, 0x2d01, 0x16e2, 0x16e2, 0x16e2, 0x16e2, 0xf002, 0x2e62, 0x2c92, 0x19c2, 0x19c2, + 0xf001, 0x1e52, 0x1ab2, 0xf002, 0x15e2, 0x15e2, 0x2ba2, 0x2d72, 0xf001, 0x17d2, 0x14e2, 0xf001, 0x1c82, 0x18c2, 0xf002, 0x2e42, 0x2e22, 0x1e32, 0x1e32, 0xf001, 0x1d62, 0x16d2, 0xf001, 0x13e2, + 0x1b92, 0xf001, 0x19b2, 0x1aa2, 0xf001, 0x12e2, 0x1e12, 0xf001, 0x11e2, 0x1d52, 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, 0x1b82, 0x18b2, 0xf001, 0x14d2, 0x1a92, 0xf001, 0x19a2, + 0x1c62, 0xf001, 0x16c2, 0x1d32, 0xf001, 0x13d2, 0x1d22, 0xf001, 0x12d2, 0x1d12, 0xf001, 0x1b72, 0x17b2, 0xf001, 0x11d2, 0x1c52, 0xf001, 0x15c2, 0x1a82, 0xf001, 0x18a2, 0x1992, 0xf001, 0x1c42, + 0x14c2, 0xf001, 0x1b62, 0x16b2, 0xf002, 0x20d1, 0x2c01, 0x1c32, 0x1c32, 0xf001, 0x13c2, 0x1a72, 0xf001, 0x17a2, 0x1c22, 0xf001, 0x12c2, 0x1b52, 0xf001, 0x15b2, 0x1c12, 0xf001, 0x1982, 0x1892, + 0xf001, 0x11c2, 0x1b42, 0xf002, 0x20c1, 0x2b01, 0x1b32, 0x1b32, 0xf002, 0x20b1, 0x2a01, 0x1a12, 0x1a12, 0xf001, 0x1a62, 0x16a2, 0xf001, 0x1972, 0x1792, 0xf002, 0x20a1, 0x2901, 0x1091, 0x1091, + 0xf001, 0x1b22, 0x1a52, 0xf001, 0x15a2, 0x1b12, 0xf001, 0x11b2, 0x1962, 0xf001, 0x1a42, 0x1872, 0xf001, 0x1801, 0x1081, 0xf001, 0x1701, 0x1071, +}; +/* pow(2,-i/4) * pow(j,4/3) for i=0..3 j=0..15, Q25 format */ +static const int32_t pow43_14[4][16] = { + {0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, 0x0cb2ff53, 0x111989d6, 0x15ce31c8, 0x1ac7f203, 0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, 0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c}, + {0x00000000, 0x0d744fcd, 0x21e71f26, 0x3a36abd9, 0x0aadc084, 0x0e610e6e, 0x12560c1d, 0x168523cf, 0x1ae89f99, 0x1f7c03a4, 0x243bae49, 0x29249c67, 0x2e34420f, 0x33686f85, 0x38bf3dff, 0x3e370182}, + {0x00000000, 0x0b504f33, 0x1c823e07, 0x30f39a55, 0x08facd62, 0x0c176319, 0x0f6b3522, 0x12efe2ad, 0x16a09e66, 0x1a79a317, 0x1e77e301, 0x2298d5b4, 0x26da56fc, 0x2b3a902a, 0x2fb7e7e7, 0x3450f650}, + {0x00000000, 0x09837f05, 0x17f910d7, 0x2929c7a9, 0x078d0dfa, 0x0a2ae661, 0x0cf73154, 0x0fec91cb, 0x1306fe0a, 0x16434a6c, 0x199ee595, 0x1d17ae3d, 0x20abd76a, 0x2459d551, 0x28204fbb, 0x2bfe1808}, +}; + +/* pow(j,4/3) for j=16..63, Q23 format */ +static const int32_t pow43[48] = { + 0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85, 0x1b24e8bb, 0x1cf7fcfa, 0x1ed28af2, 0x20b4582a, 0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000, 0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99, + 0x32cbfd4a, 0x34eca001, 0x3712ca62, 0x393e6088, 0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72, 0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3, 0x4daaebfd, 0x5007b497, 0x5268fc62, 0x54ceb29c, + 0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129, 0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b, 0x6b1fc80c, 0x6daeaa0d, 0x70416360, 0x72d7e8b0, 0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09, +}; + +static const uint32_t polyCoef[264] = { + /* shuffled vs. original from 0, 1, ... 15 to 0, 15, 2, 13, ... 14, 1 */ + 0x00000000, 0x00000074, 0x00000354, 0x0000072c, 0x00001fd4, 0x00005084, 0x000066b8, 0x000249c4, 0x00049478, 0xfffdb63c, 0x000066b8, 0xffffaf7c, 0x00001fd4, 0xfffff8d4, 0x00000354, 0xffffff8c, + 0xfffffffc, 0x00000068, 0x00000368, 0x00000644, 0x00001f40, 0x00004ad0, 0x00005d1c, 0x00022ce0, 0x000493c0, 0xfffd9960, 0x00006f78, 0xffffa9cc, 0x0000203c, 0xfffff7e4, 0x00000340, 0xffffff84, + 0xfffffffc, 0x00000060, 0x00000378, 0x0000056c, 0x00001e80, 0x00004524, 0x000052a0, 0x00020ffc, 0x000491a0, 0xfffd7ca0, 0x00007760, 0xffffa424, 0x00002080, 0xfffff6ec, 0x00000328, 0xffffff74, + 0xfffffffc, 0x00000054, 0x00000384, 0x00000498, 0x00001d94, 0x00003f7c, 0x00004744, 0x0001f32c, 0x00048e18, 0xfffd6008, 0x00007e70, 0xffff9e8c, 0x0000209c, 0xfffff5ec, 0x00000310, 0xffffff68, + 0xfffffffc, 0x0000004c, 0x0000038c, 0x000003d0, 0x00001c78, 0x000039e4, 0x00003b00, 0x0001d680, 0x00048924, 0xfffd43ac, 0x000084b0, 0xffff990c, 0x00002094, 0xfffff4e4, 0x000002f8, 0xffffff5c, + 0xfffffffc, 0x00000044, 0x00000390, 0x00000314, 0x00001b2c, 0x0000345c, 0x00002ddc, 0x0001ba04, 0x000482d0, 0xfffd279c, 0x00008a20, 0xffff93a4, 0x0000206c, 0xfffff3d4, 0x000002dc, 0xffffff4c, + 0xfffffffc, 0x00000040, 0x00000390, 0x00000264, 0x000019b0, 0x00002ef0, 0x00001fd4, 0x00019dc8, 0x00047b1c, 0xfffd0be8, 0x00008ecc, 0xffff8e64, 0x00002024, 0xfffff2c0, 0x000002c0, 0xffffff3c, + 0xfffffff8, 0x00000038, 0x0000038c, 0x000001bc, 0x000017fc, 0x0000299c, 0x000010e8, 0x000181d8, 0x0004720c, 0xfffcf09c, 0x000092b4, 0xffff894c, 0x00001fc0, 0xfffff1a4, 0x000002a4, 0xffffff2c, + 0xfffffff8, 0x00000034, 0x00000380, 0x00000120, 0x00001618, 0x00002468, 0x00000118, 0x00016644, 0x000467a4, 0xfffcd5cc, 0x000095e0, 0xffff8468, 0x00001f44, 0xfffff084, 0x00000284, 0xffffff18, + 0xfffffff8, 0x0000002c, 0x00000374, 0x00000090, 0x00001400, 0x00001f58, 0xfffff068, 0x00014b14, 0x00045bf0, 0xfffcbb88, 0x00009858, 0xffff7fbc, 0x00001ea8, 0xffffef60, 0x00000268, 0xffffff04, + 0xfffffff8, 0x00000028, 0x0000035c, 0x00000008, 0x000011ac, 0x00001a70, 0xffffded8, 0x00013058, 0x00044ef8, 0xfffca1d8, 0x00009a1c, 0xffff7b54, 0x00001dfc, 0xffffee3c, 0x0000024c, 0xfffffef0, + 0xfffffff4, 0x00000024, 0x00000340, 0xffffff8c, 0x00000f28, 0x000015b0, 0xffffcc70, 0x0001161c, 0x000440bc, 0xfffc88d8, 0x00009b3c, 0xffff7734, 0x00001d38, 0xffffed18, 0x0000022c, 0xfffffedc, + 0xfffffff4, 0x00000020, 0x00000320, 0xffffff1c, 0x00000c68, 0x0000111c, 0xffffb92c, 0x0000fc6c, 0x00043150, 0xfffc708c, 0x00009bb8, 0xffff7368, 0x00001c64, 0xffffebf4, 0x00000210, 0xfffffec4, + 0xfffffff0, 0x0000001c, 0x000002f4, 0xfffffeb4, 0x00000974, 0x00000cb8, 0xffffa518, 0x0000e350, 0x000420b4, 0xfffc5908, 0x00009b9c, 0xffff6ff4, 0x00001b7c, 0xffffead0, 0x000001f4, 0xfffffeac, + 0xfffffff0, 0x0000001c, 0x000002c4, 0xfffffe58, 0x00000648, 0x00000884, 0xffff9038, 0x0000cad0, 0x00040ef8, 0xfffc425c, 0x00009af0, 0xffff6ce0, 0x00001a88, 0xffffe9b0, 0x000001d4, 0xfffffe94, + 0xffffffec, 0x00000018, 0x0000028c, 0xfffffe04, 0x000002e4, 0x00000480, 0xffff7a90, 0x0000b2fc, 0x0003fc28, 0xfffc2c90, 0x000099b8, 0xffff6a3c, 0x00001988, 0xffffe898, 0x000001bc, 0xfffffe7c, + 0x000001a0, 0x0000187c, 0x000097fc, 0x0003e84c, 0xffff6424, 0xffffff4c, 0x00000248, 0xffffffec, +}; + +/* format = Q30, range = [0.0981, 1.9976] + * + * n = 16; + * k = 0; + * for(i=0; i<5; i++, n=n/2) { + * for(p=0; p (NRTab[x][1][y]) / 3 + * NRTab[x][2][>=1] --> (NRTab[x][2][>=1]) / 3 (first partition is long block) + */ +static const char NRTab[6][3][4] = { + {{ 6, 5, 5, 5}, {3, 3, 3, 3}, {6, 3, 3, 3}}, + {{ 6, 5, 7, 3}, {3, 3, 4, 2}, {6, 3, 4, 2}}, + {{11, 10, 0, 0}, {6, 6, 0, 0}, {6, 3, 6, 0}}, + {{ 7, 7, 7, 0}, {4, 4, 4, 0}, {6, 5, 4, 0}}, + {{ 6, 6, 6, 3}, {4, 3, 3, 2}, {6, 4, 3, 2}}, + {{ 8, 8, 5, 0}, {5, 4, 3, 0}, {6, 6, 3, 0}} +}; + + + +/* optional pre-emphasis for high-frequency scale factor bands */ +static const char preTab[22] = { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0 }; + +/* pow(2,-i/4) for i=0..3, Q31 format */ +static const int32_t pow14[4] = { + 0x7fffffff, 0x6ba27e65, 0x5a82799a, 0x4c1bf829 +}; + + +/* + * Minimax polynomial approximation to pow(x, 4/3), over the range + * poly43lo: x = [0.5, 0.7071] + * poly43hi: x = [0.7071, 1.0] + * + * Relative error < 1E-7 + * Coefs are scaled by 4, 2, 1, 0.5, 0.25 + */ +static const uint32_t poly43lo[5] = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 }; +static const uint32_t poly43hi[5] = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 }; + +/* pow(2, i*4/3) as exp and frac */ +static const int32_t pow2exp[8] = { 14, 13, 11, 10, 9, 7, 6, 5 }; + +static const int32_t pow2frac[8] = { + 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, + 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6 +}; + +static const uint16_t m_HUFF_OFFSET_01= 0; +static const uint16_t m_HUFF_OFFSET_02= 9 + m_HUFF_OFFSET_01; +static const uint16_t m_HUFF_OFFSET_03= 65 + m_HUFF_OFFSET_02; +static const uint16_t m_HUFF_OFFSET_05= 65 + m_HUFF_OFFSET_03; +static const uint16_t m_HUFF_OFFSET_06=257 + m_HUFF_OFFSET_05; +static const uint16_t m_HUFF_OFFSET_07=129 + m_HUFF_OFFSET_06; +static const uint16_t m_HUFF_OFFSET_08=110 + m_HUFF_OFFSET_07; +static const uint16_t m_HUFF_OFFSET_09=280 + m_HUFF_OFFSET_08; +static const uint16_t m_HUFF_OFFSET_10= 93 + m_HUFF_OFFSET_09; +static const uint16_t m_HUFF_OFFSET_11=320 + m_HUFF_OFFSET_10; +static const uint16_t m_HUFF_OFFSET_12=296 + m_HUFF_OFFSET_11; +static const uint16_t m_HUFF_OFFSET_13=185 + m_HUFF_OFFSET_12; +static const uint16_t m_HUFF_OFFSET_15=497 + m_HUFF_OFFSET_13; +static const uint16_t m_HUFF_OFFSET_16=580 + m_HUFF_OFFSET_15; +static const uint16_t m_HUFF_OFFSET_24=651 + m_HUFF_OFFSET_16; + +static const int32_t huffTabOffset[HUFF_PAIRTABS] = { + 0, m_HUFF_OFFSET_01, m_HUFF_OFFSET_02, m_HUFF_OFFSET_03, + 0, m_HUFF_OFFSET_05, m_HUFF_OFFSET_06, m_HUFF_OFFSET_07, + m_HUFF_OFFSET_08, m_HUFF_OFFSET_09, m_HUFF_OFFSET_10, m_HUFF_OFFSET_11, + m_HUFF_OFFSET_12, m_HUFF_OFFSET_13, 0, m_HUFF_OFFSET_15, + m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, + m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, m_HUFF_OFFSET_16, + m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, + m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24, m_HUFF_OFFSET_24,}; + +static const HuffTabLookup_t huffTabLookup[HUFF_PAIRTABS] = { + { 0, noBits }, + { 0, oneShot }, + { 0, oneShot }, + { 0, oneShot }, + { 0, invalidTab }, + { 0, oneShot }, + { 0, oneShot }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, invalidTab }, + { 0, loopNoLinbits }, + { 1, loopLinbits }, + { 2, loopLinbits }, + { 3, loopLinbits }, + { 4, loopLinbits }, + { 6, loopLinbits }, + { 8, loopLinbits }, + { 10, loopLinbits }, + { 13, loopLinbits }, + { 4, loopLinbits }, + { 5, loopLinbits }, + { 6, loopLinbits }, + { 7, loopLinbits }, + { 8, loopLinbits }, + { 9, loopLinbits }, + { 11, loopLinbits }, + { 13, loopLinbits } +}; + +static const int32_t quadTabOffset[2] = {0, 64}; +static const int32_t quadTabMaxBits[2] = {6, 4}; + +/* indexing = [version][samplerate index] + * sample rate of frame (Hz) + */ +static const int32_t samplerateTab[3][3] = { + { 44100, 48000, 32000 }, /* MPEG-1 */ + { 22050, 24000, 16000 }, /* MPEG-2 */ + { 11025, 12000, 8000 }, /* MPEG-2.5 */ +}; + + + +/* indexing = [version][layer] + * number of samples in one frame (per channel) + */ +static const uint16_t samplesPerFrameTab[3][3] = { { 384, 1152, 1152 }, /* MPEG1 */ +{ 384, 1152, 576 }, /* MPEG2 */ +{ 384, 1152, 576 }, /* MPEG2.5 */ +}; + +/* layers 1, 2, 3 */ +static const uint8_t bitsPerSlotTab[3] = { 32, 8, 8 }; + +/* indexing = [version][mono/stereo] + * number of bytes in side info section of bitstream + */ +static const uint8_t sideBytesTab[3][2] = { { 17, 32 }, /* MPEG-1: mono, stereo */ +{ 9, 17 }, /* MPEG-2: mono, stereo */ +{ 9, 17 }, /* MPEG-2.5: mono, stereo */ +}; + +/* indexing = [version][sampleRate][long (.l) or short (.s) block] + * sfBandTable[v][s].l[cb] = index of first bin in critical band cb (long blocks) + * sfBandTable[v][s].s[cb] = index of first bin in critical band cb (short blocks) + */ +static const SFBandTable_t sfBandTable[3][3] = { + { /* MPEG-1 (44, 48, 32 kHz) */ + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 }, + {0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192} }, + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 }, + {0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192} }, + { {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 }, + {0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192} } }, + { /* MPEG-2 (22, 24, 16 kHz) */ + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192} }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, 540, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192} }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192} }, }, + { /* MPEG-2.5 (11, 12, 8 kHz) */ + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } }, + { {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 }, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192 } }, + { {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 }, + {0, 8, 16, 24, 36, 52, 72, 96, 124, 160, 162, 164, 166, 192 } }, }, +}; + + +/* indexing = [intensity scale on/off][left/right] + * format = Q30, range = [0.0, 1.414] + * + * illegal intensity position scalefactors (see comments on ISFMpeg1) + */ +static const int32_t ISFIIP[2][2] = { + {0x40000000, 0x00000000}, /* mid-side off */ + {0x40000000, 0x40000000}, /* mid-side on */ +}; + +static const uint8_t uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f}; + +/* anti-alias coefficients - see spec Annex B, table 3-B.9 + * csa[0][i] = CSi, csa[1][i] = CAi + * format = Q31 + */ +static const uint32_t csa[8][2] = { + {0x6dc253f0, 0xbe2500aa}, + {0x70dcebe4, 0xc39e4949}, + {0x798d6e73, 0xd7e33f4a}, + {0x7ddd40a7, 0xe8b71176}, + {0x7f6d20b7, 0xf3e4fe2f}, + {0x7fe47e40, 0xfac1a3c7}, + {0x7ffcb263, 0xfe2ebdc6}, + {0x7fffc694, 0xff86c25d}, +}; + +/* format = Q30, right shifted by 12 (sign bits only in top 12 - undo this when rounding to short) + * this is to enable early-terminating multiplies on ARM + * range = [-1.144287109, 1.144989014] + * max gain of filter (per output sample) ~= 2.731 + * + * new (properly sign-flipped) values + * - these actually are correct to 32 bits, (floating-pt coefficients in spec + * chosen such that only ~20 bits are required) + * + * Reordering - see table 3-B.3 in spec (appendix B) + * + * polyCoef[i] = + * D[ 0, 32, 64, ... 480], i = [ 0, 15] + * D[ 1, 33, 65, ... 481], i = [ 16, 31] + * D[ 2, 34, 66, ... 482], i = [ 32, 47] + * ... + * D[15, 47, 79, ... 495], i = [240,255] + * + * also exploits symmetry: D[i] = -D[512 - i], for i = [1, 255] + * + * polyCoef[256, 257, ... 263] are for special case of sample 16 (out of 0) + * see PolyphaseStereo() and PolyphaseMono() + */ + +static const char* mpeg_version_table[] = { + "MPEG-1", // 0 + "MPEG-2", // 1 + "MPEG-2.5", // 2 + "MPEG-INVALID" // 3 +}; + +static const char* layer_table[] = { + "Unknown", // 0 + "Layer I", // 1 + "Layer II", // 2 + "Layer III" // 3 +}; + +static const uint8_t FDCT32s1s2[16] = {5, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/celt.cpp b/libraries/ESP32-audioI2S/src/opus_decoder/celt.cpp new file mode 100644 index 0000000..af01acc --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/celt.cpp @@ -0,0 +1,2865 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "celt.h" +#include "opus_decoder.h" +#include "range_decoder.h" +#include + +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t CeltDecoder::celt_pvq_u_row(uint32_t row, uint32_t data) { + uint32_t ret = CELT_PVQ_U_DATA[row_idx[row] + data]; + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool CeltDecoder::init() { + size_t omd = celt_decoder_get_size(2); + m_decode_mem.alloc(omd, "decode_mem"); + if (m_decode_mem.valid()) { + OPUS_LOG_DEBUG("Celt decoder, allocated bytes: {}", omd); + m_decode_mem.clear(); // mem zero + return true; + } + OPUS_LOG_ERROR("oom for {} bytes", omd); + return false; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::clear() { + m_decode_mem.clear(); // mem zero +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::reset() { + m_decode_mem.reset(); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::exp_rotation1(int16_t* X, int32_t len, int32_t stride, int16_t c, int16_t s) { + int32_t i; + int16_t ms; + int16_t* Xptr; + Xptr = X; + ms = NEG16(s); + for (i = 0; i < len - stride; i++) { + int16_t x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr++ = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } + Xptr = &X[len - 2 * stride - 1]; + for (i = len - 2 * stride - 1; i >= 0; i--) { + int16_t x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::exp_rotation(int16_t* X, int32_t len, int32_t dir, int32_t stride, int32_t K, int32_t spread) { + const int32_t SPREAD_FACTOR[3] = {15, 10, 5}; + int32_t i; + int16_t c, s; + int16_t gain, theta; + int32_t stride2 = 0; + int32_t factor; + + if (2 * K >= len || spread == SPREAD_NONE) return; + factor = SPREAD_FACTOR[spread - 1]; + + gain = celt_div((int32_t)MULT16_16(Q15_ONE, len), (int32_t)(len + factor * K)); + theta = HALF16(MULT16_16_Q15(gain, gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(32767, theta))); /* sin(theta) */ + + if (len >= 8 * stride) { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2 * stride2 + stride2) * stride + (stride >> 2) < len) stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len = celt_udiv(len, stride); + for (i = 0; i < stride; i++) { + if (dir < 0) { + if (stride2) exp_rotation1(X + i * len, len, stride2, s, c); + exp_rotation1(X + i * len, len, 1, c, s); + } else { + exp_rotation1(X + i * len, len, 1, c, -s); + if (stride2) exp_rotation1(X + i * len, len, stride2, s, -c); + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Takes the pitch vector and the decoded residual vector, computes the gain that will give ||p+g*y||=1 and mixes the residual with the pitch. */ +void CeltDecoder::normalise_residual(int32_t* iy, int16_t* X, int32_t N, int32_t Ryy, int16_t gain) { + int32_t i; + int32_t k; + int32_t t; + int16_t g; + + k = celt_ilog2(Ryy) >> 1; + t = VSHR32(Ryy, 2 * (k - 7)); + g = MULT16_16_P15(celt_rsqrt_norm(t), gain); + + i = 0; + do X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k + 1)); + while (++i < N); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t CeltDecoder::extract_collapse_mask(int32_t* iy, int32_t N, int32_t B) { + uint32_t collapse_mask; + int32_t N0; + int32_t i; + if (B <= 1) return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for exp_rotation().*/ + N0 = celt_udiv(N, B); + collapse_mask = 0; + i = 0; + do { + int32_t j; + uint32_t tmp = 0; + j = 0; + do { tmp |= iy[i * N0 + j]; } while (++j < N0); + collapse_mask |= (tmp != 0) << i; + } while (++i < B); + return collapse_mask; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Decode pulse vector and combine the result with the pitch vector to produce the final normalised signal in the current band. */ +uint32_t CeltDecoder::alg_unquant(int16_t* X, int32_t N, int32_t K, int32_t spread, int32_t B, int16_t gain) { + int32_t Ryy; + uint32_t collapse_mask; + + assert2(K > 0, "alg_unquant() needs at least one pulse"); + assert2(N > 1, "alg_unquant() needs at least two dimensions"); + ps_ptr iy; + iy.alloc_array(N + 3); + + Ryy = decode_pulses(iy.get(), N, K); + normalise_residual(iy.get(), X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy.get(), N, B); + return collapse_mask; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::renormalise_vector(int16_t* X, int32_t N, int16_t gain) { + int32_t i; + int32_t k; + int32_t E; + int16_t g; + int32_t t; + int16_t* xptr; + E = EPSILON + celt_inner_prod(X, X, N); + k = celt_ilog2(E) >> 1; + t = VSHR32(E, 2 * (k - 7)); + g = MULT16_16_P15(celt_rsqrt_norm(t), gain); + + xptr = X; + for (i = 0; i < N; i++) { + *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k + 1)); + xptr++; + } + /*return celt_sqrt(E);*/ +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::resampling_factor(int32_t rate) { + int32_t ret; + switch (rate) { + case 48000: ret = 1; break; + case 24000: ret = 2; break; + case 16000: ret = 3; break; + case 12000: ret = 4; break; + case 8000: ret = 6; break; + default: ret = 0; break; + } + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::comb_filter_const_c(int32_t* y, int32_t* x, int32_t T, int32_t N, int16_t g10, int16_t g11, int16_t g12) { + int32_t x0, x1, x2, x3, x4; + int32_t i; + x4 = x[-T - 2]; + x3 = x[-T - 1]; + x2 = x[-T]; + x1 = x[-T + 1]; + for (i = 0; i < N; i++) { + x0 = x[i - T + 2]; + y[i] = x[i] + MULT16_32_Q15(g10, x2) + MULT16_32_Q15(g11, ADD32(x1, x3)) + MULT16_32_Q15(g12, ADD32(x0, x4)); + y[i] = SATURATE(y[i], SIG_SAT); + x4 = x3; + x3 = x2; + x2 = x1; + x1 = x0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::comb_filter(int32_t* y, int32_t* x, int32_t T0, int32_t T1, int32_t N, int16_t g0, int16_t g1, int32_t tapset0, int32_t tapset1) { + int32_t i; + OPUS_LOG_DEBUG("{} {} {} {}", T0, T1, g0, g1); + uint8_t overlap = m_CELTMode.overlap; // =120 + int16_t g00, g01, g02, g10, g11, g12; + int32_t x0, x1, x2, x3, x4; + const int16_t gains[3][3] = {{QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)}, + {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)}, + {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}}; + + if (g0 == 0 && g1 == 0) { + if (x != y) OPUS_MOVE(y, x, N); + return; + } + /* When the gain is zero, T0 and/or T1 is set to zero. We need + to have then be at least 2 to avoid processing garbage data. */ + T0 = max(T0, (int32_t)COMBFILTER_MINPERIOD); + T1 = max(T1, (int32_t)COMBFILTER_MINPERIOD); + g00 = MULT16_16_P15(g0, gains[tapset0][0]); + g01 = MULT16_16_P15(g0, gains[tapset0][1]); + g02 = MULT16_16_P15(g0, gains[tapset0][2]); + g10 = MULT16_16_P15(g1, gains[tapset1][0]); + g11 = MULT16_16_P15(g1, gains[tapset1][1]); + g12 = MULT16_16_P15(g1, gains[tapset1][2]); + x1 = x[-T1 + 1]; + x2 = x[-T1]; + x3 = x[-T1 - 1]; + x4 = x[-T1 - 2]; + /* If the filter didn't change, we don't need the overlap */ + if (g0 == g1 && T0 == T1 && tapset0 == tapset1) overlap = 0; + for (i = 0; i < overlap; i++) { + int16_t f; + x0 = x[i - T1 + 2]; + f = MULT16_16_Q15(window120[i], window120[i]); + y[i] = x[i] + MULT16_32_Q15(MULT16_16_Q15((32767 - f), g00), x[i - T0]) + MULT16_32_Q15(MULT16_16_Q15((32767 - f), g01), ADD32(x[i - T0 + 1], x[i - T0 - 1])) + + MULT16_32_Q15(MULT16_16_Q15((32767 - f), g02), ADD32(x[i - T0 + 2], x[i - T0 - 2])) + MULT16_32_Q15(MULT16_16_Q15(f, g10), x2) + MULT16_32_Q15(MULT16_16_Q15(f, g11), ADD32(x1, x3)) + + MULT16_32_Q15(MULT16_16_Q15(f, g12), ADD32(x0, x4)); + y[i] = SATURATE(y[i], SIG_SAT); + x4 = x3; + x3 = x2; + x2 = x1; + x1 = x0; + } + if (g1 == 0) { + if (x != y) OPUS_MOVE(y + overlap, x + overlap, N - overlap); + return; + } + + /* Compute the part with the constant filter. */ + comb_filter_const(y + i, x + i, T1, N - i, g10, g11, g12); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::init_caps(int32_t* cap, int32_t LM, int32_t C) { + int32_t i; + for (i = 0; i < m_CELTMode.nbEBands; i++) { + int32_t N; + N = (eband5ms[i + 1] - eband5ms[i]) << LM; + cap[i] = (cache_caps50[m_CELTMode.nbEBands * (2 * LM + C - 1) + i] + 64) * C * N >> 2; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t CeltDecoder::celt_lcg_rand(uint32_t seed) { + return 1664525 * seed + 1013904223; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness with this approximation is important because it has an impact on the bit allocation */ +int16_t CeltDecoder::bitexact_cos(int16_t x) { + int32_t tmp; + int16_t x2; + tmp = (4096 + ((int32_t)(x) * (x))) >> 13; + assert(tmp <= 32767); + x2 = tmp; + x2 = (32767 - x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + assert(x2 <= 32766); + return 1 + x2; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::bitexact_log2tan(int32_t isin, int32_t icos) { + int32_t lc; + int32_t ls; + lc = CELT_ILOG(icos); + ls = CELT_ILOG(isin); + icos <<= 15 - lc; + isin <<= 15 - ls; + return (ls - lc) * (1 << 11) + FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) - FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* De-normalise the energy to produce the synthesis from the unit-energy bands */ +void CeltDecoder::denormalise_bands(const int16_t* X, int32_t* freq, const int16_t* bandLogE, int32_t start, int32_t end, int32_t M, int32_t downsample, int32_t silence) { + int32_t i, N; + int32_t bound; + int32_t* f; + const int16_t* x; + const int16_t* eBands = eband5ms; + N = M * m_CELTMode.shortMdctSize; + bound = M * eBands[end]; + if (downsample != 1) bound = min(bound, N / downsample); + if (silence) { + bound = 0; + start = end = 0; + } + f = freq; + x = X + M * eBands[start]; + for (i = 0; i < M * eBands[start]; i++) *f++ = 0; + for (i = start; i < end; i++) { + int32_t j, band_end; + int16_t g; + int16_t lg; + + int32_t shift; + + j = M * eBands[i]; + band_end = M * eBands[i + 1]; + lg = SATURATE16(ADD32(bandLogE[i], SHL32((int32_t)eMeans[i], 6))); + + /* Handle the integer part of the log energy */ + shift = 16 - (lg >> DB_SHIFT); + if (shift > 31) { + shift = 0; + g = 0; + } else { + /* Handle the fractional part. */ + g = celt_exp2_frac(lg & ((1 << DB_SHIFT) - 1)); + } + /* Handle extreme gains with negative shift. */ + if (shift < 0) { + /* For shift <= -2 and g > 16384 we'd be likely to overflow, so we're capping the gain here, which is equivalent to a cap of 18 on lg. + This shouldn't trigger unless the bitstream is already corrupted. */ + if (shift <= -2) { + g = 16384; + shift = -2; + } + do { *f++ = SHL32(MULT16_16(*x++, g), -shift); } while (++j < band_end); + } else + /* Be careful of the fixed-point "else" just above when changing this code */ + do { *f++ = SHR32(MULT16_16(*x++, g), shift); } while (++j < band_end); + } + assert(start <= end); + OPUS_CLEAR(&freq[bound], N - bound); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This prevents energy collapse for transients with multiple short MDCTs */ +void CeltDecoder::anti_collapse(int16_t* X_, uint8_t* collapse_masks, int32_t LM, int32_t C, int32_t size, int32_t start, int32_t end, const int16_t* logE, const int16_t* prev1logE, + const int16_t* prev2logE, const int32_t* pulses, uint32_t seed) { + int32_t c, i, j, k; + for (i = start; i < end; i++) { + int32_t N0; + int16_t thresh, sqrt_1; + int32_t depth; + + int32_t shift; + int32_t thresh32; + + N0 = eband5ms[i + 1] - eband5ms[i]; + /* depth in 1/8 bits */ + assert(pulses[i] >= 0); + depth = celt_udiv(1 + pulses[i], (eband5ms[i + 1] - eband5ms[i])) >> LM; + + thresh32 = SHR32(celt_exp2(-SHL16(depth, 10 - BITRES)), 1); + thresh = MULT16_32_Q15(QCONST16(0.5f, 15), min((int32_t)32767, thresh32)); + { + int32_t t; + t = N0 << LM; + shift = celt_ilog2(t) >> 1; + t = SHL32(t, (7 - shift) << 1); + sqrt_1 = celt_rsqrt_norm(t); + } + + c = 0; + do { + int16_t* X; + int16_t prev1; + int16_t prev2; + int32_t Ediff; + int16_t r; + int32_t renormalize = 0; + prev1 = prev1logE[c * m_CELTMode.nbEBands + i]; + prev2 = prev2logE[c * m_CELTMode.nbEBands + i]; + if (C == 1) { + prev1 = max(prev1, prev1logE[m_CELTMode.nbEBands + i]); + prev2 = max(prev2, prev2logE[m_CELTMode.nbEBands + i]); + } + Ediff = EXTEND32(logE[c * m_CELTMode.nbEBands + i]) - EXTEND32(min(prev1, prev2)); + Ediff = max((int32_t)0, Ediff); + + if (Ediff < 16384) { + int32_t r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)), 1); + r = 2 * min((int32_t)16383, r32); + } else { + r = 0; + } + if (LM == 3) r = MULT16_16_Q14(23170, min((int16_t)23169, r)); + r = SHR16(min(thresh, r), 1); + r = SHR32(MULT16_16_Q15(sqrt_1, r), shift); + + X = X_ + c * size + (eband5ms[i] << LM); + for (k = 0; k < 1 << LM; k++) { + /* Detect collapse */ + if (!(collapse_masks[i * C + c] & 1 << k)) { + /* Fill with noise */ + for (j = 0; j < N0; j++) { + seed = celt_lcg_rand(seed); + X[(j << LM) + k] = (seed & 0x8000 ? r : -r); + } + renormalize = 1; + } + } + /* We just added some energy, so we need to renormalise */ + if (renormalize) renormalise_vector(X, N0 << LM, 32767); + } while (++c < C); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Compute the weights to use for optimizing normalized distortion across channels. We use the amplitude to weight square distortion, which means that we use the square root of the value we would + have been using if we wanted to minimize the MSE in the non-normalized domain. This roughly corresponds to some quick-and-dirty perceptual experiments I ran to measure inter-aural masking + (there doesn't seem to be any published data on the topic). */ +void CeltDecoder::compute_channel_weights(int32_t Ex, int32_t Ey, int16_t w[2]) { + int32_t minE; + int32_t shift; + + minE = min(Ex, Ey); + /* Adjustment to make the weights a bit more conservative. */ + Ex = ADD32(Ex, minE / 3); + Ey = ADD32(Ey, minE / 3); + + shift = celt_ilog2(EPSILON + max(Ex, Ey)) - 14; + + w[0] = VSHR32(Ex, shift); + w[1] = VSHR32(Ey, shift); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::stereo_split(int16_t* X, int16_t* Y, int32_t N) { + int32_t j; + for (j = 0; j < N; j++) { + int32_t r, l; + l = MULT16_16(QCONST16(.70710678f, 15), X[j]); + r = MULT16_16(QCONST16(.70710678f, 15), Y[j]); + X[j] = EXTRACT16(SHR32(ADD32(l, r), 15)); + Y[j] = EXTRACT16(SHR32(SUB32(r, l), 15)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::stereo_merge(int16_t* X, int16_t* Y, int16_t mid, int32_t N) { + int32_t j; + int32_t xp = 0, side = 0; + int32_t El, Er; + int16_t mid2; + + int32_t kl, kr; + + int32_t t, lgain, rgain; + + /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */ + dual_inner_prod(Y, X, Y, N, &xp, &side); + /* Compensating for the mid normalization */ + xp = MULT16_32_Q15(mid, xp); + /* mid and side are in Q15, not Q14 like X and Y */ + mid2 = SHR16(mid, 1); + El = MULT16_16(mid2, mid2) + side - 2 * xp; + Er = MULT16_16(mid2, mid2) + side + 2 * xp; + if (Er < QCONST32(6e-4f, 28) || El < QCONST32(6e-4f, 28)) { + memcpy(Y, X, N * sizeof(*Y)); + return; + } + + kl = celt_ilog2(El) >> 1; + kr = celt_ilog2(Er) >> 1; + + t = VSHR32(El, (kl - 7) << 1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr - 7) << 1); + rgain = celt_rsqrt_norm(t); + + if (kl < 7) kl = 7; + if (kr < 7) kr = 7; + + for (j = 0; j < N; j++) { + int16_t r, l; + /* Apply mid scaling (side is already scaled) */ + l = MULT16_16_P15(mid, X[j]); + r = Y[j]; + X[j] = EXTRACT16(PSHR32(MULT16_16(lgain, SUB16(l, r)), kl + 1)); + Y[j] = EXTRACT16(PSHR32(MULT16_16(rgain, ADD16(l, r)), kr + 1)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::deinterleave_hadamard(int16_t* X, int32_t N0, int32_t stride, int32_t hadamard) { + int32_t i, j; + int32_t N; + N = N0 * stride; + ps_ptr tmp; + tmp.alloc_array(N); + assert(stride > 0); + if (hadamard) { + const int32_t* ordery = ordery_table + stride - 2; + for (i = 0; i < stride; i++) { + for (j = 0; j < N0; j++) tmp[ordery[i] * N0 + j] = X[j * stride + i]; + } + } else { + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) tmp[i * N0 + j] = X[j * stride + i]; + } + memcpy(X, tmp.get(), N * sizeof(*X)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::interleave_hadamard(int16_t* X, int32_t N0, int32_t stride, int32_t hadamard) { + int32_t i, j; + int32_t N; + N = N0 * stride; + ps_ptr tmp; + tmp.alloc_array(N); + if (hadamard) { + const int32_t* ordery = ordery_table + stride - 2; + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) tmp[j * stride + i] = X[ordery[i] * N0 + j]; + } else { + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) tmp[j * stride + i] = X[i * N0 + j]; + } + memcpy(X, tmp.get(), N * sizeof(*X)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::haar1(int16_t* X, int32_t N0, int32_t stride) { + int32_t i, j; + N0 >>= 1; + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) { + int32_t tmp1, tmp2; + tmp1 = MULT16_16(QCONST16(.70710678f, 15), X[stride * 2 * j + i]); + tmp2 = MULT16_16(QCONST16(.70710678f, 15), X[stride * (2 * j + 1) + i]); + X[stride * 2 * j + i] = EXTRACT16(PSHR32(ADD32(tmp1, tmp2), 15)); + X[stride * (2 * j + 1) + i] = EXTRACT16(PSHR32(SUB32(tmp1, tmp2), 15)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::compute_qn(int32_t N, int32_t b, int32_t offset, int32_t pulse_cap, int32_t stereo) { + const int16_t exp2_table8[8] = {16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048}; + int32_t qn, qb; + int32_t N2 = 2 * N - 1; + if (stereo && N == 2) N2--; + /* The upper limit ensures that in a stereo split with itheta==16384, we'll + always have enough bits left over to code at least one pulse in the + side; otherwise it would collapse, since it doesn't get folded. */ + qb = celt_sudiv(b + N2 * offset, N2); + qb = min(b - pulse_cap - (4 << BITRES), qb); + + qb = min((int32_t)(8 << BITRES), qb); + + if (qb < (1 << BITRES >> 1)) { + qn = 1; + } else { + qn = exp2_table8[qb & 0x7] >> (14 - (qb >> BITRES)); + qn = (qn + 1) >> 1 << 1; + } + assert(qn <= 256); + return qn; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::compute_theta(struct split_ctx* sctx, int16_t* X, int16_t* Y, int32_t N, int32_t* b, int32_t B, int32_t __B0, int32_t LM, int32_t stereo, int32_t* fill) { + int32_t qn; + int32_t itheta = 0; + int32_t delta; + int32_t imid, iside; + int32_t qalloc; + int32_t pulse_cap; + int32_t offset; + int32_t tell; + int32_t inv = 0; + int32_t i; + int32_t intensity; + + i = m_band_ctx.i; + intensity = m_band_ctx.intensity; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = logN400[i] + LM * (1 << BITRES); + offset = (pulse_cap >> 1) - (stereo && N == 2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, *b, offset, pulse_cap, stereo); + if (stereo && i >= intensity) qn = 1; + + tell = rd.tell_frac(); // ->tell_frac(); + if (qn != 1) { + /* Entropy coding of the angle. We use a uniform pdf for the time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N > 2) { + int32_t p0 = 3; + int32_t x = itheta; + int32_t x0 = qn / 2; + int32_t ft = p0 * (x0 + 1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + int32_t fs; + fs = rd.decode(ft); + if (fs < (x0 + 1) * p0) + x = fs / p0; + else + x = x0 + 1 + (fs - (x0 + 1) * p0); + rd.dec_update(x <= x0 ? p0 * x : (x - 1 - x0) + (x0 + 1) * p0, x <= x0 ? p0 * (x + 1) : (x - x0) + (x0 + 1) * p0, ft); + itheta = x; + } else if (__B0 > 1 || stereo) { + /* Uniform pdf */ + itheta = rd.dec_uint(qn + 1); + } else { + int32_t fs = 1, ft; + ft = ((qn >> 1) + 1) * ((qn >> 1) + 1); + /* Triangular pdf */ + int32_t fl = 0; + int32_t fm; + fm = rd.decode(ft); + if (fm < ((qn >> 1) * ((qn >> 1) + 1) >> 1)) { + itheta = (isqrt32(8 * (uint32_t)fm + 1) - 1) >> 1; + fs = itheta + 1; + fl = itheta * (itheta + 1) >> 1; + } else { + itheta = (2 * (qn + 1) - isqrt32(8 * (uint32_t)(ft - fm - 1) + 1)) >> 1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta) * (qn + 2 - itheta) >> 1); + } + rd.dec_update(fl, fl + fs, ft); + } + assert(itheta >= 0); + itheta = celt_udiv((int32_t)itheta * 16384, qn); + + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + + if (*b > 2 << BITRES && m_band_ctx.remaining_bits > 2 << BITRES) { + inv = rd.dec_bit_logp(2); + } else + inv = 0; + /* inv flag override to avoid problems with downmixing. */ + if (m_band_ctx.disable_inv) inv = 0; + itheta = 0; + } + qalloc = rd.tell_frac() - tell; + *b -= qalloc; + + if (itheta == 0) { + imid = 32767; + iside = 0; + *fill &= (1 << B) - 1; + delta = -16384; + } else if (itheta == 16384) { + imid = 0; + iside = 32767; + *fill &= ((1 << B) - 1) << B; + delta = 16384; + } else { + imid = bitexact_cos((int16_t)itheta); + iside = bitexact_cos((int16_t)(16384 - itheta)); + /* This is the mid vs side allocation that minimizes squared error + in that band. */ + delta = FRAC_MUL16((N - 1) << 7, bitexact_log2tan(iside, imid)); + } + + sctx->inv = inv; + sctx->imid = imid; + sctx->iside = iside; + sctx->delta = delta; + sctx->itheta = itheta; + sctx->qalloc = qalloc; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t CeltDecoder::quant_band_n1(int16_t* X, int16_t* Y, int32_t b, int16_t* lowband_out) { + int32_t c; + int32_t stereo; + int16_t* x = X; + + stereo = Y != NULL; + c = 0; + do { + int32_t sign = 0; + if (m_band_ctx.remaining_bits >= 1 << BITRES) { + sign = rd.dec_bits(1); + m_band_ctx.remaining_bits -= 1 << BITRES; + b -= 1 << BITRES; + } + if (m_band_ctx.resynth) x[0] = sign ? -NORM_SCALING : NORM_SCALING; + x = Y; + } while (++c < 1 + stereo); + if (lowband_out) lowband_out[0] = SHR16(X[0], 4); + return 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This function is responsible for encoding and decoding a mono partition. It can split the band in two and transmit the energy difference with the two half-bands. + It can be called recursively so bands can end up being split in 8 parts. */ +uint32_t CeltDecoder::quant_partition(int16_t* X, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t gain, int32_t fill) { + const uint8_t* cache; + int32_t q; + int32_t curr_bits; + int32_t imid = 0, iside = 0; + int32_t _B0 = B; + int16_t mid = 0, side = 0; + uint32_t cm = 0; + int16_t* Y = NULL; + int32_t i; + int32_t spread; + + i = m_band_ctx.i; + spread = m_band_ctx.spread; + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = cache_bits50 + cache_index50[(LM + 1) * m_CELTMode.nbEBands + i]; + if (LM != -1 && b > cache[cache[0]] + 12 && N > 2) { + int32_t mbits, sbits, delta; + int32_t itheta; + int32_t qalloc; + struct split_ctx sctx; + int16_t* next_lowband2 = NULL; + int32_t rebalance; + + N >>= 1; + Y = X + N; + LM -= 1; + if (B == 1) fill = (fill & 1) | (fill << 1); + B = (B + 1) >> 1; + + compute_theta(&sctx, X, Y, N, &b, B, _B0, LM, 0, &fill); + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; + + mid = imid; + side = iside; + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (_B0 > 1 && (itheta & 0x3fff)) { + if (itheta > 8192) /* Rough approximation for pre-echo masking */ + delta -= delta >> (4 - LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = min((int32_t)0, delta + (N << BITRES >> (5 - LM))); + } + mbits = max((int32_t)0, min(b, (b - delta) / 2)); + sbits = b - mbits; + m_band_ctx.remaining_bits -= qalloc; + + if (lowband) next_lowband2 = lowband + N; /* >32-bit split case */ + + rebalance = m_band_ctx.remaining_bits; + if (mbits >= sbits) { + cm = quant_partition(X, N, mbits, B, lowband, LM, MULT16_16_P15(gain, mid), fill); + rebalance = mbits - (rebalance - m_band_ctx.remaining_bits); + if (rebalance > 3 << BITRES && itheta != 0) sbits += rebalance - (3 << BITRES); + cm |= quant_partition(Y, N, sbits, B, next_lowband2, LM, MULT16_16_P15(gain, side), fill >> B) << (_B0 >> 1); + } else { + cm = quant_partition(Y, N, sbits, B, next_lowband2, LM, MULT16_16_P15(gain, side), fill >> B) << (_B0 >> 1); + rebalance = sbits - (rebalance - m_band_ctx.remaining_bits); + if (rebalance > 3 << BITRES && itheta != 16384) mbits += rebalance - (3 << BITRES); + cm |= quant_partition(X, N, mbits, B, lowband, LM, MULT16_16_P15(gain, mid), fill); + } + } else { + /* This is the basic no-split case */ + q = bits2pulses(i, LM, b); + curr_bits = pulses2bits(i, LM, q); + m_band_ctx.remaining_bits -= curr_bits; + + /* Ensures we can never bust the budget */ + while (m_band_ctx.remaining_bits < 0 && q > 0) { + m_band_ctx.remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(i, LM, q); + m_band_ctx.remaining_bits -= curr_bits; + } + + if (q != 0) { + int32_t K = get_pulses(q); + + /* Finally do the actual quantization */ + cm = alg_unquant(X, N, K, spread, B, gain); + } else { + /* If there's no pulse, fill the band anyway */ + int32_t j; + if (m_band_ctx.resynth) { + uint32_t cm_mask; + /* B can be as large as 16, so this shift might overflow an int32_t on a 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (uint32_t)(1UL << B) - 1; + fill &= cm_mask; + if (!fill) { + OPUS_CLEAR(X, N); + } else { + if (lowband == NULL) { + /* Noise */ + for (j = 0; j < N; j++) { + m_band_ctx.seed = celt_lcg_rand(m_band_ctx.seed); + X[j] = (int16_t)((int32_t)m_band_ctx.seed >> 20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j = 0; j < N; j++) { + int16_t tmp; + m_band_ctx.seed = celt_lcg_rand(m_band_ctx.seed); + /* About 48 dB below the "normal" folding level */ + tmp = QCONST16(1.0f / 256, 10); + tmp = (m_band_ctx.seed) & 0x8000 ? tmp : -tmp; + X[j] = lowband[j] + tmp; + } + cm = fill; + } + renormalise_vector(X, N, gain); + } + } + } + } + + return cm; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This function is responsible for encoding and decoding a band for the mono case. */ +uint32_t CeltDecoder::quant_band(int16_t* X, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t* lowband_out, int16_t gain, int16_t* lowband_scratch, int32_t fill) { + int32_t N0 = N; + int32_t N_B = N; + int32_t N__B0; + int32_t _B0 = B; + int32_t time_divide = 0; + int32_t recombine = 0; + int32_t longBlocks; + uint32_t cm = 0; + int32_t k; + int32_t tf_change; + + tf_change = m_band_ctx.tf_change; + + longBlocks = _B0 == 1; + + N_B = celt_udiv(N_B, B); + + /* Special case for one sample */ + if (N == 1) { return quant_band_n1(X, NULL, b, lowband_out); } + + if (tf_change > 0) recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband_scratch && lowband && (recombine || ((N_B & 1) == 0 && tf_change < 0) || _B0 > 1)) { + memcpy(lowband_scratch, lowband, N * sizeof(*lowband_scratch)); + lowband = lowband_scratch; + } + + for (k = 0; k < recombine; k++) { + const uint8_t bit_interleave_table[16] = {0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3}; + if (lowband) haar1(lowband, N >> k, 1 << k); + fill = bit_interleave_table[fill & 0xF] | bit_interleave_table[fill >> 4] << 2; + } + B >>= recombine; + N_B <<= recombine; + + /* Increasing the time resolution */ + while ((N_B & 1) == 0 && tf_change < 0) { + if (lowband) haar1(lowband, N_B, B); + fill |= fill << B; + B <<= 1; + N_B >>= 1; + time_divide++; + tf_change++; + } + _B0 = B; + N__B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (_B0 > 1) { + if (lowband) deinterleave_hadamard(lowband, N_B >> recombine, _B0 << recombine, longBlocks); + } + + cm = quant_partition(X, N, b, B, lowband, LM, gain, fill); + + if (m_band_ctx.resynth) { + /* Undo the sample reorganization going from time order to frequency order */ + if (_B0 > 1) interleave_hadamard(X, N_B >> recombine, _B0 << recombine, longBlocks); + + /* Undo time-freq changes that we did earlier */ + N_B = N__B0; + B = _B0; + for (k = 0; k < time_divide; k++) { + B >>= 1; + N_B <<= 1; + cm |= cm >> B; + haar1(X, N_B, B); + } + + for (k = 0; k < recombine; k++) { + const uint8_t bit_deinterleave_table[16] = {0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF}; + cm = bit_deinterleave_table[cm]; + haar1(X, N0 >> k, 1 << k); + } + B <<= recombine; + + /* Scale output for later folding */ + if (lowband_out) { + int32_t j; + int16_t n; + n = celt_sqrt(SHL32(EXTEND32(N0), 22)); + for (j = 0; j < N0; j++) lowband_out[j] = MULT16_16_Q15(n, X[j]); + } + cm &= (1 << B) - 1; + } + return cm; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This function is responsible for encoding and decoding a band for the stereo case. */ +uint32_t CeltDecoder::quant_band_stereo(int16_t* X, int16_t* Y, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t* lowband_out, int16_t* lowband_scratch, int32_t fill) { + int32_t imid = 0, iside = 0; + int32_t inv = 0; + int16_t mid = 0, side = 0; + uint32_t cm = 0; + int32_t mbits, sbits, delta; + int32_t itheta; + int32_t qalloc; + struct split_ctx sctx; + int32_t orig_fill; + + /* Special case for one sample */ + if (N == 1) { return quant_band_n1(X, Y, b, lowband_out); } + + orig_fill = fill; + + compute_theta(&sctx, X, Y, N, &b, B, B, LM, 1, &fill); + inv = sctx.inv; + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; + + mid = imid; + side = iside; + + /* This is a special case for N=2 that only works for stereo and takes advantage of the fact that mid and side are orthogonal to encode the side with just one bit. */ + if (N == 2) { + int32_t c; + int32_t sign = 0; + int16_t *x2, *y2; + mbits = b; + sbits = 0; + /* Only need one bit for the side. */ + if (itheta != 0 && itheta != 16384) sbits = 1 << BITRES; + mbits -= sbits; + c = itheta > 8192; + m_band_ctx.remaining_bits -= qalloc + sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) { sign = rd.dec_bits(1); } + sign = 1 - 2 * sign; + /* We use orig_fill here because we want to fold the side, but if itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(x2, N, mbits, B, lowband, LM, lowband_out, 32767, lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign * x2[1]; + y2[1] = sign * x2[0]; + if (m_band_ctx.resynth) { + int16_t tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp, Y[0]); + Y[0] = ADD16(tmp, Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp, Y[1]); + Y[1] = ADD16(tmp, Y[1]); + } + } else { + /* "Normal" split code */ + int32_t rebalance; + + mbits = max((int32_t)0, min(b, (b - delta) / 2)); + sbits = b - mbits; + m_band_ctx.remaining_bits -= qalloc; + + rebalance = m_band_ctx.remaining_bits; + if (mbits >= sbits) { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized mid for folding later. */ + cm = quant_band(X, N, mbits, B, lowband, LM, lowband_out, 32767, lowband_scratch, fill); + rebalance = mbits - (rebalance - m_band_ctx.remaining_bits); + if (rebalance > 3 << BITRES && itheta != 0) sbits += rebalance - (3 << BITRES); + + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm |= quant_band(Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill >> B); + } else { + /* For a stereo split, the high bits of fill are always zero, so no folding will be done to the side. */ + cm = quant_band(Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill >> B); + rebalance = sbits - (rebalance - m_band_ctx.remaining_bits); + if (rebalance > 3 << BITRES && itheta != 16384) mbits += rebalance - (3 << BITRES); + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized mid for folding later. */ + cm |= quant_band(X, N, mbits, B, lowband, LM, lowband_out, 32767, lowband_scratch, fill); + } + } + if (m_band_ctx.resynth) { + if (N != 2) stereo_merge(X, Y, mid, N); + if (inv) { + int32_t j; + for (j = 0; j < N; j++) Y[j] = -Y[j]; + } + } + return cm; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::special_hybrid_folding(int16_t* norm, int16_t* norm2, int32_t start, int32_t M, int32_t dual_stereo) { + int32_t n1, n2; + const int16_t* eBands = eband5ms; + n1 = M * (eBands[start + 1] - eBands[start]); + n2 = M * (eBands[start + 2] - eBands[start + 1]); + /* Duplicate enough of the first band folding data to be able to fold the second band. Copies no data for CELT-only mode. */ + memcpy(&norm[n1], &norm[2 * n1 - n2], (n2 - n1) * sizeof(*norm)); + if (dual_stereo) memcpy(&norm2[n1], &norm2[2 * n1 - n2], (n2 - n1) * sizeof(*norm2)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::quant_all_bands(int32_t start, int32_t end, int16_t* X_, int16_t* Y_, uint8_t* collapse_masks, const int32_t* bandE, int32_t* pulses, int32_t shortBlocks, int32_t spread, + int32_t dual_stereo, int32_t intensity, int32_t* tf_res, int32_t total_bits, int32_t balance, int32_t LM, int32_t codedBands, uint32_t* seed, int32_t complexity, + int32_t disable_inv) { + int32_t i; + int32_t remaining_bits; + const int16_t* eBands = eband5ms; + int16_t * norm, *norm2; + + int32_t resynth_alloc; + int16_t* lowband_scratch; + int32_t B; + int32_t M; + int32_t lowband_offset; + int32_t update_lowband = 1; + int32_t C = Y_ != NULL ? 2 : 1; + int32_t norm_offset; + int32_t resynth = 1; + + M = 1 << LM; + B = shortBlocks ? M : 1; + norm_offset = M * eBands[start]; + /* No need to allocate norm for the last band because we don't need an + output in that band. */ + ps_ptr _norm; + _norm.alloc_array(C * (M * eBands[m_CELTMode.nbEBands - 1] - norm_offset)); + norm = _norm.get(); + norm2 = norm + M * eBands[m_CELTMode.nbEBands - 1] - norm_offset; + + /* For decoding, we can use the last band as scratch space because we don't need that scratch space for the last band and we don't care about the data there until we're + decoding the last band. */ + resynth_alloc = ALLOC_NONE; + + ps_ptr _lowband_scratch; + _lowband_scratch.alloc_array(resynth_alloc); + lowband_scratch = X_ + M * eBands[m_CELTMode.nbEBands - 1]; + + ps_ptr X_save; + X_save.alloc_array(resynth_alloc); + ps_ptr Y_save; + Y_save.alloc_array(resynth_alloc); + ps_ptr X_save2; + X_save2.alloc_array(resynth_alloc); + ps_ptr Y_save2; + Y_save2.alloc_array(resynth_alloc); + ps_ptr norm_save2; + norm_save2.alloc_array(resynth_alloc); + + lowband_offset = 0; + m_band_ctx.bandE = bandE; + m_band_ctx.intensity = intensity; + m_band_ctx.seed = *seed; + m_band_ctx.spread = spread; + m_band_ctx.disable_inv = disable_inv; + m_band_ctx.resynth = resynth; + m_band_ctx.theta_round = 0; + /* Avoid injecting noise in the first band on transients. */ + m_band_ctx.avoid_split_noise = B > 1; + for (i = start; i < end; i++) { + int32_t tell; + int32_t b; + int32_t N; + int32_t curr_balance; + int32_t effective_lowband = -1; + int16_t *X, *Y; + int32_t tf_change = 0; + uint32_t x_cm; + uint32_t y_cm; + int32_t last; + + m_band_ctx.i = i; + last = (i == end - 1); + + X = X_ + M * eBands[i]; + if (Y_ != NULL) + Y = Y_ + M * eBands[i]; + else + Y = NULL; + N = M * eBands[i + 1] - M * eBands[i]; + assert(N > 0); + tell = rd.tell_frac(); + + /* Compute how many bits we want to allocate to this band */ + if (i != start) balance -= tell; + remaining_bits = total_bits - tell - 1; + m_band_ctx.remaining_bits = remaining_bits; + if (i <= codedBands - 1) { + curr_balance = celt_sudiv(balance, min((int32_t)3, codedBands - i)); + b = max((int32_t)0, min((int32_t)16383, min(remaining_bits + (int32_t)1, (int32_t)pulses[i] + curr_balance))); + } else { + b = 0; + } + + if (resynth && (M * eBands[i] - N >= M * eBands[start] || i == start + 1) && (update_lowband || lowband_offset == 0)) lowband_offset = i; + if (i == start + 1) special_hybrid_folding(norm, norm2, start, M, dual_stereo); + + tf_change = tf_res[i]; + m_band_ctx.tf_change = tf_change; + if (i >= m_CELTMode.effEBands) { + X = norm; + if (Y_ != NULL) Y = norm; + lowband_scratch = NULL; + } + if (last) lowband_scratch = NULL; + + /* Get a conservative estimate of the collapse_mask's for the bands we're going to be folding from. */ + if (lowband_offset != 0 && (spread != SPREAD_AGGRESSIVE || B > 1 || tf_change < 0)) { + int32_t fold_start; + int32_t fold_end; + int32_t fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = max((int32_t)0, M * eBands[lowband_offset] - norm_offset - N); + fold_start = lowband_offset; + while (M * eBands[--fold_start] > effective_lowband + norm_offset); + fold_end = lowband_offset - 1; + + while (++fold_end < i && M * eBands[fold_end] < effective_lowband + norm_offset + N); + + x_cm = y_cm = 0; + fold_i = fold_start; + do { + x_cm |= collapse_masks[fold_i * C + 0]; + y_cm |= collapse_masks[fold_i * C + C - 1]; + } while (++fold_i < fold_end); + } + /* Otherwise, we'll be using the LCG to fold, so all blocks will (almost always) be non-zero. */ + else + x_cm = y_cm = (1 << B) - 1; + + if (dual_stereo && i == intensity) { + int32_t j; + + /* Switch off dual stereo to do intensity. */ + dual_stereo = 0; + if (resynth) + for (j = 0; j < M * eBands[i] - norm_offset; j++) norm[j] = HALF32(norm[j] + norm2[j]); + } + if (dual_stereo) { + x_cm = quant_band(X, N, b / 2, B, effective_lowband != -1 ? norm + effective_lowband : NULL, LM, last ? NULL : norm + M * eBands[i] - norm_offset, 32767, lowband_scratch, x_cm); + y_cm = quant_band(Y, N, b / 2, B, effective_lowband != -1 ? norm2 + effective_lowband : NULL, LM, last ? NULL : norm2 + M * eBands[i] - norm_offset, 32767, lowband_scratch, y_cm); + } else { + if (Y != NULL) { + m_band_ctx.theta_round = 0; + x_cm = quant_band_stereo(X, Y, N, b, B, effective_lowband != -1 ? norm + effective_lowband : NULL, LM, last ? NULL : norm + M * eBands[i] - norm_offset, lowband_scratch, x_cm | y_cm); + } else { + x_cm = quant_band(X, N, b, B, effective_lowband != -1 ? norm + effective_lowband : NULL, LM, last ? NULL : norm + M * eBands[i] - norm_offset, 32767, lowband_scratch, x_cm | y_cm); + } + y_cm = x_cm; + } + collapse_masks[i * C + 0] = (uint8_t)x_cm; + collapse_masks[i * C + C - 1] = (uint8_t)y_cm; + balance += pulses[i] + tell; + + /* Update the folding position only as long as we have 1 bit/sample depth. */ + update_lowband = b > (N << BITRES); + /* We only need to avoid noise on a split for the first band. After that, we + have folding. */ + m_band_ctx.avoid_split_noise = 0; + } + *seed = m_band_ctx.seed; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_decoder_get_size(int32_t channels) { + int32_t size = (channels * (DECODE_BUFFER_SIZE + m_CELTMode.overlap) - 1) * sizeof(int32_t) + channels * 24 * sizeof(int16_t) + 4 * 2 * m_CELTMode.nbEBands * sizeof(int16_t); + return size; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_decoder_init(int32_t channels) { + + m_celtDec.downsample = 1; // resampling_factor(Fs); + m_celtDec.channels = channels; + if (channels == 1) + m_celtDec.disable_inv = 1; + else + m_celtDec.disable_inv = 0; // 1 mono , 0 stereo + m_celtDec.end = m_CELTMode.nbEBands; // 21 + m_celtDec.error = 0; + m_celtDec.overlap = m_CELTMode.overlap; + m_celtDec.postfilter_gain = 0; + m_celtDec.postfilter_gain_old = 0; + m_celtDec.postfilter_period = 0; + m_celtDec.postfilter_tapset = 0; + m_celtDec.postfilter_tapset_old = 0; + m_celtDec.preemph_memD[0] = 0; + m_celtDec.preemph_memD[1] = 0; + m_celtDec.rng = 0; + m_celtDec.signalling = 1; + m_celtDec.start = 0; + m_celtDec.end = m_CELTMode.effEBands; + m_celtDec.stream_channels = channels; + int32_t ret = celt_decoder_ctl(OPUS_RESET_STATE); + if (ret < 0) return ret; + + return OPUS_OK; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Special case for stereo with no downsampling and no accumulation. This is quite common and we can make it faster by processing both channels in the same loop, reducing overhead due to the + dependency loop in the IIR filter. */ +void CeltDecoder::deemphasis_stereo_simple(int32_t* in[], int16_t* pcm, int32_t N, const int16_t coef0, int32_t* mem) { + int32_t* x0; + int32_t* x1; + int32_t m0, m1; + int32_t j; + x0 = in[0]; + x1 = in[1]; + m0 = mem[0]; + m1 = mem[1]; + for (j = 0; j < N; j++) { + int32_t tmp0, tmp1; + /* Add VERY_SMALL to x[] first to reduce dependency chain. */ + tmp0 = x0[j] + VERY_SMALL + m0; + tmp1 = x1[j] + VERY_SMALL + m1; + m0 = MULT16_32_Q15(coef0, tmp0); + m1 = MULT16_32_Q15(coef0, tmp1); + pcm[2 * j] = SCALEOUT(sig2word16(tmp0)); + pcm[2 * j + 1] = SCALEOUT(sig2word16(tmp1)); + } + mem[0] = m0; + mem[1] = m1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::deemphasis(int32_t* in[], int16_t* pcm, int32_t N, int32_t C, int32_t downsample, const int16_t* coef, int32_t* mem, int32_t accum) { + int32_t c; + int32_t Nd; + int32_t apply_downsampling = 0; + int16_t coef0; + + /* Short version for common case. */ + if (downsample == 1 && C == 2 && !accum) { + deemphasis_stereo_simple(in, pcm, N, coef[0], mem); + return; + } + + ps_ptr scratch; + scratch.alloc_array(N); + coef0 = coef[0]; + Nd = N / downsample; + c = 0; + do { + int32_t j; + int32_t* x; + int16_t* y; + int32_t m = mem[c]; + x = in[c]; + y = pcm + c; + + if (downsample > 1) { + /* Shortcut for the standard (non-custom modes) case */ + for (j = 0; j < N; j++) { + int32_t tmp = x[j] + VERY_SMALL + m; + m = MULT16_32_Q15(coef0, tmp); + scratch[j] = tmp; + } + apply_downsampling = 1; + } else { + /* Shortcut for the standard (non-custom modes) case */ + + if (accum) { + for (j = 0; j < N; j++) { + int32_t tmp = x[j] + m + VERY_SMALL; + m = MULT16_32_Q15(coef0, tmp); + y[j * C] = SAT16(ADD32(y[j * C], SCALEOUT(sig2word16(tmp)))); + } + } else { + for (j = 0; j < N; j++) { + int32_t tmp = x[j] + VERY_SMALL + m; + m = MULT16_32_Q15(coef0, tmp); + y[j * C] = SCALEOUT(sig2word16(tmp)); + } + } + } + mem[c] = m; + + if (apply_downsampling) { + /* Perform down-sampling */ + + if (accum) { + for (j = 0; j < Nd; j++) y[j * C] = SAT16(ADD32(y[j * C], SCALEOUT(sig2word16(scratch[j * downsample])))); + } else { + for (j = 0; j < Nd; j++) y[j * C] = SCALEOUT(sig2word16(scratch[j * downsample])); + } + } + } while (++c < C); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::celt_synthesis(int16_t* X, int32_t* out_syn[], int16_t* oldBandE, int32_t start, int32_t effEnd, int32_t C, int32_t CC, int32_t isTransient, int32_t LM, int32_t downsample, + int32_t silence) { + int32_t c, i; + int32_t M; + int32_t b; + int32_t B; + int32_t N, NB; + int32_t shift; + int32_t nbEBands; + int32_t overlap; + + overlap = m_CELTMode.overlap; + nbEBands = m_CELTMode.nbEBands; + N = m_CELTMode.shortMdctSize << LM; + ps_ptr freq; + freq.alloc_array(N); /**< Interleaved signal MDCTs */ + M = 1 << LM; + + if (isTransient) { + B = M; + NB = m_CELTMode.shortMdctSize; + shift = m_CELTMode.maxLM; + } else { + B = 1; + NB = m_CELTMode.shortMdctSize << LM; + shift = m_CELTMode.maxLM - LM; + } + + if (CC == 2 && C == 1) { + /* Copying a mono streams to two channels */ + int32_t* freq2; + denormalise_bands(X, freq.get(), oldBandE, start, effEnd, M, downsample, silence); + /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ + freq2 = out_syn[1] + overlap / 2; + memcpy(freq2, freq.get(), N * sizeof(*freq2)); + for (b = 0; b < B; b++) clt_mdct_backward(&freq2[b], out_syn[0] + NB * b, overlap, shift, B); + for (b = 0; b < B; b++) clt_mdct_backward(&freq[b], out_syn[1] + NB * b, overlap, shift, B); + } else if (CC == 1 && C == 2) { + /* Downmixing a stereo stream to mono */ + int32_t* freq2; + freq2 = out_syn[0] + overlap / 2; + denormalise_bands(X, freq.get(), oldBandE, start, effEnd, M, downsample, silence); + /* Use the output buffer as temp array before downmixing. */ + denormalise_bands(X + N, freq2, oldBandE + nbEBands, start, effEnd, M, downsample, silence); + for (i = 0; i < N; i++) freq[i] = ADD32(HALF32(freq[i]), HALF32(freq2[i])); + for (b = 0; b < B; b++) + for (b = 0; b < B; b++) clt_mdct_backward(&freq[b], out_syn[0] + NB * b, overlap, shift, B); + } else { + /* Normal case (mono or stereo) */ + c = 0; + do { + denormalise_bands(X + c * N, freq.get(), oldBandE + c * nbEBands, start, effEnd, M, downsample, silence); + for (b = 0; b < B; b++) + for (b = 0; b < B; b++) clt_mdct_backward(&freq[b], out_syn[c] + NB * b, overlap, shift, B); + } while (++c < CC); + } + /* Saturate IMDCT output so that we can't overflow in the pitch postfilter or in the */ + c = 0; + do { + for (i = 0; i < N; i++) out_syn[c][i] = SATURATE(out_syn[c][i], SIG_SAT); + } while (++c < CC); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::tf_decode(int32_t start, int32_t end, int32_t isTransient, int32_t* tf_res, int32_t LM) { + int32_t i, curr, tf_select; + int32_t tf_select_rsv; + int32_t tf_changed; + int32_t logp; + uint32_t budget; + uint32_t tell; + + budget = rd.get_storage() * 8; + tell = rd.tell(); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM > 0 && tell + logp + 1 <= budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i = start; i < end; i++) { + if (tell + logp <= budget) { + curr ^= rd.dec_bit_logp(logp); + tell = rd.tell(); + tf_changed |= curr; + } + tf_res[i] = curr; + logp = isTransient ? 4 : 5; + } + tf_select = 0; + if (tf_select_rsv && tf_select_table[LM][4 * isTransient + 0 + tf_changed] != tf_select_table[LM][4 * isTransient + 2 + tf_changed]) { tf_select = rd.dec_bit_logp(1); } + for (i = start; i < end; i++) { tf_res[i] = tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]]; } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_decode_with_ec(int16_t* outbuf, int32_t frame_size) { + int32_t c, i, N; + int32_t spread_decision; + int32_t bits; + int32_t* decode_mem[2]; + int32_t* out_syn[2]; + int16_t* lpc; + int16_t *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int32_t shortBlocks; + int32_t isTransient; + int32_t intra_ener; + const int32_t CC = m_celtDec.channels; + int32_t LM, M; + int32_t start; + int32_t end; + int32_t effEnd; + int32_t codedBands; + int32_t alloc_trim; + int32_t postfilter_pitch; + int16_t postfilter_gain; + int32_t intensity = 0; + int32_t dual_stereo = 0; + int32_t total_bits; + int32_t balance; + int32_t tell; + int32_t dynalloc_logp; + int32_t postfilter_tapset; + int32_t anti_collapse_rsv; + int32_t anti_collapse_on = 0; + int32_t silence; + const uint8_t C = m_celtDec.stream_channels; // =channels=2 + const uint8_t nbEBands = m_CELTMode.nbEBands; // =21 + const uint8_t overlap = m_CELTMode.overlap; // =120 + const int16_t* eBands = eband5ms; + + start = m_celtDec.start; + end = m_CELTMode.effEBands; + frame_size *= m_celtDec.downsample; + + lpc = (int16_t*)(m_decode_mem.get() + (DECODE_BUFFER_SIZE + overlap) * CC); + oldBandE = lpc + CC * LPC_ORDER; + oldLogE = oldBandE + 2 * nbEBands; + oldLogE2 = oldLogE + 2 * nbEBands; + backgroundLogE = oldLogE2 + 2 * nbEBands; + + { + for (LM = 0; LM <= m_CELTMode.maxLM; LM++) + if (m_CELTMode.shortMdctSize << LM == frame_size) break; + if (LM > m_CELTMode.maxLM) { + OPUS_LOG_ERROR("Opus Celt bas arg"); + return OPUS_BAD_ARG; + } + } + + M = 1 << LM; + + if (rd.get_storage() > 1275 || outbuf == NULL) { + OPUS_LOG_ERROR("Opus Celt bad arg"); + return OPUS_BAD_ARG; + } + + N = M * m_CELTMode.shortMdctSize; + c = 0; + do { + decode_mem[c] = (int32_t*)(m_decode_mem.get() + c * (DECODE_BUFFER_SIZE + overlap)); // todo + out_syn[c] = decode_mem[c] + DECODE_BUFFER_SIZE - N; + } while (++c < CC); + + if (rd.get_storage() <= 1) { + OPUS_LOG_ERROR("Opus Celt bas arg"); + return OPUS_BAD_ARG; + } + + effEnd = end; + if (effEnd > m_CELTMode.effEBands) effEnd = m_CELTMode.effEBands; + + /* Check if there are at least two packets received consecutively before turning on the pitch-based PLC */ + m_celtDec.skip_plc = m_celtDec.loss_count != 0; + + if (C == 1) { + for (i = 0; i < nbEBands; i++) oldBandE[i] = max(oldBandE[i], oldBandE[nbEBands + i]); + } + + total_bits = rd.get_storage() * 8; + tell = rd.tell(); + + if (tell >= total_bits) + silence = 1; + else if (tell == 1) + silence = rd.dec_bit_logp(15); + else + silence = 0; + if (silence) { + /* Pretend we've read all the remaining bits */ + tell = rd.get_storage() * 8; + rd.add_nbits_total(tell - rd.tell()); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (start == 0 && tell + 16 <= total_bits) { + if (rd.dec_bit_logp(1)) { + int32_t qg, octave; + octave = rd.dec_uint(6); + postfilter_pitch = (16 << octave) + rd.dec_bits(4 + octave) - 1; + qg = rd.dec_bits(3); + if (rd.tell() + 2 <= total_bits) postfilter_tapset = rd.dec_icdf(tapset_icdf, 2); + postfilter_gain = QCONST16(.09375f, 15) * (qg + 1); + } + tell = rd.tell(); + } + + if (LM > 0 && tell + 3 <= total_bits) { + isTransient = rd.dec_bit_logp(3); + tell = rd.tell(); + } else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell + 3 <= total_bits ? rd.dec_bit_logp(3) : 0; + /* Get band energies */ + unquant_coarse_energy(start, end, oldBandE, intra_ener, C, LM); + + ps_ptr tf_res; + tf_res.alloc_array(nbEBands); + tf_decode(start, end, isTransient, tf_res.get(), LM); + + tell = rd.tell(); + spread_decision = SPREAD_NORMAL; + if (tell + 4 <= total_bits) spread_decision = rd.dec_icdf(spread_icdf, 5); + + ps_ptr cap; + cap.alloc_array(nbEBands); + + init_caps(cap.get(), LM, C); + + ps_ptr offsets; + offsets.alloc_array(nbEBands); + + dynalloc_logp = 6; + total_bits <<= BITRES; + tell = rd.tell_frac(); + for (i = start; i < end; i++) { + int32_t width, quanta; + int32_t dynalloc_loop_logp; + int32_t boost; + width = C * (eBands[i + 1] - eBands[i]) << LM; + /* quanta is 6 bits, but no more than 1 bit/sample and no less than 1/8 bit/sample */ + quanta = min(width << BITRES, max((int32_t)(6 << BITRES), width)); + dynalloc_loop_logp = dynalloc_logp; + boost = 0; + while (tell + (dynalloc_loop_logp << BITRES) < total_bits && boost < cap[i]) { + int32_t flag; + flag = rd.dec_bit_logp(dynalloc_loop_logp); + tell = rd.tell_frac(); + if (!flag) break; + boost += quanta; + total_bits -= quanta; + dynalloc_loop_logp = 1; + } + offsets[i] = boost; + /* Making dynalloc more likely */ + if (boost > 0) dynalloc_logp = max((int32_t)2, dynalloc_logp - 1); + } + + ps_ptr fine_quant; + fine_quant.alloc_array(nbEBands); + + alloc_trim = tell + (6 << BITRES) <= total_bits ? rd.dec_icdf(trim_icdf, 7) : 5; + + bits = (((int32_t)rd.get_storage() * 8) << BITRES) - rd.tell_frac() - 1; + anti_collapse_rsv = isTransient && LM >= 2 && bits >= ((LM + 2) << BITRES) ? (1 << BITRES) : 0; + bits -= anti_collapse_rsv; + + ps_ptr pulses; + pulses.alloc_array(nbEBands); + ps_ptr fine_priority; + fine_priority.alloc_array(nbEBands); + + codedBands = + clt_compute_allocation(start, end, offsets.get(), cap.get(), alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses.get(), fine_quant.get(), fine_priority.get(), C, LM, 0, 0, 0); + + unquant_fine_energy(start, end, oldBandE, fine_quant.get(), C); + + c = 0; + do { OPUS_MOVE(decode_mem[c], decode_mem[c] + N, DECODE_BUFFER_SIZE - N + overlap / 2); } while (++c < CC); + + /* Decode fixed codebook */ + ps_ptr collapse_masks; + collapse_masks.alloc_array(C * nbEBands); + + ps_ptr X; + X.alloc_array(C * N); /**< Interleaved normalised MDCTs */ + + quant_all_bands(start, end, X.get(), C == 2 ? X.get() + N : NULL, collapse_masks.get(), NULL, pulses.get(), shortBlocks, spread_decision, dual_stereo, intensity, tf_res.get(), + rd.get_storage() * (8 << BITRES) - anti_collapse_rsv, balance, LM, codedBands, &m_celtDec.rng, 0, m_celtDec.disable_inv); + + if (anti_collapse_rsv > 0) { anti_collapse_on = rd.dec_bits(1); } + + unquant_energy_finalise(start, end, oldBandE, fine_quant.get(), fine_priority.get(), rd.get_storage() * 8 - rd.tell(), C); + + if (anti_collapse_on) anti_collapse(X.get(), collapse_masks.get(), LM, C, N, start, end, oldBandE, oldLogE, oldLogE2, pulses.get(), m_celtDec.rng); + + if (silence) { + for (i = 0; i < C * nbEBands; i++) oldBandE[i] = -QCONST16(28.f, DB_SHIFT); + } + + celt_synthesis(X.get(), out_syn, oldBandE, start, effEnd, C, CC, isTransient, LM, m_celtDec.downsample, silence); + + c = 0; + do { + m_celtDec.postfilter_period = max(m_celtDec.postfilter_period, (int32_t)COMBFILTER_MINPERIOD); + m_celtDec.postfilter_period_old = max(m_celtDec.postfilter_period_old, (int32_t)COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], m_celtDec.postfilter_period_old, m_celtDec.postfilter_period, m_CELTMode.shortMdctSize, m_celtDec.postfilter_gain_old, m_celtDec.postfilter_gain, + m_celtDec.postfilter_tapset_old, m_celtDec.postfilter_tapset); + if (LM != 0) + comb_filter(out_syn[c] + m_CELTMode.shortMdctSize, out_syn[c] + m_CELTMode.shortMdctSize, m_celtDec.postfilter_period, postfilter_pitch, N - m_CELTMode.shortMdctSize, + m_celtDec.postfilter_gain, postfilter_gain, m_celtDec.postfilter_tapset, postfilter_tapset); + + } while (++c < CC); + m_celtDec.postfilter_period_old = m_celtDec.postfilter_period; + m_celtDec.postfilter_gain_old = m_celtDec.postfilter_gain; + m_celtDec.postfilter_tapset_old = m_celtDec.postfilter_tapset; + m_celtDec.postfilter_period = postfilter_pitch; + m_celtDec.postfilter_gain = postfilter_gain; + m_celtDec.postfilter_tapset = postfilter_tapset; + if (LM != 0) { + m_celtDec.postfilter_period_old = m_celtDec.postfilter_period; + m_celtDec.postfilter_gain_old = m_celtDec.postfilter_gain; + m_celtDec.postfilter_tapset_old = m_celtDec.postfilter_tapset; + } + + if (C == 1) memcpy(&oldBandE[nbEBands], oldBandE, nbEBands * sizeof(*oldBandE)); + + /* In case start or end were to change */ + if (!isTransient) { + int16_t max_background_increase; + memcpy(oldLogE2, oldLogE, 2 * nbEBands * sizeof(*oldLogE2)); + memcpy(oldLogE, oldBandE, 2 * nbEBands * sizeof(*oldLogE)); + /* In normal circumstances, we only allow the noise floor to increase by up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB increase for each update.*/ + if (m_celtDec.loss_count < 10) + max_background_increase = M * QCONST16(0.001f, DB_SHIFT); + else + max_background_increase = QCONST16(1.f, DB_SHIFT); + for (i = 0; i < 2 * nbEBands; i++) backgroundLogE[i] = min((int16_t)(backgroundLogE[i] + max_background_increase), (int16_t)(oldBandE[i])); + } else { + for (i = 0; i < 2 * nbEBands; i++) oldLogE[i] = min(oldLogE[i], oldBandE[i]); + } + c = 0; + do { + for (i = 0; i < start; i++) { + oldBandE[c * nbEBands + i] = 0; + oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -QCONST16(28.f, DB_SHIFT); + } + for (i = end; i < nbEBands; i++) { + oldBandE[c * nbEBands + i] = 0; + oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -QCONST16(28.f, DB_SHIFT); + } + } while (++c < 2); + m_celtDec.rng = rd.get_rng(); + + deemphasis(out_syn, outbuf, N, CC, m_celtDec.downsample, m_CELTMode.preemph, m_celtDec.preemph_memD, 0); + m_celtDec.loss_count = 0; + if (rd.tell() > 8 * rd.get_storage()) return OPUS_INTERNAL_ERROR; + if (rd.get_error()) m_celtDec.error = 1; + return frame_size / m_celtDec.downsample; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_decoder_ctl(int32_t request, ...) { + va_list ap; + + va_start(ap, request); + switch (request) { + case CELT_SET_START_BAND_REQUEST: { + int32_t value = va_arg(ap, int32_t); + if (value < 0 || value >= m_CELTMode.nbEBands) goto bad_arg; + m_celtDec.start = value; + } break; + case CELT_SET_END_BAND_REQUEST: { + int32_t value = va_arg(ap, int32_t); + if (value < 1 || value > m_CELTMode.nbEBands) goto bad_arg; + m_celtDec.end = value; + } break; + case CELT_SET_CHANNELS_REQUEST: { + int32_t value = va_arg(ap, int32_t); + if (value < 1 || value > 2) goto bad_arg; + m_celtDec.stream_channels = value; + } break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: { + int32_t* value = va_arg(ap, int32_t*); + if (value == NULL) goto bad_arg; + *value = m_celtDec.error; + m_celtDec.error = 0; + } break; + case OPUS_GET_LOOKAHEAD_REQUEST: { + int32_t* value = va_arg(ap, int32_t*); + if (value == NULL) goto bad_arg; + *value = m_celtDec.overlap / m_celtDec.downsample; + } break; + case OPUS_RESET_STATE: { + int32_t i; + int16_t *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (int16_t*)(m_decode_mem.get() + (DECODE_BUFFER_SIZE + m_celtDec.overlap) * m_celtDec.channels); + oldBandE = lpc + m_celtDec.channels * LPC_ORDER; + oldLogE = oldBandE + 2 * m_CELTMode.nbEBands; + oldLogE2 = oldLogE + 2 * m_CELTMode.nbEBands; + + m_celtDec.rng = 0; + m_celtDec.error = 0; + m_celtDec.postfilter_period = 0; + m_celtDec.postfilter_period_old = 0; + m_celtDec.postfilter_gain = 0; + m_celtDec.postfilter_gain_old = 0; + m_celtDec.postfilter_tapset = 0; + m_celtDec.postfilter_tapset_old = 0; + + for (i = 0; i < 2 * m_CELTMode.nbEBands; i++) oldLogE[i] = oldLogE2[i] = -QCONST16(28.f, DB_SHIFT); + m_celtDec.skip_plc = 1; + } break; + case OPUS_GET_PITCH_REQUEST: { + int32_t* value = va_arg(ap, int32_t*); + if (value == NULL) goto bad_arg; + *value = m_celtDec.postfilter_period; + } break; + case CELT_GET_MODE_REQUEST: { + const CELTMode_t** value = va_arg(ap, const CELTMode_t**); + if (value == 0) goto bad_arg; + *value = &m_CELTMode; + } break; + case CELT_SET_SIGNALLING_REQUEST: { + int32_t value = va_arg(ap, int32_t); + m_celtDec.signalling = value; + } break; + case OPUS_GET_FINAL_RANGE_REQUEST: { + uint32_t* value = va_arg(ap, uint32_t*); + if (value == 0) goto bad_arg; + *value = m_celtDec.rng; + } break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: { + int32_t value = va_arg(ap, int32_t); + if (value < 0 || value > 1) { goto bad_arg; } + m_celtDec.disable_inv = value; + } break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: { + int32_t* value = va_arg(ap, int32_t*); + if (!value) { goto bad_arg; } + *value = m_celtDec.disable_inv; + } break; + default: goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::cwrsi(int32_t _n, int32_t _k, uint32_t _i, int32_t* _y) { + uint32_t p; + int32_t s; + int32_t k0; + int16_t val; + int32_t yy = 0; + assert(_k > 0); + assert(_n > 1); + while (_n > 2) { + uint32_t q; + /*Lots of pulses case:*/ + if (_k >= _n) { + const uint32_t* row; + // row = celt_pvq_u_row[_n]; + row = &CELT_PVQ_U_DATA[row_idx[_n]]; + + /*Are the pulses in this dimension negative?*/ + p = row[_k + 1]; + s = -(_i >= p); + _i -= p & s; + /*Count how many pulses were placed in this dimension.*/ + k0 = _k; + q = row[_n]; + if (q > _i) { + assert(p > q); + _k = _n; + do p = celt_pvq_u_row(--_k, _n); + while (p > _i); + } else + for (p = row[_k]; p > _i; p = row[_k]) _k--; + _i -= p; + val = (k0 - _k + s) ^ s; + *_y++ = val; + yy = MAC16_16(yy, val, val); + } + /*Lots of dimensions case:*/ + else { + /*Are there any pulses in this dimension at all?*/ + p = celt_pvq_u_row(_k, _n); + q = celt_pvq_u_row(_k + 1, _n); + if (p <= _i && _i < q) { + _i -= p; + *_y++ = 0; + } else { + /*Are the pulses in this dimension negative?*/ + s = -(_i >= q); + _i -= q & s; + /*Count how many pulses were placed in this dimension.*/ + k0 = _k; + do p = celt_pvq_u_row(--_k, _n); + while (p > _i); + _i -= p; + val = (k0 - _k + s) ^ s; + *_y++ = val; + yy = MAC16_16(yy, val, val); + } + } + _n--; + } + /*_n==2*/ + p = 2 * _k + 1; + s = -(_i >= p); + _i -= p & s; + k0 = _k; + _k = (_i + 1) >> 1; + if (_k) _i -= 2 * _k - 1; + val = (k0 - _k + s) ^ s; + *_y++ = val; + yy = MAC16_16(yy, val, val); + /*_n==1*/ + s = -(int32_t)_i; + val = (_k + s) ^ s; + *_y = val; + yy = MAC16_16(yy, val, val); + return yy; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::decode_pulses(int32_t* _y, int32_t _n, int32_t _k) { + return cwrsi(_n, _k, rd.dec_uint(CELT_PVQ_V(_n, _k)), _y); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::kf_bfly2(kiss_fft_cpx* Fout, int32_t m, int32_t N) { + kiss_fft_cpx* Fout2; + int32_t i; + (void)m; + + { + int16_t tw; + tw = QCONST16(0.7071067812f, 15); + /* We know that m==4 here because the radix-2 is just after a radix-4 */ + assert(m == 4); + for (i = 0; i < N; i++) { + kiss_fft_cpx t; + Fout2 = Fout + 4; + t = Fout2[0]; + C_SUB(Fout2[0], Fout[0], t); + C_ADDTO(Fout[0], t); + + t.r = S_MUL(ADD32_ovflw(Fout2[1].r, Fout2[1].i), tw); + t.i = S_MUL(SUB32_ovflw(Fout2[1].i, Fout2[1].r), tw); + C_SUB(Fout2[1], Fout[1], t); + C_ADDTO(Fout[1], t); + + t.r = Fout2[2].i; + t.i = -Fout2[2].r; + C_SUB(Fout2[2], Fout[2], t); + C_ADDTO(Fout[2], t); + + t.r = S_MUL(SUB32_ovflw(Fout2[3].i, Fout2[3].r), tw); + t.i = S_MUL(NEG32_ovflw(ADD32_ovflw(Fout2[3].i, Fout2[3].r)), tw); + C_SUB(Fout2[3], Fout[3], t); + C_ADDTO(Fout[3], t); + Fout += 8; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::kf_bfly4(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* tw, int32_t m, int32_t N, int32_t mm) { + int32_t i; + + if (m == 1) { + /* Degenerate case where all the twiddles are 1. */ + for (i = 0; i < N; i++) { + kiss_fft_cpx scratch0, scratch1; + + C_SUB(scratch0, *Fout, Fout[2]); + C_ADDTO(*Fout, Fout[2]); + C_ADD(scratch1, Fout[1], Fout[3]); + C_SUB(Fout[2], *Fout, scratch1); + C_ADDTO(*Fout, scratch1); + C_SUB(scratch1, Fout[1], Fout[3]); + + Fout[1].r = ADD32_ovflw(scratch0.r, scratch1.i); + Fout[1].i = SUB32_ovflw(scratch0.i, scratch1.r); + Fout[3].r = SUB32_ovflw(scratch0.r, scratch1.i); + Fout[3].i = ADD32_ovflw(scratch0.i, scratch1.r); + Fout += 4; + } + } else { + int32_t j; + kiss_fft_cpx scratch[6]; + const kiss_twiddle_cpx *tw1, *tw2, *tw3; + const int32_t m2 = 2 * m; + const int32_t m3 = 3 * m; + kiss_fft_cpx* Fout_beg = Fout; + for (i = 0; i < N; i++) { + Fout = Fout_beg + i * mm; + tw3 = tw2 = tw1 = tw->twiddles; + /* m is guaranteed to be a multiple of 4. */ + for (j = 0; j < m; j++) { + C_MUL(scratch[0], Fout[m], *tw1); + C_MUL(scratch[1], Fout[m2], *tw2); + C_MUL(scratch[2], Fout[m3], *tw3); + + C_SUB(scratch[5], *Fout, scratch[1]); + C_ADDTO(*Fout, scratch[1]); + C_ADD(scratch[3], scratch[0], scratch[2]); + C_SUB(scratch[4], scratch[0], scratch[2]); + C_SUB(Fout[m2], *Fout, scratch[3]); + tw1 += fstride; + tw2 += fstride * 2; + tw3 += fstride * 3; + C_ADDTO(*Fout, scratch[3]); + + Fout[m].r = ADD32_ovflw(scratch[5].r, scratch[4].i); + Fout[m].i = SUB32_ovflw(scratch[5].i, scratch[4].r); + Fout[m3].r = SUB32_ovflw(scratch[5].r, scratch[4].i); + Fout[m3].i = ADD32_ovflw(scratch[5].i, scratch[4].r); + ++Fout; + } + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::kf_bfly3(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* tw, int32_t m, int32_t N, int32_t mm) { + int32_t i; + size_t k; + const size_t m2 = 2 * m; + const kiss_twiddle_cpx *tw1, *tw2; + kiss_fft_cpx scratch[5]; + kiss_twiddle_cpx epi3; + + kiss_fft_cpx* Fout_beg = Fout; + /*epi3.r = -16384;*/ /* Unused */ + epi3.i = -28378; + for (i = 0; i < N; i++) { + Fout = Fout_beg + i * mm; + tw1 = tw2 = tw->twiddles; + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + k = m; + do { + C_MUL(scratch[1], Fout[m], *tw1); + C_MUL(scratch[2], Fout[m2], *tw2); + + C_ADD(scratch[3], scratch[1], scratch[2]); + C_SUB(scratch[0], scratch[1], scratch[2]); + tw1 += fstride; + tw2 += fstride * 2; + + Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r)); + Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i)); + + C_MULBYSCALAR(scratch[0], epi3.i); + + C_ADDTO(*Fout, scratch[3]); + + Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i); + Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r); + + Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i); + Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r); + + ++Fout; + } while (--k); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::kf_bfly5(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* tff, int32_t m, int32_t N, int32_t mm) { + kiss_fft_cpx * Fout0, *Fout1, *Fout2, *Fout3, *Fout4; + int32_t i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx* tw; + kiss_twiddle_cpx ya, yb; + kiss_fft_cpx* Fout_beg = Fout; + + ya.r = 10126; + ya.i = -31164; + yb.r = -26510; + yb.i = -19261; + tw = tff->twiddles; + + for (i = 0; i < N; i++) { + Fout = Fout_beg + i * mm; + Fout0 = Fout; + Fout1 = Fout0 + m; + Fout2 = Fout0 + 2 * m; + Fout3 = Fout0 + 3 * m; + Fout4 = Fout0 + 4 * m; + + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + for (u = 0; u < m; ++u) { + scratch[0] = *Fout0; + + C_MUL(scratch[1], *Fout1, tw[u * fstride]); + C_MUL(scratch[2], *Fout2, tw[2 * u * fstride]); + C_MUL(scratch[3], *Fout3, tw[3 * u * fstride]); + C_MUL(scratch[4], *Fout4, tw[4 * u * fstride]); + + C_ADD(scratch[7], scratch[1], scratch[4]); + C_SUB(scratch[10], scratch[1], scratch[4]); + C_ADD(scratch[8], scratch[2], scratch[3]); + C_SUB(scratch[9], scratch[2], scratch[3]); + + Fout0->r = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r)); + Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i)); + + scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r, ya.r), S_MUL(scratch[8].r, yb.r))); + scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i, ya.r), S_MUL(scratch[8].i, yb.r))); + + scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i, ya.i), S_MUL(scratch[9].i, yb.i)); + scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r, ya.i), S_MUL(scratch[9].r, yb.i))); + + C_SUB(*Fout1, scratch[5], scratch[6]); + C_ADD(*Fout4, scratch[5], scratch[6]); + + scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r, yb.r), S_MUL(scratch[8].r, ya.r))); + scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i, yb.r), S_MUL(scratch[8].i, ya.r))); + scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i, ya.i), S_MUL(scratch[10].i, yb.i)); + scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r, yb.i), S_MUL(scratch[9].r, ya.i)); + + C_ADD(*Fout2, scratch[11], scratch[12]); + C_SUB(*Fout3, scratch[11], scratch[12]); + + ++Fout0; + ++Fout1; + ++Fout2; + ++Fout3; + ++Fout4; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::opus_fft_impl(const kiss_fft_state* tff, kiss_fft_cpx* fout) { + int32_t m2, m; + int32_t p; + int32_t L; + int32_t fstride[MAXFACTORS]; + int32_t i; + int32_t shift; + + /* m_celtDec.shift can be -1 */ + shift = tff->shift > 0 ? tff->shift : 0; + + fstride[0] = 1; + L = 0; + do { + p = tff->factors[2 * L]; + m = tff->factors[2 * L + 1]; + fstride[L + 1] = fstride[L] * p; + L++; + } while (m != 1); + m = tff->factors[2 * L - 1]; + for (i = L - 1; i >= 0; i--) { + if (i != 0) + m2 = tff->factors[2 * i - 1]; + else + m2 = 1; + switch (tff->factors[2 * i]) { + case 2: kf_bfly2(fout, m, fstride[i]); break; + case 4: kf_bfly4(fout, fstride[i] << shift, tff, m, fstride[i], m2); break; + case 3: kf_bfly3(fout, fstride[i] << shift, tff, m, fstride[i], m2); break; + case 5: kf_bfly5(fout, fstride[i] << shift, tff, m, fstride[i], m2); break; + } + m = m2; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/*Compute floor(sqrt(_val)) with exact arithmetic. _val must be greater than 0. This has been tested on all possible 32-bit inputs greater than 0.*/ +uint32_t CeltDecoder::isqrt32(uint32_t _val) { + uint32_t b; + uint32_t g; + int32_t bshift; + /*Uses the second method from http://www.azillionmonkeys.com/qed/sqroot.html The main idea is to search for the + largest binary digit b such that (g+b)*(g+b) <= _val, and add it to the solution g.*/ + g = 0; + bshift = (CELT_ILOG(_val) - 1) >> 1; + b = 1U << bshift; + do { + uint32_t t; + t = (((uint32_t)g << 1) + b) << bshift; + if (t <= _val) { + g += b; + _val -= t; + } + b >>= 1; + bshift--; + } while (bshift >= 0); + return g; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +int16_t CeltDecoder::celt_rsqrt_norm(int32_t x) { + int16_t n; + int16_t r; + int16_t r2; + int16_t y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x - 32768; + /* Get a rough initial guess for the root. The optimal minmax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). Coefficients here, and the final result r, + are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. We can compute the result from n and r using Q15 + multiplies with some adjustment, carefully done to avoid overflow. Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). This yields the Q14 reciprocal square root of + the Q16 x, with a maximum relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a peak absolute + error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Sqrt approximation (QX input, QX/2 output) */ +int32_t CeltDecoder::celt_sqrt(int32_t x) { + int32_t k; + int16_t n; + int32_t rt; + const int16_t C[5] = {23175, 11561, -3011, 1699, -664}; + if (x == 0) + return 0; + else if (x >= 1073741824) + return 32767; + k = (celt_ilog2(x) >> 1) - 7; + x = VSHR32(x, 2 * k); + n = x - 32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt, 7 - k); + return rt; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int16_t CeltDecoder::_celt_cos_pi_2(int16_t x) { + int16_t x2; + x2 = MULT16_16_P15(x, x); + return ADD16(1, min((int32_t)32766, (int32_t)(ADD32(SUB16(32767, x2), MULT16_16_P15(x2, ADD32(-7651, MULT16_16_P15(x2, ADD32(8277, MULT16_16_P15(-626, x2))))))))); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int16_t CeltDecoder::celt_cos_norm(int32_t x) { + x = x & 0x0001ffff; + if (x > SHL32(EXTEND32(1), 16)) x = SUB32(SHL32(EXTEND32(1), 17), x); + if (x & 0x00007fff) { + if (x < SHL32(EXTEND32(1), 15)) { + return _celt_cos_pi_2(EXTRACT16(x)); + } else { + return NEG16(_celt_cos_pi_2(EXTRACT16(65536 - x))); + } + } else { + if (x & 0x0000ffff) + return 0; + else if (x & 0x0001ffff) + return -32767; + else + return 32767; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Reciprocal approximation (Q15 input, Q16 output) */ +int32_t CeltDecoder::celt_rcp(int32_t x) { + int32_t i; + int16_t n; + int16_t r; + assert(x > 0); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x, i - 15) - 32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute error of 1.24665/32768. */ + return VSHR32(EXTEND32(r), i - 16); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::clt_mdct_backward(int32_t* in, int32_t* out, int32_t overlap, int32_t shift, int32_t stride) { + int32_t i; + int32_t N, N2, N4; + const int16_t* trig; + + N = m_mdct_lookup.n; + trig = m_mdct_lookup.trig; + for (i = 0; i < shift; i++) { + N >>= 1; + trig += N; + } + N2 = N >> 1; + N4 = N >> 2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const int32_t* xp1 = in; + const int32_t* xp2 = in + stride * (N2 - 1); + int32_t* yp = out + (overlap >> 1); + const int16_t* t = &trig[0]; + const int16_t* bitrev = m_mdct_lookup.kfft[shift]->bitrev; + for (i = 0; i < N4; i++) { + int32_t rev; + int32_t yr, yi; + rev = *bitrev++; + yr = ADD32_ovflw(S_MUL(*xp2, t[i]), S_MUL(*xp1, t[N4 + i])); + yi = SUB32_ovflw(S_MUL(*xp1, t[i]), S_MUL(*xp2, t[N4 + i])); + /* We swap real and imag because we use an FFT instead of an IFFT. */ + yp[2 * rev + 1] = yr; + yp[2 * rev] = yi; + /* Storing the pre-rotation directly in the bitrev order. */ + xp1 += 2 * stride; + xp2 -= 2 * stride; + } + } + + opus_fft_impl(m_mdct_lookup.kfft[shift], (kiss_fft_cpx*)(out + (overlap >> 1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make it in-place. */ + { + int32_t* yp0 = out + (overlap >> 1); + int32_t* yp1 = out + (overlap >> 1) + N2 - 2; + const int16_t* t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for (i = 0; i < (N4 + 1) >> 1; i++) { + int32_t re, im, yr, yi; + int16_t t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4 + i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re, t0), S_MUL(im, t1)); + yi = SUB32_ovflw(S_MUL(re, t1), S_MUL(im, t0)); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4 - i - 1)]; + t1 = t[(N2 - i - 1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re, t0), S_MUL(im, t1)); + yi = SUB32_ovflw(S_MUL(re, t1), S_MUL(im, t0)); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + int32_t* xp1 = out + overlap - 1; + int32_t* yp1 = out; + const int16_t* wp1 = window120; + const int16_t* wp2 = window120 + overlap - 1; + + for (i = 0; i < overlap / 2; i++) { + int32_t x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1)); + *xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1)); + wp1++; + wp2--; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::interp_bits2pulses(int32_t start, int32_t end, int32_t skip_start, const int32_t* bits1, const int32_t* bits2, const int32_t* thresh, const int32_t* cap, int32_t total, + int32_t* _balance, int32_t skip_rsv, int32_t* intensity, int32_t intensity_rsv, int32_t* dual_stereo, int32_t dual_stereo_rsv, int32_t* bits, int32_t* ebits, + int32_t* fine_priority, int32_t C, int32_t LM, int32_t encode, int32_t prev, int32_t signalBandwidth) { + int32_t psum; + int32_t lo, hi; + int32_t i, j; + int32_t logM; + int32_t stereo; + int32_t codedBands = -1; + int32_t alloc_floor; + int32_t left, percoeff; + int32_t done; + int32_t balance; + + alloc_floor = C << BITRES; + stereo = C > 1; + + logM = LM << BITRES; + lo = 0; + hi = 1 << ALLOC_STEPS; + for (i = 0; i < ALLOC_STEPS; i++) { + int32_t mid = (lo + hi) >> 1; + psum = 0; + done = 0; + for (j = end; j-- > start;) { + int32_t tmp = bits1[j] + (mid * (int32_t)bits2[j] >> ALLOC_STEPS); + if (tmp >= thresh[j] || done) { + done = 1; + /* Don't allocate more than we can actually use */ + psum += min(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + OPUS_LOG_DEBUG("interp bisection gave {}", lo); + done = 0; + for (j = end; j-- > start;) { + int32_t tmp = bits1[j] + ((int32_t)lo * bits2[j] >> ALLOC_STEPS); + if (tmp < thresh[j] && !done) { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = min(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands = end;; codedBands--) { + int32_t band_width; + int32_t band_bits; + int32_t rem; + j = codedBands - 1; + /* Never skip the first band, nor a band that has been boosted by dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits we just signaled should be cocentrated in this band. */ + if (j <= skip_start) { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. This can include bits we've stolen back from higher, skipped bands.*/ + left = total - psum; + percoeff = celt_udiv(left, eband5ms[codedBands] - eband5ms[start]); + left -= (eband5ms[codedBands] - eband5ms[start]) * percoeff; + rem = max(left - (eband5ms[j] - eband5ms[start]), (int32_t)0); + band_width = eband5ms[codedBands] - eband5ms[j]; + band_bits = (int32_t)(bits[j] + percoeff * band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. Otherwise it is force-skipped. This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= max(thresh[j], alloc_floor + (1 << BITRES))) { + if (encode) { + ; + } else if (rd.dec_bit_logp(1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1 << BITRES; + band_bits -= 1 << BITRES; + } + /*Reclaim the bits originally allocated to this band.*/ + psum -= bits[j] + intensity_rsv; + if (intensity_rsv > 0) intensity_rsv = LOG2_FRAC_TABLE[j - start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) { + if (encode) { + ; + } else + *intensity = start + rd.dec_uint(codedBands + 1 - start); + } else + *intensity = 0; + if (*intensity <= start) { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) { + if (encode) + ; + else + *dual_stereo = rd.dec_bit_logp(1); + } else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total - psum; + percoeff = celt_udiv(left, eband5ms[codedBands] - eband5ms[start]); + left -= (eband5ms[codedBands] - eband5ms[start]) * percoeff; + for (j = start; j < codedBands; j++) bits[j] += ((int32_t)percoeff * (eband5ms[j + 1] - eband5ms[j])); + for (j = start; j < codedBands; j++) { + int32_t tmp = (int32_t)min(left, (int32_t)(eband5ms[j + 1] - eband5ms[j])); + bits[j] += tmp; + left -= tmp; + } + for (j = 0; j < end; j++) OPUS_LOG_DEBUG("{} ", bits[j]); + + balance = 0; + for (j = start; j < codedBands; j++) { + int32_t N0, N, den; + int32_t offset; + int32_t NClogN; + int32_t excess, bit; + + assert(bits[j] >= 0); + N0 = eband5ms[j + 1] - eband5ms[j]; + N = N0 << LM; + bit = (int32_t)bits[j] + balance; + + if (N > 1) { + excess = max(bit - cap[j], (int32_t)0); + bits[j] = bit - excess; + + /* Compensate for the extra DoF in stereo */ + den = (C * N + ((C == 2 && N > 2 && !*dual_stereo && j < *intensity) ? 1 : 0)); + + NClogN = den * (logN400[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET compared to their "fair share" of total/N */ + offset = (NClogN >> 1) - den * FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N == 2) offset += den << BITRES >> 2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den * 2 << BITRES) + offset += NClogN >> 2; + else if (bits[j] + offset < den * 3 << BITRES) + offset += NClogN >> 3; + + /* Divide with rounding */ + ebits[j] = max((int32_t)0, (bits[j] + offset + (den << (BITRES - 1)))); + ebits[j] = celt_udiv(ebits[j], den) >> BITRES; + + /* Make sure not to bust */ + if (C * ebits[j] > (bits[j] >> BITRES)) ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = min(ebits[j], (int32_t)MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j] * (den << BITRES) >= bits[j] + offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C * ebits[j] << BITRES; + + } else { + /* For N=1, all bits go to fine energy except for a single sign bit */ + excess = max((int32_t)0, bit - (C << BITRES)); + bits[j] = bit - excess; + ebits[j] = 0; + fine_priority[j] = 1; + } + + /* Fine energy can't take advantage of the re-balancing in quant_all_bands(). + Instead, do the re-balancing here.*/ + if (excess > 0) { + int32_t extra_fine; + int32_t extra_bits; + extra_fine = min(excess >> (stereo + BITRES), (int32_t)(MAX_FINE_BITS - ebits[j])); + ebits[j] += extra_fine; + extra_bits = extra_fine * C << BITRES; + fine_priority[j] = extra_bits >= excess - balance; + excess -= extra_bits; + } + balance = excess; + + assert(bits[j] >= 0); + assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (; j < end; j++) { + ebits[j] = bits[j] >> stereo >> BITRES; + assert(C * ebits[j] << BITRES == bits[j]); + bits[j] = 0; + fine_priority[j] = ebits[j] < 1; + } + + return codedBands; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::clt_compute_allocation(int32_t start, int32_t end, const int32_t* offsets, const int32_t* cap, int32_t alloc_trim, int32_t* intensity, int32_t* dual_stereo, int32_t total, + int32_t* balance, int32_t* pulses, int32_t* ebits, int32_t* fine_priority, int32_t C, int32_t LM, int32_t encode, int32_t prev, int32_t signalBandwidth) { + int32_t lo, hi, len, j; + int32_t codedBands; + int32_t skip_start; + int32_t skip_rsv; + int32_t intensity_rsv; + int32_t dual_stereo_rsv; + + total = max(total, (int32_t)0); + len = m_CELTMode.nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1 << BITRES ? 1 << BITRES : 0; + total -= skip_rsv; + /* Reserve bits for the intensity and dual stereo parameters. */ + intensity_rsv = dual_stereo_rsv = 0; + if (C == 2) { + intensity_rsv = LOG2_FRAC_TABLE[end - start]; + if (intensity_rsv > total) + intensity_rsv = 0; + else { + total -= intensity_rsv; + dual_stereo_rsv = total >= 1 << BITRES ? 1 << BITRES : 0; + total -= dual_stereo_rsv; + } + } + ps_ptr bits1; + bits1.alloc_array(len); + ps_ptr bits2; + bits2.alloc_array(len); + ps_ptr thresh; + thresh.alloc_array(len); + ps_ptr trim_offset; + trim_offset.alloc_array(len); + + for (j = start; j < end; j++) { + /* Below this threshold, we're sure not to allocate any PVQ bits */ + thresh[j] = max((int32_t)((C) << BITRES), (int32_t)((3 * (eband5ms[j + 1] - eband5ms[j]) << LM << BITRES) >> 4)); + /* Tilt of the allocation curve */ + trim_offset[j] = C * (eband5ms[j + 1] - eband5ms[j]) * (alloc_trim - 5 - LM) * (end - j - 1) * (1 << (LM + BITRES)) >> 6; + /* Giving less resolution to single-coefficient bands because they get more benefit from having one coarse value per coefficient*/ + if ((eband5ms[j + 1] - eband5ms[j]) << LM == 1) trim_offset[j] -= C << BITRES; + } + lo = 1; + hi = m_CELTMode.nbAllocVectors - 1; + do { + int32_t done = 0; + int32_t psum = 0; + int32_t mid = (lo + hi) >> 1; + for (j = end; j-- > start;) { + int32_t bitsj; + int32_t N = eband5ms[j + 1] - eband5ms[j]; + bitsj = C * N * band_allocation[mid * len + j] << LM >> 2; + if (bitsj > 0) bitsj = max((int32_t)0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) { + done = 1; + /* Don't allocate more than we can actually use */ + psum += min(bitsj, cap[j]); + } else { + if (bitsj >= C << BITRES) psum += C << BITRES; + } + } + if (psum > total) { + hi = mid - 1; + } else { + lo = mid + 1; + } + OPUS_LOG_VERBOSE("lo = {}, hi = {}", lo, hi); + } while (lo <= hi); + hi = lo--; + OPUS_LOG_VERBOSE("interp between {} and {}", lo, hi); + for (j = start; j < end; j++) { + int32_t bits1j, bits2j; + int32_t N = eband5ms[j + 1] - eband5ms[j]; + bits1j = C * N * band_allocation[lo * len + j] << LM >> 2; + bits2j = hi >= m_CELTMode.nbAllocVectors ? cap[j] : C * N * band_allocation[hi * len + j] << LM >> 2; + if (bits1j > 0) bits1j = max((int32_t)0, bits1j + trim_offset[j]); + if (bits2j > 0) bits2j = max((int32_t)0, bits2j + trim_offset[j]); + if (lo > 0) bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j] > 0) skip_start = j; + bits2j = max((int32_t)0, bits2j - bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(start, end, skip_start, bits1.get(), bits2.get(), thresh.get(), cap, total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, pulses, + ebits, fine_priority, C, LM, encode, prev, signalBandwidth); + + return codedBands; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::unquant_coarse_energy(int32_t start, int32_t end, int16_t* oldEBands, int32_t intra, int32_t C, int32_t LM) { + const uint8_t* prob_model = e_prob_model[LM][intra]; + int32_t i, c; + int32_t prev[2] = {0, 0}; + int16_t coef; + int16_t beta; + int32_t budget; + int32_t tell; + + if (intra) { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = rd.get_storage() * 8; + + /* Decode at a fixed coarse resolution */ + for (i = start; i < end; i++) { + c = 0; + do { + int32_t qi; + int32_t q; + int32_t tmp; + /* It would be better to express this invariant as a test on C at function entry, but that isn't enough to make the static analyzer happy. */ + assert(c < 2); + tell = rd.tell(); + if (budget - tell >= 15) { + int32_t pi; + pi = 2 * min(i, (int32_t)20); + qi = rd.laplace_decode(prob_model[pi] << 7, prob_model[pi + 1] << 6); + } else if (budget - tell >= 2) { + qi = rd.dec_icdf(small_energy_icdf, 2); + qi = (qi >> 1) ^ -(qi & 1); + } else if (budget - tell >= 1) { + qi = -rd.dec_bit_logp(1); + } else + qi = -1; + q = (int32_t)SHL32(EXTEND32(qi), DB_SHIFT); + + oldEBands[i + c * m_CELTMode.nbEBands] = max((int32_t)(-QCONST16(9.f, DB_SHIFT)), (int32_t)(oldEBands[i + c * m_CELTMode.nbEBands])); + tmp = PSHR32(MULT16_16(coef, oldEBands[i + c * m_CELTMode.nbEBands]), 8) + prev[c] + SHL32(q, 7); + tmp = max(-QCONST32(28.f, DB_SHIFT + 7), tmp); + oldEBands[i + c * m_CELTMode.nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q, 7) - MULT16_16(beta, PSHR32(q, 8)); + } while (++c < C); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::unquant_fine_energy(int32_t start, int32_t end, int16_t* oldEBands, int32_t* fine_quant, int32_t C) { + int32_t i, c; + /* Decode finer resolution */ + for (i = start; i < end; i++) { + if (fine_quant[i] <= 0) continue; + c = 0; + do { + int32_t q2; + int16_t offset; + q2 = rd.dec_bits(fine_quant[i]); + offset = SUB16(SHR32(SHL32(EXTEND32(q2), DB_SHIFT) + QCONST16(.5f, DB_SHIFT), fine_quant[i]), QCONST16(.5f, DB_SHIFT)); + oldEBands[i + c * m_CELTMode.nbEBands] += offset; + } while (++c < C); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::unquant_energy_finalise(int32_t start, int32_t end, int16_t* oldEBands, int32_t* fine_quant, int32_t* fine_priority, int32_t bits_left, int32_t C) { + int32_t i, prio, c; + + /* Use up the remaining bits */ + for (prio = 0; prio < 2; prio++) { + for (i = start; i < end && bits_left >= C; i++) { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i] != prio) continue; + c = 0; + do { + int32_t q2; + int16_t offset; + q2 = rd.dec_bits(1); + offset = SHR16(SHL16(q2, DB_SHIFT) - QCONST16(.5f, DB_SHIFT), fine_quant[i] + 1); + oldEBands[i + c * m_CELTMode.nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int16_t CeltDecoder::SAT16(int32_t x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (int16_t)x; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t CeltDecoder::celt_udiv(uint32_t n, uint32_t d) { + assert(d > 0); + return n / d; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_sudiv(int32_t n, int32_t d) { + assert(d > 0); + return n / d; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int16_t CeltDecoder::sig2word16(int32_t x) { + x = PSHR32(x, 12); + x = max(x, (int32_t)-32768); + x = min(x, (int32_t)32767); + return EXTRACT16(x); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Atan approximation using a 4th order polynomial. Input is in Q15 format and normalized by pi/4. Output is in Q15 format */ +int16_t CeltDecoder::celt_atan01(int16_t x) { + return MULT16_16_P15(x, ADD32(32767, MULT16_16_P15(x, ADD32(-21, MULT16_16_P15(x, ADD32(-11943, MULT16_16_P15(4936, x))))))); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* atan2() approximation valid for positive input values */ +int16_t CeltDecoder::celt_atan2p(int16_t y, int16_t x) { + if (y < x) { + int32_t arg; + arg = celt_div(SHL32(EXTEND32(y), 15), x); + if (arg >= 32767) arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)), 1); + } else { + int32_t arg; + arg = celt_div(SHL32(EXTEND32(x), 15), y); + if (arg >= 32767) arg = 32767; + return 25736 - SHR16(celt_atan01(EXTRACT16(arg)), 1); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_maxabs16(const int16_t* x, int32_t len) { + int32_t i; + int16_t maxval = 0; + int16_t minval = 0; + for (i = 0; i < len; i++) { + maxval = max(maxval, x[i]); + minval = min(minval, x[i]); + } + return max(EXTEND32(maxval), -EXTEND32(minval)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_maxabs32(const int32_t* x, int32_t len) { + int32_t i; + int32_t maxval = 0; + int32_t minval = 0; + for (i = 0; i < len; i++) { + maxval = max(maxval, x[i]); + minval = min(minval, x[i]); + } + return max(maxval, -minval); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Integer log in base2. Undefined for zero and negative numbers */ +int16_t CeltDecoder::celt_ilog2(int32_t x) { + assert(x > 0); + return CELT_ILOG(x) - 1; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Integer log in base2. Defined for zero, but not for negative numbers */ +int16_t CeltDecoder::celt_zlog2(int32_t x) { + return x <= 0 ? 0 : celt_ilog2(x); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ +int16_t CeltDecoder::celt_log2(int32_t x) { + int32_t i; + int16_t n, frac; + /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, + 0.15530808010959576, -0.08556153059057618 */ + const int16_t C[5] = {-6801 + (1 << (13 - DB_SHIFT)), 15746, -5217, 2545, -1401}; + if (x == 0) return -32767; + i = celt_ilog2(x); + n = VSHR32(x, i - 15) - 32768 - 16384; + frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); + return SHL16(i - 13, DB_SHIFT) + SHR16(frac, 14 - DB_SHIFT); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_exp2_frac(int16_t x) { + int16_t frac; + frac = SHL16(x, 4); + return ADD16(16383, MULT16_16_Q15(frac, ADD16(22804, MULT16_16_Q15(frac, ADD16(14819, MULT16_16_Q15(10204, frac)))))); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ +int32_t CeltDecoder::celt_exp2(int16_t x) { + int32_t integer; + int16_t frac; + integer = SHR16(x, 10); + if (integer > 14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = celt_exp2_frac(x - SHL16(integer, 10)); + return VSHR32(EXTEND32(frac), -integer - 2); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void CeltDecoder::dual_inner_prod_c(const int16_t* x, const int16_t* y01, const int16_t* y02, int32_t N, int32_t* xy1, int32_t* xy2) { + int32_t i; + int32_t xy01 = 0; + int32_t xy02 = 0; + for (i = 0; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::celt_inner_prod_c(const int16_t* x, const int16_t* y, int32_t N) { + int32_t i; + int32_t xy = 0; + for (i = 0; i < N; i++) xy = MAC16_16(xy, x[i], y[i]); + return xy; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::get_pulses(int32_t i) { + return i < 8 ? i : (8 + (i & 7)) << ((i >> 3) - 1); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::bits2pulses(int32_t band, int32_t LM, int32_t bits) { + int32_t i; + int32_t lo, hi; + const uint8_t* cache; + + LM++; + cache = cache_bits50 + cache_index50[LM * m_CELTMode.nbEBands + band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i = 0; i < LOG_MAX_PSEUDO; i++) { + int32_t mid = (lo + hi + 1) >> 1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int32_t)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits - (lo == 0 ? -1 : (int32_t)cache[lo]) <= (int32_t)cache[hi] - bits) + return lo; + else + return hi; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t CeltDecoder::pulses2bits(int32_t band, int32_t LM, int32_t pulses) { + const uint8_t* cache; + + LM++; + cache = cache_bits50 + cache_index50[LM * m_CELTMode.nbEBands + band]; + return pulses == 0 ? 0 : cache[pulses] + 1; +} diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/celt.h b/libraries/ESP32-audioI2S/src/opus_decoder/celt.h new file mode 100644 index 0000000..eeebaa0 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/celt.h @@ -0,0 +1,230 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include "../psram_unique_ptr.hpp" +#include "Arduino.h" +#include "celt_defines.h" +#include "celt_structs.h" +#include "celt_tables.h" +#include "range_decoder.h" + +extern const int16_t eband5ms[22]; +extern const uint8_t band_allocation[231]; +extern const uint32_t CELT_PVQ_U_DATA[]; +extern const int16_t mdct_twiddles960[]; +extern const int16_t window120[]; +extern const int16_t logN400[]; +extern const int16_t cache_index50[]; +extern const uint8_t cache_bits50[]; +extern const uint8_t cache_caps50[]; +extern const kiss_twiddle_cpx fft_twiddles48000_960[]; +extern const int16_t fft_bitrev480[]; +extern const int16_t fft_bitrev240[]; +extern const int16_t fft_bitrev12[]; +extern const int16_t fft_bitrev60[]; +extern const uint8_t LOG2_FRAC_TABLE[]; +extern const uint8_t e_prob_mode[]; +extern const uint8_t small_energy_icdf[]; +extern const int8_t tf_select_table[4][8]; +extern const int32_t ordery_table[]; +extern const int32_t second_check[]; +extern const uint8_t trim_icd[]; +extern const uint8_t spread_icd[]; +extern const uint8_t tapset_icdf[]; +extern const uint32_t row_idx[]; + +class CeltDecoder { + public: + CeltDecoder(RangeDecoder& rangeDecoder) : rd(rangeDecoder) {} + ~CeltDecoder() { reset(); } + bool init(); + void clear(); + void reset(); + int32_t celt_decoder_init(int32_t channels); + int32_t celt_decoder_ctl(int32_t request, ...); + int32_t celt_decode_with_ec(int16_t* pcm, int32_t frame_size); + int16_t SAT16(int32_t x); + + private: + RangeDecoder& rd; // Referenz auf RangeDecoder + + + const kiss_fft_state fft_state48000_960_0 = { + 480, /* nfft */ + 17476, /* scale */ + 8, /* scale_shift */ + -1, /* shift */ + {5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0}, /* factors */ + fft_bitrev480, /* bitrev */ + fft_twiddles48000_960, /* bitrev */ + }; + + const kiss_fft_state fft_state48000_960_1 = { + 240, /* nfft */ + 17476, /* scale */ + 7, /* scale_shift */ + 1, /* shift */ + {5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0}, /* factors */ + fft_bitrev240, /* bitrev */ + fft_twiddles48000_960, /* bitrev */ + }; + + const kiss_fft_state fft_state48000_960_2 = { + 120, /* nfft */ + 17476, /* scale */ + 6, /* scale_shift */ + 2, /* shift */ + {5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0}, /* factors */ + fft_bitrev120, /* bitrev */ + fft_twiddles48000_960, /* bitrev */ + }; + const kiss_fft_state fft_state48000_960_3 = { + 60, /* nfft */ + 17476, /* scale */ + 5, /* scale_shift */ + 3, /* shift */ + {5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* factors */ + fft_bitrev60, /* bitrev */ + fft_twiddles48000_960, /* bitrev */ + }; + + const CELTMode_t m_CELTMode = { + 48000, /* Fs */ + 120, /* overlap */ + 21, /* nbEBands */ + 21, /* effEBands */ + {27853, 0, 4096, 8192}, /* preemph */ + 3, /* maxLM */ + 8, /* nbShortMdcts */ + 120, /* shortMdctSize */ + 11, /* nbAllocVectors */ + }; + + const mdct_lookup_t m_mdct_lookup = { + 1920, + 3, + { + &fft_state48000_960_0, + &fft_state48000_960_1, + &fft_state48000_960_2, + &fft_state48000_960_3, + }, + mdct_twiddles960, /* mdct */ + }; + + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + CELTDecoder_t m_celtDec; // unique pointer + ps_ptr m_decode_mem; + band_ctx_t m_band_ctx; + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + int32_t celt_inner_prod_c(const int16_t* x, const int16_t* y, int32_t N); + int32_t celt_rcp(int32_t x); + uint32_t celt_pvq_u_row(uint32_t row, uint32_t data); + void exp_rotation1(int16_t* X, int32_t len, int32_t stride, int16_t c, int16_t s); + void exp_rotation(int16_t* X, int32_t len, int32_t dir, int32_t stride, int32_t K, int32_t spread); + void normalise_residual(int32_t* iy, int16_t* X, int32_t N, int32_t Ryy, int16_t gain); + uint32_t extract_collapse_mask(int32_t* iy, int32_t N, int32_t B); + uint32_t alg_unquant(int16_t* X, int32_t N, int32_t K, int32_t spread, int32_t B, int16_t gain); + void renormalise_vector(int16_t* X, int32_t N, int16_t gain); + int32_t resampling_factor(int32_t rate); + void comb_filter_const_c(int32_t* y, int32_t* x, int32_t T, int32_t N, int16_t g10, int16_t g11, int16_t g12); + void comb_filter(int32_t* y, int32_t* x, int32_t T0, int32_t T1, int32_t N, int16_t g0, int16_t g1, int32_t tapset0, int32_t tapset1); + void init_caps(int32_t* cap, int32_t LM, int32_t C); + uint32_t celt_lcg_rand(uint32_t seed); + int16_t bitexact_cos(int16_t x); + int32_t bitexact_log2tan(int32_t isin, int32_t icos); + void denormalise_bands(const int16_t* X, int32_t* freq, const int16_t* bandLogE, int32_t start, int32_t end, int32_t M, int32_t downsample, int32_t silence); + void anti_collapse(int16_t* X_, uint8_t* collapse_masks, int32_t LM, int32_t C, int32_t size, int32_t start, int32_t end, const int16_t* logE, const int16_t* prev1logE, const int16_t* prev2logE, + const int32_t* pulses, uint32_t seed); + void compute_channel_weights(int32_t Ex, int32_t Ey, int16_t w[2]); + void stereo_split(int16_t* X, int16_t* Y, int32_t N); + void stereo_merge(int16_t* X, int16_t* Y, int16_t mid, int32_t N); + void deinterleave_hadamard(int16_t* X, int32_t N0, int32_t stride, int32_t hadamard); + void interleave_hadamard(int16_t* X, int32_t N0, int32_t stride, int32_t hadamard); + void haar1(int16_t* X, int32_t N0, int32_t stride); + int32_t compute_qn(int32_t N, int32_t b, int32_t offset, int32_t pulse_cap, int32_t stereo); + void compute_theta(struct split_ctx* sctx, int16_t* X, int16_t* Y, int32_t N, int32_t* b, int32_t B, int32_t __B0, int32_t LM, int32_t stereo, int32_t* fill); + uint32_t quant_band_n1(int16_t* X, int16_t* Y, int32_t b, int16_t* lowband_out); + uint32_t quant_partition(int16_t* X, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t gain, int32_t fill); + uint32_t quant_band(int16_t* X, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t* lowband_out, int16_t gain, int16_t* lowband_scratch, int32_t fill); + uint32_t quant_band_stereo(int16_t* X, int16_t* Y, int32_t N, int32_t b, int32_t B, int16_t* lowband, int32_t LM, int16_t* lowband_out, int16_t* lowband_scratch, int32_t fill); + void special_hybrid_folding(int16_t* norm, int16_t* norm2, int32_t start, int32_t M, int32_t dual_stereo); + void quant_all_bands(int32_t start, int32_t end, int16_t* X_, int16_t* Y_, uint8_t* collapse_masks, const int32_t* bandE, int32_t* pulses, int32_t shortBlocks, int32_t spread, int32_t dual_stereo, + int32_t intensity, int32_t* tf_res, int32_t total_bits, int32_t balance, int32_t LM, int32_t codedBands, uint32_t* seed, int32_t complexity, int32_t disable_inv); + int32_t celt_decoder_get_size(int32_t channels); + void deemphasis_stereo_simple(int32_t* in[], int16_t* pcm, int32_t N, const int16_t coef0, int32_t* mem); + void deemphasis(int32_t* in[], int16_t* pcm, int32_t N, int32_t C, int32_t downsample, const int16_t* coef, int32_t* mem, int32_t accum); + void celt_synthesis(int16_t* X, int32_t* out_syn[], int16_t* oldBandE, int32_t start, int32_t effEnd, int32_t C, int32_t CC, int32_t isTransient, int32_t LM, int32_t downsample, int32_t silence); + void tf_decode(int32_t start, int32_t end, int32_t isTransient, int32_t* tf_res, int32_t LM); + int32_t cwrsi(int32_t _n, int32_t _k, uint32_t _i, int32_t* _y); + int32_t decode_pulses(int32_t* _y, int32_t _n, int32_t _k); + void kf_bfly2(kiss_fft_cpx* Fout, int32_t m, int32_t N); + void kf_bfly4(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* st, int32_t m, int32_t N, int32_t mm); + void kf_bfly3(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* st, int32_t m, int32_t N, int32_t mm); + void kf_bfly5(kiss_fft_cpx* Fout, const size_t fstride, const kiss_fft_state* st, int32_t m, int32_t N, int32_t mm); + void opus_fft_impl(const kiss_fft_state* st, kiss_fft_cpx* fout); + uint32_t isqrt32(uint32_t _val); + int16_t celt_rsqrt_norm(int32_t x); + int32_t celt_sqrt(int32_t x); + int16_t celt_cos_norm(int32_t x); + void clt_mdct_backward(int32_t* in, int32_t* out, int32_t overlap, int32_t shift, int32_t stride); + int32_t interp_bits2pulses(int32_t start, int32_t end, int32_t skip_start, const int32_t* bits1, const int32_t* bits2, const int32_t* thresh, const int32_t* cap, int32_t total, int32_t* _balance, + int32_t skip_rsv, int32_t* intensity, int32_t intensity_rsv, int32_t* dual_stereo, int32_t dual_stereo_rsv, int32_t* bits, int32_t* ebits, int32_t* fine_priority, + int32_t C, int32_t LM, int32_t encode, int32_t prev, int32_t signalBandwidth); + int32_t clt_compute_allocation(int32_t start, int32_t end, const int32_t* offsets, const int32_t* cap, int32_t alloc_trim, int32_t* intensity, int32_t* dual_stereo, int32_t total, + int32_t* balance, int32_t* pulses, int32_t* ebits, int32_t* fine_priority, int32_t C, int32_t LM, int32_t encode, int32_t prev, int32_t signalBandwidth); + void unquant_coarse_energy(int32_t start, int32_t end, int16_t* oldEBands, int32_t intra, int32_t C, int32_t LM); + void unquant_fine_energy(int32_t start, int32_t end, int16_t* oldEBands, int32_t* fine_quant, int32_t C); + void unquant_energy_finalise(int32_t start, int32_t end, int16_t* oldEBands, int32_t* fine_quant, int32_t* fine_priority, int32_t bits_left, int32_t C); + uint32_t celt_udiv(uint32_t n, uint32_t d); + int32_t celt_sudiv(int32_t n, int32_t d); + int16_t sig2word16(int32_t x); + int16_t celt_atan01(int16_t x); + int16_t celt_atan2p(int16_t y, int16_t x); + int32_t celt_maxabs16(const int16_t* x, int32_t len); + int32_t celt_maxabs32(const int32_t* x, int32_t len); + int16_t celt_ilog2(int32_t x); + int16_t celt_zlog2(int32_t x); + int32_t celt_exp2_frac(int16_t x); + int32_t celt_exp2(int16_t x); + void dual_inner_prod_c(const int16_t* x, const int16_t* y01, const int16_t* y02, int32_t N, int32_t* xy1, int32_t* xy2); + int32_t get_pulses(int32_t i); + int32_t bits2pulses(int32_t band, int32_t LM, int32_t bits); + int32_t pulses2bits(int32_t band, int32_t LM, int32_t pulses); + int16_t celt_log2(int32_t x); + int16_t _celt_cos_pi_2(int16_t x); +}; diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/celt_defines.h b/libraries/ESP32-audioI2S/src/opus_decoder/celt_defines.h new file mode 100644 index 0000000..0edf2f3 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/celt_defines.h @@ -0,0 +1,153 @@ +#pragma once + +#define OPUS_OK 0 +#define OPUS_BAD_ARG -1 +#define OPUS_BUFFER_TOO_SMALL -2 +#define OPUS_INTERNAL_ERROR -3 +#define OPUS_INVALID_PACKET -4 +#define OPUS_UNIMPLEMENTED -5 +#define OPUS_INVALID_STATE -6 +#define OPUS_ALLOC_FAIL -7 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +#define OPUS_RESET_STATE 4028 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 +#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define LEAK_BANDS 19 +#define MAXFACTORS 8 +#define CELT_CLZ0s ((int32_t)sizeof(uint32_t) * CHAR_BIT) +#define CELT_CLZ(_x) (__builtin_clz(_x)) +#define CELT_ILOG(_x) (CELT_CLZ0s - CELT_CLZ(_x)) +#define DECODER_RESET_START rng +#define TOTAL_MODES 1 +#define BITRES 3 +#define SPREAD_NONE (0) +#define SPREAD_LIGHT (1) +#define SPREAD_NORMAL (2) +#define SPREAD_AGGRESSIVE (3) +#define opus_likely(x) (__builtin_expect(!!(x), 1)) +#define opus_unlikely(x) (__builtin_expect(!!(x), 0)) +#define assert2(cond, message) +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 +#define LPC_ORDER 24 +#define S_MUL(a, b) MULT16_32_Q15(b, a) +#define C_MUL(m, a, b) \ + do { \ + (m).r = SUB32_ovflw(S_MUL((a).r, (b).r), S_MUL((a).i, (b).i)); \ + (m).i = ADD32_ovflw(S_MUL((a).r, (b).i), S_MUL((a).i, (b).r)); \ + } while (0) +#define C_MULBYSCALAR(c, s) \ + do { \ + (c).r = S_MUL((c).r, s); \ + (c).i = S_MUL((c).i, s); \ + } while (0) +#define DIVSCALAR(x, k) (x) = S_MUL(x, (TWID_MAX - ((k) >> 1)) / (k) + 1) +#define C_ADD(res, a, b) \ + do { \ + (res).r = ADD32_ovflw((a).r, (b).r); \ + (res).i = ADD32_ovflw((a).i, (b).i); \ + } while (0) +#define C_SUB(res, a, b) \ + do { \ + (res).r = SUB32_ovflw((a).r, (b).r); \ + (res).i = SUB32_ovflw((a).i, (b).i); \ + } while (0) +#define C_ADDTO(res, a) \ + do { \ + (res).r = ADD32_ovflw((res).r, (a).r); \ + (res).i = ADD32_ovflw((res).i, (a).i); \ + } while (0) +#define HALF_OF(x) ((x) >> 1) +#define COMBFILTER_MINPERIOD 15 +#define comb_filter_const(y, x, T, N, g10, g11, g12) (comb_filter_const_c(y, x, T, N, g10, g11, g12)) +#define SIG_SAT (300000000) +#define NORM_SCALING 16384 +#define DB_SHIFT 10 +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE16 ((int16_t)32767) +#define Q15_ONE ((int16_t)32767) +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) +#define MULT16_16SU(a, b) ((int32_t)(int16_t)(a) * (int32_t)(uint16_t)(b)) /** Multiply a 16-bit signed value by a 16-bit uint32_t value. The result is a 32-bit signed value */ +#define MULT16_32_P16(a, b) ((int32_t)PSHR((int64_t)((int16_t)(a)) * (b), 16)) /** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#define MULT16_32_Q15(a, b) ((int32_t)SHR((int64_t)((int16_t)(a)) * (b), 15)) /** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MULT32_32_Q31(a, b) ((int32_t)SHR((int64_t)(a) * (int64_t)(b), 31)) /** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#define QCONST16(x, bits) ((int16_t)(0.5L + (x) * (((int32_t)1) << (bits)))) /** Compile-time conversion of float constant to 16-bit value */ +#define QCONST32(x, bits) ((int32_t)(0.5L + (x) * (((int32_t)1) << (bits)))) /** Compile-time conversion of float constant to 32-bit value */ +#define NEG16(x) (-(x)) /** Negate a 16-bit value */ +#define NEG32(x) (-(x)) /** Negate a 32-bit value */ +#define EXTRACT16(x) ((int16_t)(x)) /** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTEND32(x) ((int32_t)(x)) /** Change a 16-bit value into a 32-bit value */ +#define SHR16(a, shift) ((a) >> (shift)) /** Arithmetic shift-right of a 16-bit value */ +#define SHL16(a, shift) ((int16_t)((uint16_t)(a) << (shift))) /** Arithmetic shift-left of a 16-bit value */ +#define SHR32(a, shift) ((a) >> (shift)) /** Arithmetic shift-right of a 32-bit value */ +#define SHL32(a, shift) ((int32_t)((uint32_t)(a) << (shift))) /** Arithmetic shift-left of a 32-bit value */ +#define PSHR32(a, shift) (SHR32((a) + ((EXTEND32(1) << ((shift)) >> 1)), shift)) /** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define VSHR32(a, shift) (((shift) > 0) ? SHR32(a, shift) : SHL32(a, -(shift))) /** 32-bit arithmetic shift right where the argument can be negative */ +#define SHR(a, shift) ((a) >> (shift)) /** "RAW" macros, should not be used outside of this header file */ +#define SHL(a, shift) SHL32(a, shift) +#define PSHR(a, shift) (SHR((a) + ((EXTEND32(1) << ((shift)) >> 1)), shift)) +#define SATURATE(x, a) (((x) > (a) ? (a) : (x) < -(a) ? -(a) : (x))) +#define SATURATE16(x) (EXTRACT16((x) > 32767 ? 32767 : (x) < -32768 ? -32768 : (x))) +#define ROUND16(x, a) (EXTRACT16(PSHR32((x), (a)))) /** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define SROUND16(x, a) EXTRACT16(SATURATE(PSHR32(x, a), 32767)); /** Shift by a and round-to-neareast 32-bit value. Result is a saturated 16-bit value */ +#define HALF16(x) (SHR16(x, 1)) /** Divide by two */ +#define HALF32(x) (SHR32(x, 1)) +#define ADD16(a, b) ((int16_t)((int16_t)(a) + (int16_t)(b))) /** Add two 16-bit values */ +#define SUB16(a, b) ((int16_t)(a) - (int16_t)(b)) /** Subtract two 16-bit values */ +#define ADD32(a, b) ((int32_t)(a) + (int32_t)(b)) /** Add two 32-bit values */ +#define SUB32(a, b) ((int32_t)(a) - (int32_t)(b)) /** Subtract two 32-bit values */ +#define ADD32_ovflw(a, b) ((int32_t)((uint32_t)(a) + (uint32_t)(b))) /** Add two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a, b) ((int32_t)((uint32_t)(a) - (uint32_t)(b))) /** Subtract two 32-bit values, ignore any overflows */ +#define NEG32_ovflw(a) ((int32_t)(0 - (uint32_t)(a))) /* Avoid MSVC warning C4146: unary minus operator applied to uint32_t type, Negate 32-bit value, ignore any overflows */ +#define MULT16_16_16(a, b) ((((int16_t)(a)) * ((int16_t)(b)))) +#define MULT16_16(a, b) (((int32_t)(int16_t)(a)) * ((int32_t)(int16_t)(b))) /** 16x16 multiplication where the result fits in 32 bits */ +#define MAC16_16(c, a, b) (ADD32((c), MULT16_16((a), (b)))) /** 16x16 multiply-add where the result fits in 32 bits */ +#define MULT16_16_Q11_32(a, b) (SHR(MULT16_16((a), (b)), 11)) +#define MULT16_16_Q11(a, b) (SHR(MULT16_16((a), (b)), 11)) +#define MULT16_16_Q13(a, b) (SHR(MULT16_16((a), (b)), 13)) +#define MULT16_16_Q14(a, b) (SHR(MULT16_16((a), (b)), 14)) +#define MULT16_16_Q15(a, b) (SHR(MULT16_16((a), (b)), 15)) +#define MULT16_16_P13(a, b) (SHR(ADD32(4096, MULT16_16((a), (b))), 13)) +#define MULT16_16_P14(a, b) (SHR(ADD32(8192, MULT16_16((a), (b))), 14)) +#define MULT16_16_P15(a, b) (SHR(ADD32(16384, MULT16_16((a), (b))), 15)) +#define DIV32_16(a, b) ((int16_t)(((int32_t)(a)) / ((int16_t)(b)))) /** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32(a, b) (((int32_t)(a)) / ((int32_t)(b))) /** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define celt_div(a, b) MULT32_32_Q31((int32_t)(a), celt_rcp(b)) +#define MAX_PERIOD 1024 +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n) * sizeof(*(dst)) + 0 * ((dst) - (src)))) +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n) * sizeof(*(dst)))) +#define ALLOC_STEPS 6 +#define celt_inner_prod(x, y, N) (celt_inner_prod_c(x, y, N)) +#define dual_inner_prod(x, y01, y02, N, xy1, xy2) (dual_inner_prod_c(x, y01, y02, N, xy1, xy2)) +#define FRAC_MUL16(a, b) ((16384 + ((int32_t)(int16_t)(a) * (int16_t)(b))) >> 15) /* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 +#define MAX_FINE_BITS 8 +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 +#define ALLOC_NONE 1 +#define OPUS_FPRINTF (void) +#define DECODE_BUFFER_SIZE 2048 +#define CELT_PVQ_U(_n, _k) (celt_pvq_u_row(min(_n, _k), max(_n, _k))) +#define CELT_PVQ_V(_n, _k) (CELT_PVQ_U(_n, _k) + CELT_PVQ_U(_n, (_k) + 1)) +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_GET_MODE_REQUEST 10015 +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_TONALITY_REQUEST 10018 +#define CELT_SET_TONALITY_SLOPE_REQUEST 10020 +#define CELT_SET_ANALYSIS_REQUEST 10022 +#define OPUS_SET_LFE_REQUEST 10024 +#define OPUS_SET_ENERGY_MASK_REQUEST 10026 +#define CELT_SET_SILK_INFO_REQUEST 10028 +#define PLC_PITCH_LAG_MAX 720 +#define PLC_PITCH_LAG_MIN 100 diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/celt_structs.h b/libraries/ESP32-audioI2S/src/opus_decoder/celt_structs.h new file mode 100644 index 0000000..b1802e0 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/celt_structs.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include "celt_defines.h" + +typedef struct { + int32_t r; + int32_t i; +} kiss_fft_cpx; + +typedef struct { + int16_t r; + int16_t i; +} kiss_twiddle_cpx; + +typedef struct kiss_fft_state { + int32_t nfft; + int16_t scale; + int32_t scale_shift; + int32_t shift; + int16_t factors[2 * MAXFACTORS]; + const int16_t* bitrev; + const kiss_twiddle_cpx* twiddles; +} kiss_fft_state; + +typedef struct { + int32_t n; + int32_t maxshift; + const kiss_fft_state* kfft[4]; + const int16_t* trig; +} mdct_lookup_t; + +typedef struct { + int32_t size; + const int16_t* index; + const uint8_t* bits; + const uint8_t* caps; +} PulseCache; + +typedef struct _CELTMode { + int32_t Fs; + int32_t overlap; + int32_t nbEBands; + int32_t effEBands; + int16_t preemph[4]; + int32_t maxLM; + int32_t nbShortMdcts; + int32_t shortMdctSize; + int32_t nbAllocVectors; /**< Number of lines in the matrix below */ +} CELTMode_t; + +typedef struct _band_ctx { + int32_t resynth; + const CELTMode_t* m; + int32_t i; + int32_t intensity; + int32_t spread; + int32_t tf_change; + int32_t remaining_bits; + const int32_t* bandE; + uint32_t seed; + int32_t theta_round; + int32_t disable_inv; + int32_t avoid_split_noise; +} band_ctx_t; + +struct split_ctx { + int32_t inv; + int32_t imid; + int32_t iside; + int32_t delta; + int32_t itheta; + int32_t qalloc; +}; + +typedef struct _CELTDecoder { + int32_t overlap; + int32_t channels; + int32_t stream_channels; + int32_t downsample; + int32_t start, end; + int32_t signalling; + int32_t disable_inv; + uint32_t rng; + int32_t error; + int32_t last_pitch_index; + int32_t loss_count; + int32_t skip_plc; + int32_t postfilter_period; + int32_t postfilter_period_old; + int16_t postfilter_gain; + int16_t postfilter_gain_old; + int32_t postfilter_tapset; + int32_t postfilter_tapset_old; + int32_t preemph_memD[2]; +} CELTDecoder_t; + + diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/celt_tables.h b/libraries/ESP32-audioI2S/src/opus_decoder/celt_tables.h new file mode 100644 index 0000000..a320011 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/celt_tables.h @@ -0,0 +1,359 @@ +#pragma once // celt_tables + +#include "celt_structs.h" +#include + +static const int16_t eband5ms[22] = { + /*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100}; + +static const uint8_t band_allocation[231] = { + /*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 110, 100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, 118, 110, 103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, + 15, 4, 0, 0, 0, 0, 126, 119, 112, 104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, 134, 127, 120, 114, 103, 97, 91, 85, 78, 72, 66, 60, + 54, 47, 41, 35, 29, 23, 16, 10, 1, 144, 137, 130, 124, 113, 107, 101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, 152, 145, 138, 132, 123, 117, 111, 105, 98, + 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, 162, 155, 148, 142, 133, 127, 121, 115, 108, 102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, 172, 165, 158, 152, 143, 137, + 131, 125, 118, 112, 106, 100, 94, 87, 81, 75, 69, 63, 56, 45, 20, 200, 200, 200, 200, 200, 200, 200, 200, 198, 193, 188, 183, 178, 173, 168, 163, 158, 153, 148, 129, 104, +}; + +/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)). Thus, the number of entries in row I is + the larger of the maximum number of pulses we will ever allocate for a given N=I (K=128, or however many fit in + 32 bits, whichever is smaller), plus one, and the maximum N for which K=I-1 pulses fit in 32 bits. + The largest band size in an Opus Custom mode is 208. Otherwise, we can limit things to the set of N which can be + achieved by splitting a band from a + standard Opus mode: 176, 144, 96, 88, 72, 64, 48,44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/ + +static const uint32_t CELT_PVQ_U_DATA[1272] = { + /*N=0, K=0...176:*/ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*N=1, K=1...176:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /*N=2, K=2...176:*/ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, + 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, + 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, + 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335, + 337, 339, 341, 343, 345, 347, 349, 351, + /*N=3, K=3...176:*/ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, + 3121, 3281, 3445, 3613, 3785, 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, 9941, + 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, 17113, 17485, 17861, 18241, 18625, 19013, 19405, + 19801, 20201, 20605, 21013, 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, 31501, 32005, + 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, + 48361, 48985, 49613, 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, 57461, 58141, 58825, 59513, 60205, 60901, 61601, + /*N=4, K=4...176:*/ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, 30913, 34279, 37881, 41727, 45825, 50183, + 54809, 59711, 64897, 70375, 76153, 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, 267033, + 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, 597057, 620775, 645113, 670079, 695681, 721927, 748825, + 776383, 804609, 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, 1436025, 1478463, 1521729, + 1565831, 1610777, 1656575, 1703233, 1750759, 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, 3858425, 3940223, 4023169, 4107271, 4192537, + 4278975, 4366593, 4455399, 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, 6154617, 6266175, + 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, 7085049, 7207551, + /*N=5, K=5...176:*/ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, 330409, 383041, 441729, 506921, 579081, + 658689, 746241, 842249, 947241, 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, 4695809, 5071041, + 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, + 19468809, 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, 40914369, 42794761, 44739241, 46749249, + 48826241, 50971689, 53187081, 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, 95872041, 99421961, + 103069569, 106816641, 110664969, 114616361, 118672641, 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, 155123009, 160208001, 165417001, 170752009, 176215041, + 181808129, 187533321, 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, 290705281, + 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, 420810249, 431530241, 442453761, 453583369, + 464921641, 476471169, 488234561, 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, 590359041, 604167209, 618216201, 632508801, + /*N=6, K=6...96:*/ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, 2908411, 3522221, 4235671, 5060441, + 6009091, 7095093, 8332863, 9737793, 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, 64696159, 71789409, + 79491819, 87841821, 96879431, 106646281, 117185651, 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, + 374284647, 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, 1020274013, 1083597703, + 1150027593, 1219676595, 1292660325, 1369097135, 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, 2011371957, 2120032959, + /*N=7, K=7...54*/ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, 19665841, 24957661, 31388293, 39146185, + 48442297, 59511829, 72616013, 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, 793950709, + 904317037, 1027188385, 1163673953, 1314955181, 1482288821, 1667010073, 1870535785, 2094367717, + /*N=8, K=8...37*/ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, 104692735, 139703809, 184327311, 240673265, + 311207743, 398796225, 506750351, 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, 2229491905U, + /*N=9, K=9...28:*/ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, 628496897, 872893441, 1196924561, 1621925137, + 2173806145U, + /*N=10, K=10...24:*/ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U, 3375210671U, + /*N=11, K=11...19:*/ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, 948062325, 1616336765, + /*N=12, K=12...18:*/ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, 3248227095U, + /*N=13, K=13...16:*/ + 251595969, 579168825, 1267854873, 2653649025U, + /*N=14, K=14:*/ + 1409933619}; + +static const int16_t mdct_twiddles960[1800] = { + 32767, 32767, 32767, 32766, 32765, 32763, 32761, 32759, 32756, 32753, 32750, 32746, 32742, 32738, 32733, 32728, 32722, 32717, 32710, 32704, 32697, 32690, 32682, 32674, + 32666, 32657, 32648, 32639, 32629, 32619, 32609, 32598, 32587, 32576, 32564, 32552, 32539, 32526, 32513, 32500, 32486, 32472, 32457, 32442, 32427, 32411, 32395, 32379, + 32362, 32345, 32328, 32310, 32292, 32274, 32255, 32236, 32217, 32197, 32177, 32157, 32136, 32115, 32093, 32071, 32049, 32027, 32004, 31981, 31957, 31933, 31909, 31884, + 31859, 31834, 31809, 31783, 31756, 31730, 31703, 31676, 31648, 31620, 31592, 31563, 31534, 31505, 31475, 31445, 31415, 31384, 31353, 31322, 31290, 31258, 31226, 31193, + 31160, 31127, 31093, 31059, 31025, 30990, 30955, 30920, 30884, 30848, 30812, 30775, 30738, 30701, 30663, 30625, 30587, 30548, 30509, 30470, 30430, 30390, 30350, 30309, + 30269, 30227, 30186, 30144, 30102, 30059, 30016, 29973, 29930, 29886, 29842, 29797, 29752, 29707, 29662, 29616, 29570, 29524, 29477, 29430, 29383, 29335, 29287, 29239, + 29190, 29142, 29092, 29043, 28993, 28943, 28892, 28842, 28791, 28739, 28688, 28636, 28583, 28531, 28478, 28425, 28371, 28317, 28263, 28209, 28154, 28099, 28044, 27988, + 27932, 27876, 27820, 27763, 27706, 27648, 27591, 27533, 27474, 27416, 27357, 27298, 27238, 27178, 27118, 27058, 26997, 26936, 26875, 26814, 26752, 26690, 26628, 26565, + 26502, 26439, 26375, 26312, 26247, 26183, 26119, 26054, 25988, 25923, 25857, 25791, 25725, 25658, 25592, 25524, 25457, 25389, 25322, 25253, 25185, 25116, 25047, 24978, + 24908, 24838, 24768, 24698, 24627, 24557, 24485, 24414, 24342, 24270, 24198, 24126, 24053, 23980, 23907, 23834, 23760, 23686, 23612, 23537, 23462, 23387, 23312, 23237, + 23161, 23085, 23009, 22932, 22856, 22779, 22701, 22624, 22546, 22468, 22390, 22312, 22233, 22154, 22075, 21996, 21916, 21836, 21756, 21676, 21595, 21515, 21434, 21352, + 21271, 21189, 21107, 21025, 20943, 20860, 20777, 20694, 20611, 20528, 20444, 20360, 20276, 20192, 20107, 20022, 19937, 19852, 19767, 19681, 19595, 19509, 19423, 19336, + 19250, 19163, 19076, 18988, 18901, 18813, 18725, 18637, 18549, 18460, 18372, 18283, 18194, 18104, 18015, 17925, 17835, 17745, 17655, 17565, 17474, 17383, 17292, 17201, + 17110, 17018, 16927, 16835, 16743, 16650, 16558, 16465, 16372, 16279, 16186, 16093, 15999, 15906, 15812, 15718, 15624, 15529, 15435, 15340, 15245, 15150, 15055, 14960, + 14864, 14769, 14673, 14577, 14481, 14385, 14288, 14192, 14095, 13998, 13901, 13804, 13706, 13609, 13511, 13414, 13316, 13218, 13119, 13021, 12923, 12824, 12725, 12626, + 12527, 12428, 12329, 12230, 12130, 12030, 11930, 11831, 11730, 11630, 11530, 11430, 11329, 11228, 11128, 11027, 10926, 10824, 10723, 10622, 10520, 10419, 10317, 10215, + 10113, 10011, 9909, 9807, 9704, 9602, 9499, 9397, 9294, 9191, 9088, 8985, 8882, 8778, 8675, 8572, 8468, 8364, 8261, 8157, 8053, 7949, 7845, 7741, + 7637, 7532, 7428, 7323, 7219, 7114, 7009, 6905, 6800, 6695, 6590, 6485, 6380, 6274, 6169, 6064, 5958, 5853, 5747, 5642, 5536, 5430, 5325, 5219, + 5113, 5007, 4901, 4795, 4689, 4583, 4476, 4370, 4264, 4157, 4051, 3945, 3838, 3732, 3625, 3518, 3412, 3305, 3198, 3092, 2985, 2878, 2771, 2664, + 2558, 2451, 2344, 2237, 2130, 2023, 1916, 1809, 1702, 1594, 1487, 1380, 1273, 1166, 1059, 952, 844, 737, 630, 523, 416, 308, 201, 94, + -13, -121, -228, -335, -442, -550, -657, -764, -871, -978, -1086, -1193, -1300, -1407, -1514, -1621, -1728, -1835, -1942, -2049, -2157, -2263, -2370, -2477, + -2584, -2691, -2798, -2905, -3012, -3118, -3225, -3332, -3439, -3545, -3652, -3758, -3865, -3971, -4078, -4184, -4290, -4397, -4503, -4609, -4715, -4821, -4927, -5033, + -5139, -5245, -5351, -5457, -5562, -5668, -5774, -5879, -5985, -6090, -6195, -6301, -6406, -6511, -6616, -6721, -6826, -6931, -7036, -7140, -7245, -7349, -7454, -7558, + -7663, -7767, -7871, -7975, -8079, -8183, -8287, -8390, -8494, -8597, -8701, -8804, -8907, -9011, -9114, -9217, -9319, -9422, -9525, -9627, -9730, -9832, -9934, -10037, + -10139, -10241, -10342, -10444, -10546, -10647, -10748, -10850, -10951, -11052, -11153, -11253, -11354, -11455, -11555, -11655, -11756, -11856, -11955, -12055, -12155, -12254, -12354, -12453, + -12552, -12651, -12750, -12849, -12947, -13046, -13144, -13242, -13340, -13438, -13536, -13633, -13731, -13828, -13925, -14022, -14119, -14216, -14312, -14409, -14505, -14601, -14697, -14793, + -14888, -14984, -15079, -15174, -15269, -15364, -15459, -15553, -15647, -15741, -15835, -15929, -16023, -16116, -16210, -16303, -16396, -16488, -16581, -16673, -16766, -16858, -16949, -17041, + -17133, -17224, -17315, -17406, -17497, -17587, -17678, -17768, -17858, -17948, -18037, -18127, -18216, -18305, -18394, -18483, -18571, -18659, -18747, -18835, -18923, -19010, -19098, -19185, + -19271, -19358, -19444, -19531, -19617, -19702, -19788, -19873, -19959, -20043, -20128, -20213, -20297, -20381, -20465, -20549, -20632, -20715, -20798, -20881, -20963, -21046, -21128, -21210, + -21291, -21373, -21454, -21535, -21616, -21696, -21776, -21856, -21936, -22016, -22095, -22174, -22253, -22331, -22410, -22488, -22566, -22643, -22721, -22798, -22875, -22951, -23028, -23104, + -23180, -23256, -23331, -23406, -23481, -23556, -23630, -23704, -23778, -23852, -23925, -23998, -24071, -24144, -24216, -24288, -24360, -24432, -24503, -24574, -24645, -24716, -24786, -24856, + -24926, -24995, -25064, -25133, -25202, -25270, -25339, -25406, -25474, -25541, -25608, -25675, -25742, -25808, -25874, -25939, -26005, -26070, -26135, -26199, -26264, -26327, -26391, -26455, + -26518, -26581, -26643, -26705, -26767, -26829, -26891, -26952, -27013, -27073, -27133, -27193, -27253, -27312, -27372, -27430, -27489, -27547, -27605, -27663, -27720, -27777, -27834, -27890, + -27946, -28002, -28058, -28113, -28168, -28223, -28277, -28331, -28385, -28438, -28491, -28544, -28596, -28649, -28701, -28752, -28803, -28854, -28905, -28955, -29006, -29055, -29105, -29154, + -29203, -29251, -29299, -29347, -29395, -29442, -29489, -29535, -29582, -29628, -29673, -29719, -29764, -29808, -29853, -29897, -29941, -29984, -30027, -30070, -30112, -30154, -30196, -30238, + -30279, -30320, -30360, -30400, -30440, -30480, -30519, -30558, -30596, -30635, -30672, -30710, -30747, -30784, -30821, -30857, -30893, -30929, -30964, -30999, -31033, -31068, -31102, -31135, + -31168, -31201, -31234, -31266, -31298, -31330, -31361, -31392, -31422, -31453, -31483, -31512, -31541, -31570, -31599, -31627, -31655, -31682, -31710, -31737, -31763, -31789, -31815, -31841, + -31866, -31891, -31915, -31939, -31963, -31986, -32010, -32032, -32055, -32077, -32099, -32120, -32141, -32162, -32182, -32202, -32222, -32241, -32260, -32279, -32297, -32315, -32333, -32350, + -32367, -32383, -32399, -32415, -32431, -32446, -32461, -32475, -32489, -32503, -32517, -32530, -32542, -32555, -32567, -32579, -32590, -32601, -32612, -32622, -32632, -32641, -32651, -32659, + -32668, -32676, -32684, -32692, -32699, -32706, -32712, -32718, -32724, -32729, -32734, -32739, -32743, -32747, -32751, -32754, -32757, -32760, -32762, -32764, -32765, -32767, -32767, -32767, + 32767, 32767, 32765, 32761, 32756, 32750, 32742, 32732, 32722, 32710, 32696, 32681, 32665, 32647, 32628, 32608, 32586, 32562, 32538, 32512, 32484, 32455, 32425, 32393, + 32360, 32326, 32290, 32253, 32214, 32174, 32133, 32090, 32046, 32001, 31954, 31906, 31856, 31805, 31753, 31700, 31645, 31588, 31530, 31471, 31411, 31349, 31286, 31222, + 31156, 31089, 31020, 30951, 30880, 30807, 30733, 30658, 30582, 30504, 30425, 30345, 30263, 30181, 30096, 30011, 29924, 29836, 29747, 29656, 29564, 29471, 29377, 29281, + 29184, 29086, 28987, 28886, 28784, 28681, 28577, 28471, 28365, 28257, 28147, 28037, 27925, 27812, 27698, 27583, 27467, 27349, 27231, 27111, 26990, 26868, 26744, 26620, + 26494, 26367, 26239, 26110, 25980, 25849, 25717, 25583, 25449, 25313, 25176, 25038, 24900, 24760, 24619, 24477, 24333, 24189, 24044, 23898, 23751, 23602, 23453, 23303, + 23152, 22999, 22846, 22692, 22537, 22380, 22223, 22065, 21906, 21746, 21585, 21423, 21261, 21097, 20933, 20767, 20601, 20434, 20265, 20096, 19927, 19756, 19584, 19412, + 19239, 19065, 18890, 18714, 18538, 18361, 18183, 18004, 17824, 17644, 17463, 17281, 17098, 16915, 16731, 16546, 16361, 16175, 15988, 15800, 15612, 15423, 15234, 15043, + 14852, 14661, 14469, 14276, 14083, 13889, 13694, 13499, 13303, 13107, 12910, 12713, 12515, 12317, 12118, 11918, 11718, 11517, 11316, 11115, 10913, 10710, 10508, 10304, + 10100, 9896, 9691, 9486, 9281, 9075, 8869, 8662, 8455, 8248, 8040, 7832, 7623, 7415, 7206, 6996, 6787, 6577, 6366, 6156, 5945, 5734, 5523, 5311, + 5100, 4888, 4675, 4463, 4251, 4038, 3825, 3612, 3399, 3185, 2972, 2758, 2544, 2330, 2116, 1902, 1688, 1474, 1260, 1045, 831, 617, 402, 188, + -27, -241, -456, -670, -885, -1099, -1313, -1528, -1742, -1956, -2170, -2384, -2598, -2811, -3025, -3239, -3452, -3665, -3878, -4091, -4304, -4516, -4728, -4941, + -5153, -5364, -5576, -5787, -5998, -6209, -6419, -6629, -6839, -7049, -7258, -7467, -7676, -7884, -8092, -8300, -8507, -8714, -8920, -9127, -9332, -9538, -9743, -9947, + -10151, -10355, -10558, -10761, -10963, -11165, -11367, -11568, -11768, -11968, -12167, -12366, -12565, -12762, -12960, -13156, -13352, -13548, -13743, -13937, -14131, -14324, -14517, -14709, + -14900, -15091, -15281, -15470, -15659, -15847, -16035, -16221, -16407, -16593, -16777, -16961, -17144, -17326, -17508, -17689, -17869, -18049, -18227, -18405, -18582, -18758, -18934, -19108, + -19282, -19455, -19627, -19799, -19969, -20139, -20308, -20475, -20642, -20809, -20974, -21138, -21301, -21464, -21626, -21786, -21946, -22105, -22263, -22420, -22575, -22730, -22884, -23037, + -23189, -23340, -23490, -23640, -23788, -23935, -24080, -24225, -24369, -24512, -24654, -24795, -24934, -25073, -25211, -25347, -25482, -25617, -25750, -25882, -26013, -26143, -26272, -26399, + -26526, -26651, -26775, -26898, -27020, -27141, -27260, -27379, -27496, -27612, -27727, -27841, -27953, -28065, -28175, -28284, -28391, -28498, -28603, -28707, -28810, -28911, -29012, -29111, + -29209, -29305, -29401, -29495, -29587, -29679, -29769, -29858, -29946, -30032, -30118, -30201, -30284, -30365, -30445, -30524, -30601, -30677, -30752, -30825, -30897, -30968, -31038, -31106, + -31172, -31238, -31302, -31365, -31426, -31486, -31545, -31602, -31658, -31713, -31766, -31818, -31869, -31918, -31966, -32012, -32058, -32101, -32144, -32185, -32224, -32262, -32299, -32335, + -32369, -32401, -32433, -32463, -32491, -32518, -32544, -32568, -32591, -32613, -32633, -32652, -32669, -32685, -32700, -32713, -32724, -32735, -32744, -32751, -32757, -32762, -32766, -32767, + 32767, 32764, 32755, 32741, 32720, 32694, 32663, 32626, 32583, 32535, 32481, 32421, 32356, 32286, 32209, 32128, 32041, 31948, 31850, 31747, 31638, 31523, 31403, 31278, + 31148, 31012, 30871, 30724, 30572, 30415, 30253, 30086, 29913, 29736, 29553, 29365, 29172, 28974, 28771, 28564, 28351, 28134, 27911, 27684, 27452, 27216, 26975, 26729, + 26478, 26223, 25964, 25700, 25432, 25159, 24882, 24601, 24315, 24026, 23732, 23434, 23133, 22827, 22517, 22204, 21886, 21565, 21240, 20912, 20580, 20244, 19905, 19563, + 19217, 18868, 18516, 18160, 17802, 17440, 17075, 16708, 16338, 15964, 15588, 15210, 14829, 14445, 14059, 13670, 13279, 12886, 12490, 12093, 11693, 11291, 10888, 10482, + 10075, 9666, 9255, 8843, 8429, 8014, 7597, 7180, 6760, 6340, 5919, 5496, 5073, 4649, 4224, 3798, 3372, 2945, 2517, 2090, 1661, 1233, 804, 375, + -54, -483, -911, -1340, -1768, -2197, -2624, -3052, -3479, -3905, -4330, -4755, -5179, -5602, -6024, -6445, -6865, -7284, -7702, -8118, -8533, -8946, -9358, -9768, + -10177, -10584, -10989, -11392, -11793, -12192, -12589, -12984, -13377, -13767, -14155, -14541, -14924, -15305, -15683, -16058, -16430, -16800, -17167, -17531, -17892, -18249, -18604, -18956, + -19304, -19649, -19990, -20329, -20663, -20994, -21322, -21646, -21966, -22282, -22595, -22904, -23208, -23509, -23806, -24099, -24387, -24672, -24952, -25228, -25499, -25766, -26029, -26288, + -26541, -26791, -27035, -27275, -27511, -27741, -27967, -28188, -28405, -28616, -28823, -29024, -29221, -29412, -29599, -29780, -29957, -30128, -30294, -30455, -30611, -30761, -30906, -31046, + -31181, -31310, -31434, -31552, -31665, -31773, -31875, -31972, -32063, -32149, -32229, -32304, -32373, -32437, -32495, -32547, -32594, -32635, -32671, -32701, -32726, -32745, -32758, -32766, + 32767, 32754, 32717, 32658, 32577, 32473, 32348, 32200, 32029, 31837, 31624, 31388, 31131, 30853, 30553, 30232, 29891, 29530, 29148, 28746, 28324, 27883, 27423, 26944, + 26447, 25931, 25398, 24847, 24279, 23695, 23095, 22478, 21846, 21199, 20538, 19863, 19174, 18472, 17757, 17030, 16291, 15541, 14781, 14010, 13230, 12441, 11643, 10837, + 10024, 9204, 8377, 7545, 6708, 5866, 5020, 4171, 3319, 2464, 1608, 751, -107, -965, -1822, -2678, -3532, -4383, -5232, -6077, -6918, -7754, -8585, -9409, + -10228, -11039, -11843, -12639, -13426, -14204, -14972, -15730, -16477, -17213, -17937, -18648, -19347, -20033, -20705, -21363, -22006, -22634, -23246, -23843, -24423, -24986, -25533, -26062, + -26573, -27066, -27540, -27995, -28431, -28848, -29245, -29622, -29979, -30315, -30630, -30924, -31197, -31449, -31679, -31887, -32074, -32239, -32381, -32501, -32600, -32675, -32729, -32759, +}; + +static const int16_t window120[120] = { + 2, 20, 55, 108, 178, 266, 372, 494, 635, 792, 966, 1157, 1365, 1590, 1831, 2089, 2362, 2651, 2956, 3276, 3611, 3961, 4325, 4703, + 5094, 5499, 5916, 6346, 6788, 7241, 7705, 8179, 8663, 9156, 9657, 10167, 10684, 11207, 11736, 12271, 12810, 13353, 13899, 14447, 14997, 15547, 16098, 16648, + 17197, 17744, 18287, 18827, 19363, 19893, 20418, 20936, 21447, 21950, 22445, 22931, 23407, 23874, 24330, 24774, 25208, 25629, 26039, 26435, 26819, 27190, 27548, 27893, + 28224, 28541, 28845, 29135, 29411, 29674, 29924, 30160, 30384, 30594, 30792, 30977, 31151, 31313, 31463, 31602, 31731, 31849, 31958, 32057, 32148, 32229, 32303, 32370, + 32429, 32481, 32528, 32568, 32604, 32634, 32661, 32683, 32701, 32717, 32729, 32740, 32748, 32754, 32758, 32762, 32764, 32766, 32767, 32767, 32767, 32767, 32767, 32767, +}; + +static const int16_t logN400[21] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, +}; + +static const int16_t cache_index50[105] = { + -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, 41, 123, 123, + 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, + 123, 240, 240, 240, 240, 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const uint8_t cache_bits50[392] = { + 40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 40, 15, 23, 28, 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, + 63, 63, 65, 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, 94, 96, 98, + 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, 97, 100, 102, 105, 107, 111, 115, 118, 121, + 124, 126, 129, 131, 135, 139, 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, + 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, 166, 174, 182, 189, 195, 201, + 207, 217, 227, 235, 243, 251, 17, 35, 63, 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, + 168, 174, 180, 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, 74, 103, 128, + 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, 228, 241, 253, 9, 44, 81, 113, 142, 168, + 192, 214, 235, 255, 7, 49, 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, + 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, 182, 234, +}; +static const uint8_t cache_caps50[168] = { + 224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, 240, 240, 240, 207, + 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38, 240, 240, 240, 240, 240, + 240, 240, 240, 207, 207, 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, + 138, 65, 39, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, + 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40, +}; + +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { + {32767, 0}, {32766, -429}, {32757, -858}, {32743, -1287}, {32724, -1715}, {32698, -2143}, {32667, -2570}, {32631, -2998}, {32588, -3425}, {32541, -3851}, + {32488, -4277}, {32429, -4701}, {32364, -5125}, {32295, -5548}, {32219, -5971}, {32138, -6393}, {32051, -6813}, {31960, -7231}, {31863, -7650}, {31760, -8067}, + {31652, -8481}, {31539, -8895}, {31419, -9306}, {31294, -9716}, {31165, -10126}, {31030, -10532}, {30889, -10937}, {30743, -11340}, {30592, -11741}, {30436, -12141}, + {30274, -12540}, {30107, -12935}, {29936, -13328}, {29758, -13718}, {29577, -14107}, {29390, -14493}, {29197, -14875}, {29000, -15257}, {28797, -15635}, {28590, -16010}, + {28379, -16384}, {28162, -16753}, {27940, -17119}, {27714, -17484}, {27482, -17845}, {27246, -18205}, {27006, -18560}, {26760, -18911}, {26510, -19260}, {26257, -19606}, + {25997, -19947}, {25734, -20286}, {25466, -20621}, {25194, -20952}, {24918, -21281}, {24637, -21605}, {24353, -21926}, {24063, -22242}, {23770, -22555}, {23473, -22865}, + {23171, -23171}, {22866, -23472}, {22557, -23769}, {22244, -24063}, {21927, -24352}, {21606, -24636}, {21282, -24917}, {20954, -25194}, {20622, -25465}, {20288, -25733}, + {19949, -25997}, {19607, -26255}, {19261, -26509}, {18914, -26760}, {18561, -27004}, {18205, -27246}, {17846, -27481}, {17485, -27713}, {17122, -27940}, {16755, -28162}, + {16385, -28378}, {16012, -28590}, {15636, -28797}, {15258, -28999}, {14878, -29197}, {14494, -29389}, {14108, -29576}, {13720, -29757}, {13329, -29934}, {12937, -30107}, + {12540, -30274}, {12142, -30435}, {11744, -30592}, {11342, -30743}, {10939, -30889}, {10534, -31030}, {10127, -31164}, {9718, -31294}, {9307, -31418}, {8895, -31537}, + {8482, -31652}, {8067, -31759}, {7650, -31862}, {7233, -31960}, {6815, -32051}, {6393, -32138}, {5973, -32219}, {5549, -32294}, {5127, -32364}, {4703, -32429}, + {4278, -32487}, {3852, -32541}, {3426, -32588}, {2999, -32630}, {2572, -32667}, {2144, -32698}, {1716, -32724}, {1287, -32742}, {860, -32757}, {430, -32766}, + {0, -32767}, {-429, -32766}, {-858, -32757}, {-1287, -32743}, {-1715, -32724}, {-2143, -32698}, {-2570, -32667}, {-2998, -32631}, {-3425, -32588}, {-3851, -32541}, + {-4277, -32488}, {-4701, -32429}, {-5125, -32364}, {-5548, -32295}, {-5971, -32219}, {-6393, -32138}, {-6813, -32051}, {-7231, -31960}, {-7650, -31863}, {-8067, -31760}, + {-8481, -31652}, {-8895, -31539}, {-9306, -31419}, {-9716, -31294}, {-10126, -31165}, {-10532, -31030}, {-10937, -30889}, {-11340, -30743}, {-11741, -30592}, {-12141, -30436}, + {-12540, -30274}, {-12935, -30107}, {-13328, -29936}, {-13718, -29758}, {-14107, -29577}, {-14493, -29390}, {-14875, -29197}, {-15257, -29000}, {-15635, -28797}, {-16010, -28590}, + {-16384, -28379}, {-16753, -28162}, {-17119, -27940}, {-17484, -27714}, {-17845, -27482}, {-18205, -27246}, {-18560, -27006}, {-18911, -26760}, {-19260, -26510}, {-19606, -26257}, + {-19947, -25997}, {-20286, -25734}, {-20621, -25466}, {-20952, -25194}, {-21281, -24918}, {-21605, -24637}, {-21926, -24353}, {-22242, -24063}, {-22555, -23770}, {-22865, -23473}, + {-23171, -23171}, {-23472, -22866}, {-23769, -22557}, {-24063, -22244}, {-24352, -21927}, {-24636, -21606}, {-24917, -21282}, {-25194, -20954}, {-25465, -20622}, {-25733, -20288}, + {-25997, -19949}, {-26255, -19607}, {-26509, -19261}, {-26760, -18914}, {-27004, -18561}, {-27246, -18205}, {-27481, -17846}, {-27713, -17485}, {-27940, -17122}, {-28162, -16755}, + {-28378, -16385}, {-28590, -16012}, {-28797, -15636}, {-28999, -15258}, {-29197, -14878}, {-29389, -14494}, {-29576, -14108}, {-29757, -13720}, {-29934, -13329}, {-30107, -12937}, + {-30274, -12540}, {-30435, -12142}, {-30592, -11744}, {-30743, -11342}, {-30889, -10939}, {-31030, -10534}, {-31164, -10127}, {-31294, -9718}, {-31418, -9307}, {-31537, -8895}, + {-31652, -8482}, {-31759, -8067}, {-31862, -7650}, {-31960, -7233}, {-32051, -6815}, {-32138, -6393}, {-32219, -5973}, {-32294, -5549}, {-32364, -5127}, {-32429, -4703}, + {-32487, -4278}, {-32541, -3852}, {-32588, -3426}, {-32630, -2999}, {-32667, -2572}, {-32698, -2144}, {-32724, -1716}, {-32742, -1287}, {-32757, -860}, {-32766, -430}, + {-32767, 0}, {-32766, 429}, {-32757, 858}, {-32743, 1287}, {-32724, 1715}, {-32698, 2143}, {-32667, 2570}, {-32631, 2998}, {-32588, 3425}, {-32541, 3851}, + {-32488, 4277}, {-32429, 4701}, {-32364, 5125}, {-32295, 5548}, {-32219, 5971}, {-32138, 6393}, {-32051, 6813}, {-31960, 7231}, {-31863, 7650}, {-31760, 8067}, + {-31652, 8481}, {-31539, 8895}, {-31419, 9306}, {-31294, 9716}, {-31165, 10126}, {-31030, 10532}, {-30889, 10937}, {-30743, 11340}, {-30592, 11741}, {-30436, 12141}, + {-30274, 12540}, {-30107, 12935}, {-29936, 13328}, {-29758, 13718}, {-29577, 14107}, {-29390, 14493}, {-29197, 14875}, {-29000, 15257}, {-28797, 15635}, {-28590, 16010}, + {-28379, 16384}, {-28162, 16753}, {-27940, 17119}, {-27714, 17484}, {-27482, 17845}, {-27246, 18205}, {-27006, 18560}, {-26760, 18911}, {-26510, 19260}, {-26257, 19606}, + {-25997, 19947}, {-25734, 20286}, {-25466, 20621}, {-25194, 20952}, {-24918, 21281}, {-24637, 21605}, {-24353, 21926}, {-24063, 22242}, {-23770, 22555}, {-23473, 22865}, + {-23171, 23171}, {-22866, 23472}, {-22557, 23769}, {-22244, 24063}, {-21927, 24352}, {-21606, 24636}, {-21282, 24917}, {-20954, 25194}, {-20622, 25465}, {-20288, 25733}, + {-19949, 25997}, {-19607, 26255}, {-19261, 26509}, {-18914, 26760}, {-18561, 27004}, {-18205, 27246}, {-17846, 27481}, {-17485, 27713}, {-17122, 27940}, {-16755, 28162}, + {-16385, 28378}, {-16012, 28590}, {-15636, 28797}, {-15258, 28999}, {-14878, 29197}, {-14494, 29389}, {-14108, 29576}, {-13720, 29757}, {-13329, 29934}, {-12937, 30107}, + {-12540, 30274}, {-12142, 30435}, {-11744, 30592}, {-11342, 30743}, {-10939, 30889}, {-10534, 31030}, {-10127, 31164}, {-9718, 31294}, {-9307, 31418}, {-8895, 31537}, + {-8482, 31652}, {-8067, 31759}, {-7650, 31862}, {-7233, 31960}, {-6815, 32051}, {-6393, 32138}, {-5973, 32219}, {-5549, 32294}, {-5127, 32364}, {-4703, 32429}, + {-4278, 32487}, {-3852, 32541}, {-3426, 32588}, {-2999, 32630}, {-2572, 32667}, {-2144, 32698}, {-1716, 32724}, {-1287, 32742}, {-860, 32757}, {-430, 32766}, + {0, 32767}, {429, 32766}, {858, 32757}, {1287, 32743}, {1715, 32724}, {2143, 32698}, {2570, 32667}, {2998, 32631}, {3425, 32588}, {3851, 32541}, + {4277, 32488}, {4701, 32429}, {5125, 32364}, {5548, 32295}, {5971, 32219}, {6393, 32138}, {6813, 32051}, {7231, 31960}, {7650, 31863}, {8067, 31760}, + {8481, 31652}, {8895, 31539}, {9306, 31419}, {9716, 31294}, {10126, 31165}, {10532, 31030}, {10937, 30889}, {11340, 30743}, {11741, 30592}, {12141, 30436}, + {12540, 30274}, {12935, 30107}, {13328, 29936}, {13718, 29758}, {14107, 29577}, {14493, 29390}, {14875, 29197}, {15257, 29000}, {15635, 28797}, {16010, 28590}, + {16384, 28379}, {16753, 28162}, {17119, 27940}, {17484, 27714}, {17845, 27482}, {18205, 27246}, {18560, 27006}, {18911, 26760}, {19260, 26510}, {19606, 26257}, + {19947, 25997}, {20286, 25734}, {20621, 25466}, {20952, 25194}, {21281, 24918}, {21605, 24637}, {21926, 24353}, {22242, 24063}, {22555, 23770}, {22865, 23473}, + {23171, 23171}, {23472, 22866}, {23769, 22557}, {24063, 22244}, {24352, 21927}, {24636, 21606}, {24917, 21282}, {25194, 20954}, {25465, 20622}, {25733, 20288}, + {25997, 19949}, {26255, 19607}, {26509, 19261}, {26760, 18914}, {27004, 18561}, {27246, 18205}, {27481, 17846}, {27713, 17485}, {27940, 17122}, {28162, 16755}, + {28378, 16385}, {28590, 16012}, {28797, 15636}, {28999, 15258}, {29197, 14878}, {29389, 14494}, {29576, 14108}, {29757, 13720}, {29934, 13329}, {30107, 12937}, + {30274, 12540}, {30435, 12142}, {30592, 11744}, {30743, 11342}, {30889, 10939}, {31030, 10534}, {31164, 10127}, {31294, 9718}, {31418, 9307}, {31537, 8895}, + {31652, 8482}, {31759, 8067}, {31862, 7650}, {31960, 7233}, {32051, 6815}, {32138, 6393}, {32219, 5973}, {32294, 5549}, {32364, 5127}, {32429, 4703}, + {32487, 4278}, {32541, 3852}, {32588, 3426}, {32630, 2999}, {32667, 2572}, {32698, 2144}, {32724, 1716}, {32742, 1287}, {32757, 860}, {32766, 430}, +}; + +static const int16_t fft_bitrev480[480] = { + 0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, 8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, 16, 112, 208, 304, 400, 48, 144, 240, 336, 432, + 80, 176, 272, 368, 464, 24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, 4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, 12, 108, 204, 300, 396, + 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, 20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, 28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, + 1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, 9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, 17, 113, 209, 305, 401, 49, 145, 241, 337, 433, + 81, 177, 273, 369, 465, 25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, 5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, 13, 109, 205, 301, 397, + 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, 21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, 29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, + 2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, 10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, 18, 114, 210, 306, 402, 50, 146, 242, 338, 434, + 82, 178, 274, 370, 466, 26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, 6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, 14, 110, 206, 302, 398, + 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, 22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, 30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, + 3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, 11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, 19, 115, 211, 307, 403, 51, 147, 243, 339, 435, + 83, 179, 275, 371, 467, 27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, 7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, 15, 111, 207, 303, 399, + 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, 23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, 31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; + +static const int16_t fft_bitrev240[240] = { + 0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, 4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, 8, 56, 104, 152, 200, 24, 72, 120, 168, 216, + 40, 88, 136, 184, 232, 12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, 1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, 5, 53, 101, 149, 197, + 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, 9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, 13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, + 2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, 6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, 10, 58, 106, 154, 202, 26, 74, 122, 170, 218, + 42, 90, 138, 186, 234, 14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, 3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, 7, 55, 103, 151, 199, + 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, 11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, 15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; + +static const int16_t fft_bitrev120[120] = { + 0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, 4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, 1, 25, 49, 73, 97, 9, 33, 57, 81, 105, + 17, 41, 65, 89, 113, 5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, 2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, 6, 30, 54, 78, 102, + 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, 3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, 7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; + +static const int16_t fft_bitrev60[60] = { + 0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, 1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, + 2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, 3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; + +static const uint8_t LOG2_FRAC_TABLE[24] = {0, 8, 13, 16, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37}; + +/* Mean energy in each band quantized in Q4 */ +static const signed char eMeans[25] = {103, 100, 92, 85, 81, 77, 72, 70, 78, 75, 73, 71, 78, 74, 69, 72, 70, 74, 76, 71, 60, 60, 60, 60, 60}; + +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +static const int16_t pred_coef[4] = {29440, 26112, 21248, 16384}; +static const int16_t beta_coef[4] = {30147, 22282, 12124, 6554}; +static const int16_t beta_intra = 4915; + +/*Parameters of the Laplace-like probability models used for the coarse energy. There is one pair of parameters for + each frame size, prediction type (inter/intra), and band number. The first number of each pair is the probability + of 0, and the second is the decay rate, both in Q8 precision.*/ +static const uint8_t e_prob_model[4][2][42] = { + /*120 sample frames.*/ + {/*Inter*/ + {72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11}, + /*Intra*/ + {24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50}}, + /*240 sample frames.*/ + {/*Inter*/ + {83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9}, + /*Intra*/ + {23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45}}, + /*480 sample frames.*/ + {/*Inter*/ + {61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10}, + /*Intra*/ + {21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42}}, + /*960 sample frames.*/ + {/*Inter*/ + {42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15}, + /*Intra*/ + {22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40}}}; + +static const uint8_t small_energy_icdf[3] = {2, 1, 0}; + +/* TF change table. Positive values mean better frequency resolution (longer effective window), whereas negative values mean better time resolution (shorter effective window). + The second index is computed as: 4*isTransient + 2*tf_select + per_band_flag */ +static const int8_t tf_select_table[4][8] = { + /*isTransient=0 isTransient=1 */ + {0, -1, 0, -1, 0, -1, 0, -1}, /* 2.5 ms */ + {0, -1, 0, -2, 1, 0, 1, -1}, /* 5 ms */ + {0, -2, 0, -3, 2, 0, 1, -1}, /* 10 ms */ + {0, -2, 0, -3, 3, 0, 1, -1}, /* 20 ms */ +}; + +/* Indexing table for converting from natural Hadamard to ordery Hadamarangedec-> This is essentially a bit-reversed Gray, + on top of which we've added an inversion of the order because we want the DC at the end rather than the beginning. + The lines are for N=2, 4, 8, 16 */ +static const int32_t ordery_table[30] = { + 1, 0, 3, 0, 2, 1, 7, 0, 4, 3, 6, 1, 5, 2, 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static const int32_t second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; + +static const uint8_t trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const uint8_t spread_icdf[4] = {25, 23, 2, 0}; + +static const uint8_t tapset_icdf[3] = {2, 1, 0}; + +static const uint32_t row_idx[15] = {0, 176, 351, 525, 698, 870, 1041, 1131, 1178, 1207, 1226, 1240, 1248, 1254, 1257}; diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.cpp b/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.cpp new file mode 100644 index 0000000..9acf804 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.cpp @@ -0,0 +1,1465 @@ +/* + * opus_decoder.cpp + * based on Xiph.Org Foundation celt decoder + * + * Created on: 26.01.2023 + * Updated on: 14.02.2026 + */ +//---------------------------------------------------------------------------------------------------------------------- +// O G G / O P U S I M P L. +//---------------------------------------------------------------------------------------------------------------------- +#include "opus_decoder.h" +#include "Arduino.h" + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool OpusDecoder::init() { + + if (!rangedec) { + OPUS_LOG_ERROR("RangeDecoder is null"); + return false; + } + // } + + if (!silkdec) { + OPUS_LOG_ERROR("Failed to allocate SilkDecoder"); + return false; + } + silkdec->init(); + + if (!celtdec) { + OPUS_LOG_ERROR("Failed to allocate CeltkDecoder"); + return false; + } + celtdec->init(); + + if (!m_opusSegmentTable.alloc_array(256)) return false; + ; + celtdec->clear(); + + m_out16.alloc_array(4608 * 2, "m_out16"); + if(!m_out16.valid()) return false; + + clear(); + // allocate CELT buffers after OPUS head (nr of channels is needed) + m_opusError = celtdec->celt_decoder_init(2); + if (m_opusError < 0) { return false; /*ERR_OPUS_CELT_NOT_INIT;*/ } + m_opusError = celtdec->celt_decoder_ctl(CELT_SET_SIGNALLING_REQUEST, 0); + if (m_opusError < 0) { return false; /*ERR_OPUS_CELT_NOT_INIT;*/ } + m_opusError = celtdec->celt_decoder_ctl(CELT_SET_END_BAND_REQUEST, 21); + if (m_opusError < 0) { return false; /*ERR_OPUS_CELT_NOT_INIT;*/ } + OPUSsetDefaults(); + + int32_t ret = 0, silkDecSizeBytes = 0; + (void)ret; + (void)silkDecSizeBytes; + silkdec->silk_InitDecoder(); + m_isValid = true; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void OpusDecoder::reset() { + rangedec.reset(); + silkdec.reset(); + celtdec.reset(); + m_opusSegmentTable.reset(); + m_frameCount = 0; + m_opusSegmentLength = 0; + m_opusValidSamples = 0; + m_opusSegmentTableSize = 0; + m_opusOggHeaderSize = 0; + m_opusSegmentTableRdPtr = -1; + m_opusCountCode = 0; + m_isValid = false; + m_out16.reset(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void OpusDecoder::clear() { + m_opusSegmentTable.clear(); + m_frameCount = 0; + m_opusSegmentLength = 0; + m_opusValidSamples = 0; + m_opusSegmentTableSize = 0; + m_opusOggHeaderSize = 0; + m_opusSegmentTableRdPtr = -1; + m_opusCountCode = 0; + m_opusCurrentFilePos = 0; + m_comment.reset(); + m_out16.clear(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool OpusDecoder::isValid() { + return m_isValid; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void OpusDecoder::OPUSsetDefaults() { + m_ofp2.reset(); + m_ofp3.reset(); + m_odp3.reset(); + m_ofp3.firstCall = true; + m_f_opusParseOgg = false; + m_f_newSteamTitle = false; // streamTitle + m_f_opusNewMetadataBlockPicture = false; + m_f_opusStereoFlag = false; + m_f_lastPage = false; + m_opusChannels = 0; + m_frameCount = 0; + m_mode = 0; + m_opusSamplerate = 0; + m_internalSampleRate = 0; + m_bandWidth = 0; + m_opusSegmentLength = 0; + m_opusValidSamples = 0; + m_opusSegmentTableSize = 0; + m_opusOggHeaderSize = 0; + m_opusSegmentTableRdPtr = -1; + m_opusCountCode = 0; + m_opusBlockPicPos = 0; + m_opusCurrentFilePos = 0; + m_opusAudioDataStart = 0; + m_opusBlockPicLen = 0; + m_opusCommentBlockSize = 0; + m_opusRemainBlockPicLen = 0; + m_blockPicLenUntilFrameEnd = 0; + m_opusBlockLen = 0; + m_opusPageNr = 0; + m_opusError = 0; + m_endband = 0; + m_prev_mode = MODE_NONE; + m_opusBlockPicItem.clear(); + m_opusBlockPicItem.shrink_to_fit(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + int32_t ret = OPUS_NONE; + int32_t segmLen = 0; + int32_t bytesLeft_begin = *bytesLeft; + int32_t bytes_consumed = 0; + + if (m_f_lastPage && m_opusSegmentTableSize == 0) { + if (OPUS_specialIndexOf(inbuf, "OggS", 5) == 0) { // next round + m_opusPageNr = 0; + } else { + return OPUS_END; + } + } + + if (m_frameCount > 0) { // decode audio, next part + ret = opusDecodePage3(inbuf, bytesLeft, segmLen, m_out16.get()); + goto exit; + } + + if (!m_opusSegmentTableSize) { + m_f_opusParseOgg = false; + m_opusCountCode = 0; + ret = parseOGG(inbuf, bytesLeft); + bytes_consumed = bytesLeft_begin - (*bytesLeft); + if (ret != OPUS_NONE) goto exit; // error + inbuf += m_opusOggHeaderSize; // no return, fall through + } + + if (m_opusSegmentTableSize > 0) { + m_opusSegmentTableRdPtr++; + m_opusSegmentTableSize--; + segmLen = m_opusSegmentTable[m_opusSegmentTableRdPtr]; + } + + if (m_opusPageNr == 0) { // OpusHead + ret = opusDecodePage0(inbuf, bytesLeft, segmLen); + m_comment.reset(); + goto exit; + } + + else if (m_opusPageNr == 1) { // OpusComment Subsequent Pages + ret = parseOpusComment(inbuf, segmLen, m_opusCurrentFilePos + bytes_consumed); + + if (ret == OPUS_COMMENT_INVALID) { + OPUS_LOG_ERROR("Error in Opus comment page"); + return OPUS_ERR; + } else if (ret == OPUS_COMMENT_NEED_MORE) { // more comment pages follows + *bytesLeft -= segmLen; + ret = OPUS_PARSE_OGG_DONE; + } else { // OPUS_COMMENT_DONE + *bytesLeft -= segmLen; + m_opusPageNr = 3; // all comments are consumed + ret = OPUS_PARSE_OGG_DONE; + } + goto exit; + } + + else if (m_opusPageNr == 3) { + ret = opusDecodePage3(inbuf, bytesLeft, segmLen, m_out16.get()); // decode audio + goto exit; + } + + else { + } + +exit: + if (m_opusSegmentTableSize == 0) { + m_opusSegmentTableRdPtr = -1; // back to the parking position + } + + if (ret >= 0) { m_opusCurrentFilePos += bytesLeft_begin - (*bytesLeft); } + + if(ret == 0){ + + if (m_opusChannels == 1) { + for (int i = 0; i < m_opusValidSamples; i++) { + outbuf[i * 2] = m_out16[i] << 16; + outbuf[i * 2 + 1] = m_out16[i] << 16; + } + } + + if (m_opusChannels == 2) { + for (int i = 0; i < m_opusValidSamples * 2; i++) { outbuf[i] = m_out16[i] << 16; } + } + + } + + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::opusDecodePage0(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength) { + int32_t ret = 0; + ret = parseOpusHead(inbuf, segmentLength); + *bytesLeft -= segmentLength; + // m_opusCurrentFilePos += segmentLength; + if (ret == 1) { m_opusPageNr++; } + if (ret == 0) { + OPUS_LOG_ERROR("Opus head not found"); + return OPUS_ERR; + } + if (ret < 0) return ret; + return OPUS_PARSE_OGG_DONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::opusDecodePage3(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, int16_t* outbuf) { + + if (m_opusAudioDataStart == 0) { m_opusAudioDataStart = m_opusCurrentFilePos; } + m_endband = 21; + + int32_t ret = 0; + + if (m_frameCount > 0) goto FramePacking; // more than one frame in the packet + + m_odp3.configNr = parseOpusTOC(inbuf[0]); + if (m_odp3.configNr < 0) { + OPUS_LOG_ERROR("wrong config number: {}", m_odp3.configNr); + return OPUS_ERR; + } // SILK or Hybrid mode + + switch (m_odp3.configNr) { + case 0 ... 3: + m_endband = 0; // OPUS_BANDWIDTH_SILK_NARROWBAND + m_mode = MODE_SILK_ONLY; + m_bandWidth = OPUS_BANDWIDTH_NARROWBAND; + m_internalSampleRate = 8000; + break; + case 4 ... 7: + m_endband = 0; // OPUS_BANDWIDTH_SILK_MEDIUMBAND + m_mode = MODE_SILK_ONLY; + m_bandWidth = OPUS_BANDWIDTH_MEDIUMBAND; + m_internalSampleRate = 12000; + break; + case 8 ... 11: + m_endband = 0; // OPUS_BANDWIDTH_SILK_WIDEBAND + m_mode = MODE_SILK_ONLY; + m_bandWidth = OPUS_BANDWIDTH_WIDEBAND; + m_internalSampleRate = 16000; + break; + case 12 ... 13: + m_endband = 0; // OPUS_BANDWIDTH_HYBRID_SUPERWIDEBAND + m_mode = MODE_HYBRID; + m_bandWidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + break; + case 14 ... 15: + m_endband = 0; // OPUS_BANDWIDTH_HYBRID_FULLBAND + m_mode = MODE_HYBRID; + m_bandWidth = OPUS_BANDWIDTH_FULLBAND; + break; + case 16 ... 19: + m_endband = 13; // OPUS_BANDWIDTH_CELT_NARROWBAND + m_mode = MODE_CELT_ONLY; + m_bandWidth = OPUS_BANDWIDTH_NARROWBAND; + break; + case 20 ... 23: + m_endband = 17; // OPUS_BANDWIDTH_CELT_WIDEBAND + m_mode = MODE_CELT_ONLY; + m_bandWidth = OPUS_BANDWIDTH_WIDEBAND; + break; + case 24 ... 27: + m_endband = 19; // OPUS_BANDWIDTH_CELT_SUPERWIDEBAND + m_mode = MODE_CELT_ONLY; + m_bandWidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + break; + case 28 ... 31: + m_endband = 21; // OPUS_BANDWIDTH_CELT_FULLBAND + m_mode = MODE_CELT_ONLY; + m_bandWidth = OPUS_BANDWIDTH_FULLBAND; + break; + default: + OPUS_LOG_WARN("unknown bandwifth {}, m_odp3.configNr", m_odp3.configNr); + m_endband = 21; // assume OPUS_BANDWIDTH_FULLBAND + break; + } + + // celt_decoder_ctl(CELT_SET_START_BAND_REQUEST, m_endband); + if (m_mode == MODE_CELT_ONLY) { + celtdec->celt_decoder_ctl(CELT_SET_END_BAND_REQUEST, m_endband); + } else if (m_mode == MODE_SILK_ONLY) { + // silk_InitDecoder(); + } + + m_odp3.samplesPerFrame = opus_packet_get_samples_per_frame(inbuf, /*s_opusSamplerate*/ 48000); + +FramePacking: // https://www.tech-invite.com/y65/tinv-ietf-rfc-6716-2.html 3.2. Frame Packing + // OPUS_LOG_INFO("s_opusCountCode {}, configNr {}", m_opusCountCode, configNr); + + switch (m_opusCountCode) { + case 0: // Code 0: One Frame in the Packet + ret = opus_FramePacking_Code0(inbuf, bytesLeft, outbuf, segmentLength, m_odp3.samplesPerFrame); + break; + case 1: // Code 1: Two Frames in the Packet, Each with Equal Compressed Size + ret = opus_FramePacking_Code1(inbuf, bytesLeft, outbuf, segmentLength, m_odp3.samplesPerFrame, &m_frameCount); + break; + case 2: // Code 2: Two Frames in the Packet, with Different Compressed Sizes + ret = opus_FramePacking_Code2(inbuf, bytesLeft, outbuf, segmentLength, m_odp3.samplesPerFrame, &m_frameCount); + break; + case 3: // Code 3: A Signaled Number of Frames in the Packet + ret = opus_FramePacking_Code3(inbuf, bytesLeft, outbuf, segmentLength, m_odp3.samplesPerFrame, &m_frameCount); + break; + default: + OPUS_LOG_ERROR("Opus unknown count code {}", m_opusCountCode); + return OPUS_ERR; + break; + } + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::opus_decode_frame(uint8_t* inbuf, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame) { + if (!packetLen) { + OPUS_LOG_WARN("Opus packetLen is 0"); + return 0; + } + int i, silk_ret = 0, celt_ret = 0; + uint16_t audiosize = 960; + uint8_t payloadSize_ms = max(10, 1000 * samplesPerFrame / 48000); /* The SILK PLC cannot produce frames of less than 10 ms */ + int decoded_samples = 0; + int32_t silk_frame_size; + uint8_t start_band = 17; + uint8_t end_band = 21; + + silkdec->setChannelsAPI(m_opusChannels); + silkdec->setChannelsInternal(m_opusChannels); + silkdec->setAPIsampleRate(48000); + + if (m_bandWidth == OPUS_BANDWIDTH_NARROWBAND) { + m_internalSampleRate = 8000; + } else if (m_bandWidth == OPUS_BANDWIDTH_MEDIUMBAND) { + m_internalSampleRate = 12000; + } else if (m_bandWidth == OPUS_BANDWIDTH_WIDEBAND) { + m_internalSampleRate = 16000; + } else { + m_internalSampleRate = 16000; + } + + if (m_prev_mode == MODE_NONE) celtdec->celt_decoder_ctl((int32_t)OPUS_RESET_STATE); + + if (m_mode == MODE_CELT_ONLY) { + if (m_prev_mode != m_mode) { + celtdec->celt_decoder_ctl((int32_t)OPUS_RESET_STATE); + rangedec->dec_init((uint8_t*)inbuf, packetLen); + celtdec->celt_decoder_ctl((int32_t)CELT_SET_START_BAND_REQUEST, 0); + } + m_prev_mode = m_mode; + rangedec->dec_init((uint8_t*)inbuf, packetLen); + celtdec->celt_decoder_ctl(CELT_SET_END_BAND_REQUEST, m_endband); + return celtdec->celt_decode_with_ec((int16_t*)outbuf, samplesPerFrame); + } + + if (m_mode == MODE_SILK_ONLY) { + if (m_prev_mode == MODE_CELT_ONLY) silkdec->silk_InitDecoder(); + decoded_samples = 0; + rangedec->dec_init((uint8_t*)inbuf, samplesPerFrame); + silkdec->silk_setRawParams(m_opusChannels, 2, payloadSize_ms, m_internalSampleRate, 48000); + do { /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + int silk_ret = silkdec->silk_Decode(0, first_frame, (int16_t*)outbuf + decoded_samples, &silk_frame_size); + if (silk_ret < 0) return silk_ret; + decoded_samples += silk_frame_size; + } while (decoded_samples < samplesPerFrame); + + return decoded_samples; + } + + if (m_mode == MODE_HYBRID) { + rangedec->dec_init((uint8_t*)inbuf, packetLen); + int pcm_silk_size = samplesPerFrame * 4; + ps_ptr pcm_silk; + pcm_silk.alloc_array(pcm_silk_size); + int16_t* pcm_ptr; + pcm_ptr = pcm_silk.get(); + if (m_prev_mode == MODE_CELT_ONLY || m_prev_mode == MODE_NONE) silkdec->silk_InitDecoder(); + decoded_samples = 0; + silkdec->silk_setRawParams(m_opusChannels, 2, payloadSize_ms, m_internalSampleRate, 48000); + do { /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + int32_t nSamplesOut; + silk_ret = silkdec->silk_Decode(0, first_frame, pcm_ptr, &nSamplesOut); + if (silk_ret < 0) return silk_ret; + pcm_ptr += nSamplesOut * m_opusChannels; + decoded_samples += nSamplesOut; + } while (decoded_samples < audiosize); + + if (rangedec->tell() + 17 + 20 <= 8 * packetLen) { + /* Check if we have a redundant 0-8 kHz band */ + rangedec->dec_bit_logp(12); + } + if (m_bandWidth) { + switch (m_bandWidth) { + case OPUS_BANDWIDTH_NARROWBAND: end_band = 13; break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: end_band = 17; break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: end_band = 19; break; + case OPUS_BANDWIDTH_FULLBAND: end_band = 21; break; + default: break; + } + celtdec->celt_decoder_ctl((int32_t)CELT_SET_END_BAND_REQUEST, (end_band)); + celtdec->celt_decoder_ctl((int32_t)CELT_SET_CHANNELS_REQUEST, (m_opusChannels)); + } + + /* MUST be after PLC */ + celtdec->celt_decoder_ctl((int32_t)CELT_SET_START_BAND_REQUEST, start_band); + + /* Make sure to discard any previous CELT state */ + if (m_mode != m_prev_mode && m_prev_mode > 0) celtdec->celt_decoder_ctl((int32_t)OPUS_RESET_STATE); + celt_ret = celtdec->celt_decode_with_ec(outbuf, audiosize); + + for (i = 0; i < audiosize * m_opusChannels; i++) outbuf[i] = celtdec->SAT16(ADD32(outbuf[i], pcm_silk[i])); + + m_prev_mode = MODE_HYBRID; + return celt_ret < 0 ? celt_ret : audiosize; + } + m_prev_mode = MODE_NONE; + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t OpusDecoder::opus_FramePacking_Code0(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame) { + + /* Code 0: One Frame in the Packet + + For code 0 packets, the TOC byte is immediately followed by N-1 bytes + of compressed data for a single frame (where N is the size of the + packet), as illustrated + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | config |s|0|0| | + +-+-+-+-+-+-+-+-+ | + | Compressed frame 1 (N-1 bytes)... : + : | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + int32_t ret = 0; + *bytesLeft -= packetLen; + // m_opusCurrentFilePos += packetLen; + packetLen--; + inbuf++; + ret = opus_decode_frame(inbuf, outbuf, packetLen, samplesPerFrame); + + if (ret < 0) { + return ret; // decode err + } + m_opusValidSamples = ret; + return OPUS_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t OpusDecoder::opus_FramePacking_Code1(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount) { + + /* Code 1: Two Frames in the Packet, Each with Equal Compressed Size + + For code 1 packets, the TOC byte is immediately followed by the (N-1)/2 bytes [where N is the size of the packet] of compressed + data for the first frame, followed by (N-1)/2 bytes of compressed data for the second frame, as illustrated. The number of payload bytes + available for compressed data, N-1, MUST be even for all code 1 packets. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | config |s|0|1| | + +-+-+-+-+-+-+-+-+ : + | Compressed frame 1 ((N-1)/2 bytes)... | + : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : + | Compressed frame 2 ((N-1)/2 bytes)... | + : +-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + int32_t ret = 0; + if (*frameCount == 0) { + packetLen--; + inbuf++; + *bytesLeft -= 1; + // m_opusCurrentFilePos += 1; + m_ofp3.c1fs = packetLen / 2; + // OPUS_LOG_WARN("OPUS countCode 1 len {}, c1fs {}", len, c1fs); + *frameCount = 2; + } + if (*frameCount > 0) { + ret = opus_decode_frame(inbuf, outbuf, m_ofp3.c1fs, samplesPerFrame); + // OPUS_LOG_WARN("code 1, ret {}", ret); + if (ret < 0) { + *frameCount = 0; + return ret; // decode err + } + m_opusValidSamples = ret; + *bytesLeft -= m_ofp3.c1fs; + // m_opusCurrentFilePos += m_ofp3.c1fs; + } + *frameCount -= 1; + return OPUS_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t OpusDecoder::opus_FramePacking_Code2(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount) { + + /* Code 2: Two Frames in the Packet, with Different Compressed Sizes + + For code 2 packets, the TOC byte is followed by a one- or two-byte sequence indicating the length of the first frame (marked N1 in the Figure), + followed by N1 bytes of compressed data for the first frame. The remaining N-N1-2 or N-N1-3 bytes are the compressed data for the second frame. + This is illustrated in the Figure. A code 2 packet MUST contain enough bytes to represent a valid length. For example, a 1-byte code 2 packet + is always invalid, and a 2-byte code 2 packet whose second byte is in the range 252...255 is also invalid. The length of the first frame, N1, + MUST also be no larger than the size of the payload remaining after decoding that length for all code 2 packets. This makes, for example, + a 2-byte code 2 packet with a second byte in the range 1...251 invalid as well (the only valid 2-byte code 2 packet is one where the length of + both frames is zero). + compute N1: o 1...251: Length of the frame in bytes + o 252...255: A second byte is needed. The total length is (second_byte*4)+first_byte + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | config |s|1|0| N1 (1-2 bytes): | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : + | Compressed frame 1 (N1 bytes)... | + : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + | Compressed frame 2... : + : | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + int32_t ret = 0; + + if (*frameCount == 0) { + uint8_t b1 = inbuf[1]; + uint8_t b2 = inbuf[2]; + if (b1 < 252) { + m_ofp2.firstFrameLength = b1; + packetLen -= 2; + *bytesLeft -= 2; + // m_opusCurrentFilePos += 2; + inbuf += 2; + } else { + m_ofp2.firstFrameLength = b1 + (b2 * 4); + packetLen -= 3; + *bytesLeft -= 3; + // m_opusCurrentFilePos += 3; + inbuf += 3; + } + m_ofp2.secondFrameLength = packetLen - m_ofp2.firstFrameLength; + *frameCount = 2; + } + if (*frameCount == 2) { + ret = opus_decode_frame(inbuf, outbuf, m_ofp2.firstFrameLength, samplesPerFrame); + // OPUS_LOG_WARN("code 2, ret {}", ret); + if (ret < 0) { + *frameCount = 0; + return ret; // decode err + } + m_opusValidSamples = ret; + *bytesLeft -= m_ofp2.firstFrameLength; + // m_opusCurrentFilePos += m_ofp2.firstFrameLength; + } + if (*frameCount == 1) { + ret = opus_decode_frame(inbuf, outbuf, m_ofp2.secondFrameLength, samplesPerFrame); + // OPUS_LOG_WARN("code 2, ret {}", ret); + if (ret < 0) { + *frameCount = 0; + return ret; // decode err + } + m_opusValidSamples = ret; + *bytesLeft -= m_ofp2.secondFrameLength; + // m_opusCurrentFilePos += m_ofp2.secondFrameLength; + } + *frameCount -= 1; + return OPUS_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t OpusDecoder::opus_FramePacking_Code3(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount) { + + /* Code 3: A Signaled Number of Frames in the Packet + + Code 3 packets signal the number of frames, as well as additional padding, called "Opus padding" to indicate that this padding is added + at the Opus layer rather than at the transport layer. Code 3 packets MUST have at least 2 bytes [R6,R7]. The TOC byte is followed by a + byte encoding the number of frames in the packet in bits 2 to 7 (marked "M" in the Figure ) 0 + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |v|p| M | + +-+-+-+-+-+-+-+-+ + with bit 1 indicating whether or not Opus + padding is inserted (marked "p" in Figure 5), and bit 0 indicating VBR (marked "v" in Figure). M MUST NOT be zero, and the audio + duration contained within a packet MUST NOT exceed 120 ms. This limits the maximum frame count for any frame size to 48 (for 2.5 ms + frames), with lower limits for longer frame sizes. The Figure below illustrates the layout of the frame count byte. + When Opus padding is used, the number of bytes of padding is encoded in the bytes following the frame count byte. Values from 0...254 + indicate that 0...254 bytes of padding are included, in addition to the byte(s) used to indicate the size of the padding. If the value + is 255, then the size of the additional padding is 254 bytes, plus the padding value encoded in the next byte. + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Padding Length 254 | 253 | 253 x 0x00 : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Padding Length 255 | 254 | 254 x 0x00 : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Padding Length 256 | 255 | 0 | 254 x 0x00 : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + There MUST be at least one more byte in the packet in this case [R6,R7]. The additional padding bytes appear at the end of the packet and MUST + be set to zero by the encoder to avoid creating a covert channel. The decoder MUST accept any value for the padding bytes, however. + Although this encoding provides multiple ways to indicate a given number of padding bytes, each uses a different number of bytes to + indicate the padding size and thus will increase the total packet size by a different amount. For example, to add 255 bytes to a + packet, set the padding bit, p, to 1, insert a single byte after the frame count byte with a value of 254, and append 254 padding bytes + with the value zero to the end of the packet. To add 256 bytes to a packet, set the padding bit to 1, insert two bytes after the frame + count byte with the values 255 and 0, respectively, and append 254 padding bytes with the value zero to the end of the packet. By using + the value 255 multiple times, it is possible to create a packet of any specific, desired size. Let P be the number of header bytes used + to indicate the padding size plus the number of padding bytes themselves (i.e., P is the total number of bytes added to the + packet). Then, P MUST be no more than N-2. In the CBR case, let R=N-2-P be the number of bytes remaining in the packet after subtracting the + (optional) padding. Then, the compressed length of each frame in bytes is equal to R/M. The value R MUST be a non-negative integer multiple + of M. The compressed data for all M frames follows, each of size R/M bytes, as illustrated in the Figure below. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | config |s|1|1|0|p| M | Padding length (Optional) : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame 1 (R/M bytes)... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame 2 (R/M bytes)... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : ... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame M (R/M bytes)... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + : Opus Padding (Optional)... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + In the VBR case, the (optional) padding length is followed by M-1 frame lengths (indicated by "N1" to "N[M-1]" in Figure 7), each encoded in a + one- or two-byte sequence as described above. The packet MUST contain enough data for the M-1 lengths after removing the (optional) padding, + and the sum of these lengths MUST be no larger than the number of bytes remaining in the packet after decoding them. The compressed data for + all M frames follows, each frame consisting of the indicated number of bytes, with the final frame consuming any remaining bytes before the final + padding, as illustrated in the Figure below. The number of header bytes (TOC byte, frame count byte, padding length bytes, and frame length bytes), + plus the signaled length of the first M-1 frames themselves, plus the signaled length of the padding MUST be no larger than N, the total + size of the packet. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | config |s|1|1|1|p| M | Padding length (Optional) : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + : N1 (1-2 bytes): N2 (1-2 bytes): ... : N[M-1] | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame 1 (N1 bytes)... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame 2 (N2 bytes)... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : ... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Compressed frame M... : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + : Opus Padding (Optional)... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + */ + int32_t ret = 0; + int32_t current_payload_offset = 0; // Offset from inbuf start where the current frame data begins + m_ofp3.idx = 0; + + if (m_ofp3.firstCall) { + // OPUS_LOG_WARN("0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} 0x{:02X} ", + // inbuf[0], inbuf[1], inbuf[2], inbuf[3], inbuf[4], inbuf[5], inbuf[6], inbuf[7], inbuf[8], inbuf[9]); + + // Reset all relevant state for a new packet + m_ofp3.firstCall = false; + m_ofp3.paddingLength = 0; + m_ofp3.v = false; + m_ofp3.p = false; + m_ofp3.M = 0; + m_ofp3.fs = 0; + // Ensure vfs is cleared or handled appropriately if it's a static member + // memset(m_ofp3.vfs, 0, sizeof(m_ofp3.vfs)); // Only if m_ofp3.vfs is part of m_ofp3 + + // m_opusCurrentFilePos += packetLen; + m_ofp3.idx = 1; // Start reading after TOC byte (inbuf[0]) + m_ofp3.spf = samplesPerFrame; + + // Parse Frame Count Byte (inbuf[1]) + if (m_ofp3.idx >= packetLen) { // Check bounds before accessing + *bytesLeft -= packetLen; // Consume this potentially malformed packet + *frameCount = 0; + m_ofp3.firstCall = true; + return OPUS_NONE; // Packet too short + } + if (inbuf[m_ofp3.idx] & 0b10000000) m_ofp3.v = true; // VBR indicator + if (inbuf[m_ofp3.idx] & 0b01000000) m_ofp3.p = true; // padding bit + m_ofp3.M = inbuf[m_ofp3.idx] & 0b00111111; // framecount + *frameCount = m_ofp3.M; // Set the output frameCount for this packet + m_ofp3.idx++; // Move past the frame count byte + + // M MUST NOT be zero (from spec) + if (m_ofp3.M == 0) { + // OPUS_LOG_INFO("Error: Opus Code 3 packet with M = 0 (no frames)"); + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Opus code 3; packet with no frames"); + return OPUS_ERR; + } + + // Parse Padding Length + if (m_ofp3.p) { + uint32_t current_padding_chunk_val; + do { + if (m_ofp3.idx >= packetLen) { // Check bounds + // OPUS_LOG_INFO("Error: Packet truncated during padding length parsing"); + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Opus packet is truncated during padding length parsing"); + return OPUS_ERR; + } + current_padding_chunk_val = inbuf[m_ofp3.idx]; + m_ofp3.idx++; + m_ofp3.paddingLength += current_padding_chunk_val; + } while (current_padding_chunk_val == 255); // Continue if the last byte read was 255 + // OPUS_LOG_WARN("we have {} padding bytes", m_ofp3.paddingLength); + } + + // Parse Variable Frame Sizes (N1 to N[M-1] for VBR) + if (m_ofp3.v && m_ofp3.M > 1) { // Only M-1 lengths are signaled if M > 1 + for (int m = 0; m < (m_ofp3.M - 1); m++) { + if (m_ofp3.idx >= packetLen) { // Check bounds + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Opus packet has been truncated at VBR parsing"); + return OPUS_ERR; + } + uint16_t current_frame_len_val = inbuf[m_ofp3.idx]; + m_ofp3.idx++; + if (current_frame_len_val == 255) { + if (m_ofp3.idx >= packetLen) { // Check bounds for second byte + // OPUS_LOG_INFO("Error: Packet truncated during VBR frame length parsing (second byte)"); + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Opus packet has been truncated at VBR parsing"); + return OPUS_ERR; + } + current_frame_len_val += inbuf[m_ofp3.idx]; // Add the next byte's value + m_ofp3.idx++; + } + m_ofp3.vfs[m] = current_frame_len_val; + // OPUS_LOG_INFO("VFS[{}]: {}", m, m_ofp3.vfs[m]); + } + } + + // Calculate bytes available for compressed audio frames + int32_t total_header_bytes = m_ofp3.idx; // idx now points to start of first compressed frame data + int32_t remaining_bytes_for_data_and_padding = packetLen - total_header_bytes; + + // Verify enough data for padding + if (remaining_bytes_for_data_and_padding < m_ofp3.paddingLength) { + // OPUS_LOG_INFO("Error: Padding length {} exceeds remaining packet bytes {}", m_ofp3.paddingLength, remaining_bytes_for_data_and_padding); + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Too many parsing bytes: {}, padding length; {}", remaining_bytes_for_data_and_padding, m_ofp3.paddingLength); + return OPUS_ERR; + } + + // Bytes containing actual compressed data (excluding padding at the end) + int32_t compressed_data_bytes = remaining_bytes_for_data_and_padding - m_ofp3.paddingLength; + + // OPUS_LOG_INFO("packetLen {}, total_header_bytes {}, compressed_data_bytes {}, paddingLength {}, framecount {}", + // packetLen, total_header_bytes, compressed_data_bytes, m_ofp3.paddingLength, *frameCount); + + if (!m_ofp3.v) { // Constant Bitrates (CBR) + // R = N - 2 - P + // R = packetLen (N) - (TOC + FrameCountByte) - (Padding Header Bytes + Padding Data Bytes) + // R = packetLen - m_ofp3.idx (which is total header bytes) - m_ofp3.paddingLength (which is actual padding data) + // But simplified: R = compressed_data_bytes (calculated above) + + if (m_ofp3.M == 0) { // Already checked, but good for robustness + // OPUS_LOG_INFO("Error: CBR with 0 frames (should not happen based on spec M>0)"); + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("Opus CBR wihtout frames"); + return OPUS_ERR; + } + + m_ofp3.fs = compressed_data_bytes / m_ofp3.M; + int r = compressed_data_bytes % m_ofp3.M; + if (r > 0) { + OPUS_LOG_WARN("CBR data not perfectly divisible by frame count. remainingBytes {}, frames {}, remainder {}", compressed_data_bytes, m_ofp3.M, r); + // This might indicate a malformed packet, or a small rounding difference for very short packets. + // For strict compliance, R MUST be a non-negative integer multiple of M. + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + return OPUS_NONE; + } + + // In CBR, all frames have size m_ofp3.fs. We don't use vfs here. + } else { // Variable Bitrates (VBR) + // Calculate the length of the last frame (M) + uint32_t sum_of_signaled_lengths = 0; + for (int m = 0; m < (m_ofp3.M - 1); m++) { sum_of_signaled_lengths += m_ofp3.vfs[m]; } + + if (sum_of_signaled_lengths > compressed_data_bytes) { + OPUS_LOG_ERROR("Opus wrong VBR length, sum_of_signaled_lengths: {}, compressed_data_bytes: {}", sum_of_signaled_lengths, compressed_data_bytes); + return OPUS_ERR; + *bytesLeft -= packetLen; + *frameCount = 0; + m_ofp3.firstCall = true; + return OPUS_NONE; + } + m_ofp3.vfs[m_ofp3.M - 1] = compressed_data_bytes - sum_of_signaled_lengths; + // OPUS_LOG_INFO("Calculated VFS[{}] (last frame): {}", m_ofp3.M - 1, m_ofp3.vfs[s_ofp3.M - 1]); + } + current_payload_offset = total_header_bytes; // This is where the first frame data starts + (void)current_payload_offset; + (*bytesLeft) -= total_header_bytes; // Account for all header bytes consumed + } + + // Decoding loop (outside the firstCall block) + if (*frameCount > 0) { + int32_t frame_len; + if (m_ofp3.v) { + // Get the length of the current frame to decode + uint8_t current_frame_idx = m_ofp3.M - (*frameCount); // 0 for first, M-1 for last + if (current_frame_idx >= m_ofp3.M) { // Safety check + // OPUS_LOG_INFO("Error: Invalid VFS index access. current_frame_idx {}, M {}", current_frame_idx, m_ofp3.M); + *bytesLeft -= (*bytesLeft > 0 ? *bytesLeft : 0); // Consume remaining bytes to reset + *frameCount = 0; + m_ofp3.firstCall = true; + OPUS_LOG_ERROR("opus invalid VFS index access, current_frame_idx; {}, nr of frames: {}", current_frame_idx, m_ofp3.M); + return OPUS_ERR; + } + frame_len = m_ofp3.vfs[current_frame_idx]; + } else { + frame_len = m_ofp3.fs; + } + // Check if enough bytes are left for the current frame + if (*bytesLeft < frame_len) { + OPUS_LOG_ERROR("Opus not enough bytes: {}, required: {}", *bytesLeft, frame_len); + return OPUS_ERR; + *bytesLeft -= (*bytesLeft > 0 ? *bytesLeft : 0); // Consume remaining bytes to reset + *frameCount = 0; + m_ofp3.firstCall = true; + return OPUS_NONE; + } + + // Decode the frame + // The inbuf + current_payload_offset points to the start of the current frame data + + ret = opus_decode_frame(inbuf + m_ofp3.idx, outbuf, frame_len, m_ofp3.spf); + // OPUS_LOG_INFO("code 3, fs {}, spf {}, ret {}, offs {}", frame_len, m_ofp3.spf, ret, m_ofp3.idx); + // Update bytesLeft and frameCount + *bytesLeft -= frame_len; + *frameCount -= 1; + m_opusValidSamples = ret; + + if (*frameCount > 0) { + return OPUS_CONTINUE; // More frames in this packet + } + } + + // After all frames are decoded, account for padding bytes if any remain. + // The *bytesLeft at this point should ideally be equal to m_ofp3.paddingLength + // because total_header_bytes and frame_len (for all frames) have been subtracted. + // If there's a mismatch, it indicates an issue or just consume the rest. + *bytesLeft -= m_ofp3.paddingLength; // Consume padding bytes from *bytesLeft for the packet + if (*bytesLeft < 0) { + OPUS_LOG_WARN("Warning: Negative bytesLeft after consuming padding. Remaining: {}", *bytesLeft); + *bytesLeft = 0; // Prevent negative + } + + *frameCount = 0; // All frames processed for this packet + m_opusValidSamples = samplesPerFrame; // Reset for next packet's first frame + m_ofp3.firstCall = true; // Signal for next packet + return OPUS_NONE; // Packet finished +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::opus_packet_get_samples_per_frame(const uint8_t* data, int32_t Fs) { + int32_t audiosize; + if ((data[0] & 0x80) == 0x080) { + audiosize = ((data[0] >> 3) & 0x03); + audiosize = (Fs << audiosize) / 400; + } else if ((data[0] & 0x60) == 0x60) { + audiosize = (data[0] & 0x08) ? Fs / 50 : Fs / 100; + } else { + audiosize = ((data[0] >> 3) & 0x3); + if (audiosize == 3) { + audiosize = Fs * 60 / 1000; + } else { + audiosize = (Fs << audiosize) / 100; + } + } + return audiosize; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t OpusDecoder::getChannels() { + return m_opusChannels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::getSampleRate() { + return 48000; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t OpusDecoder::getBitsPerSample() { + return 16; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::getOutputSamples() { + return m_opusValidSamples; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::getAudioDataStart() { + return m_opusAudioDataStart; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::getAudioFileDuration() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void OpusDecoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) { + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* OpusDecoder::arg2() { + return nullptr; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::val1() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::val2() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::getBitRate() { + if (m_opusCompressionRatio != 0) { + return (16 * 2 * 48000) / m_opusCompressionRatio; // bitsPerSample * channel* SampleRate/CompressionRatio + } else + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* OpusDecoder::getStreamTitle() { + if (m_f_newSteamTitle) { + m_f_newSteamTitle = false; + return m_comment.stream_title.c_get(); + } + return NULL; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* OpusDecoder::whoIsIt() { + return "OPUS"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* OpusDecoder::arg1() { // mode CELT, SILK or HYBRID + const char* p = "unknown mode"; + if (m_mode == MODE_CELT_ONLY) p = "Opus Mode: CELT_ONLY"; + if (m_mode == MODE_HYBRID) p = "Opus Mode: HYBRID"; + if (m_mode == MODE_SILK_ONLY) p = "Opus Mode: SILK_ONLY"; + if (m_mode == MODE_NONE) p = "Opus Mode: NONE"; + return p; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector OpusDecoder::getMetadataBlockPicture() { + if (m_f_opusNewMetadataBlockPicture) { + m_f_opusNewMetadataBlockPicture = false; + return m_comment.pic_vec; + } + std::vector v; + return v; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t OpusDecoder::parseOpusTOC(uint8_t TOC_Byte) { // https://www.rfc-editor.org/rfc/rfc6716 page 16 ff + + uint8_t configNr = 0; + uint8_t s = 0; // stereo flag + uint8_t c = 0; + (void)c; // count code + + configNr = (TOC_Byte & 0b11111000) >> 3; + s = (TOC_Byte & 0b00000100) >> 2; + c = (TOC_Byte & 0b00000011); + + /* Configuration Mode Bandwidth FrameSizes Audio Bandwidth Sample Rate (Effective) + + configNr 0 ... 3 SILK NB (narrow band) 10, 20, 40, 60ms 4 kHz 8 kHz + configNr 4 ... 7 SILK MB (medium band) 10, 20, 40, 60ms 6 kHz 12 kHz + configNr 8 ... 11 SILK WB (wide band) 10, 20, 40, 60ms 8 kHz 16 kHz + configNr 12 ... 13 HYBRID SWB (super wideband) 10, 20ms 12 kHz (*) 24 kHz + configNr 14 ... 15 HYBRID FB (full band) 10, 20ms 20 kHz (*) 48 kHz + configNr 16 ... 19 CELT NB (narrow band) 2.5, 5, 10, 20ms 4 kHz 8 kHz + configNr 20 ... 23 CELT WB (wide band) 2.5, 5, 10, 20ms 8 kHz 16 kHz + configNr 24 ... 27 CELT SWB (super wideband) 2.5, 5, 10, 20ms 12 kHz 24 kHz + configNr 28 ... 31 CELT FB (full band) 2.5, 5, 10, 20ms 20 kHz (*) 48 kHz <------- + + (*) Although the sampling theorem allows a bandwidth as large as half the sampling rate, Opus never codes + audio above 20 kHz, as that is the generally accepted upper limit of human hearing. + + s = 0: mono 1: stereo + + c = 0: 1 frame in the packet + c = 1: 2 frames in the packet, each with equal compressed size + c = 2: 2 frames in the packet, with different compressed sizes + c = 3: an arbitrary number of frames in the packet + */ + m_opusCountCode = c; + m_f_opusStereoFlag = s; + + // if(configNr < 12) return ERR_OPUS_SILK_MODE_UNSUPPORTED; + // if(configNr < 16) return ERR_OPUS_HYBRID_MODE_UNSUPPORTED; + // if(configNr < 20) return ERR_OPUS_NARROW_BAND_UNSUPPORTED; + // if(configNr < 24) return ERR_OPUS_WIDE_BAND_UNSUPPORTED; + // if(configNr < 28) return ERR_OPUS_SUPER_WIDE_BAND_UNSUPPORTED; + + return configNr; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::parseOpusComment(uint8_t* inbuf, int32_t nBytes, uint32_t current_file_pos) { + + /* reference https://www.rfc-editor.org/rfc/rfc7845#section-5 + returns: + OPUS_COMMENT_INVALID (-1) → "OpusTags" not found + OPUS_COMMENT_NEED_MORE (1) → needs more data (comment continues) + OPUS_COMMENT_DONE (2) → all comments consumed + */ + constexpr uint32_t MAX_COMMENT_SIZE = 1024; + int32_t available_bytes = nBytes; + + auto parse_comment = [&](ps_ptr comment) -> void { + int idx = comment.index_of("="); + if (idx <= 0) return; + ps_ptr key = comment.substr(0, idx); + ps_ptr val = comment.substr(idx + 1); + if (key.starts_with_icase("metadata_block_picture")) { + if (m_comment.item_vec.size() % 2 != 0) { OPUS_LOG_ERROR("vec.size is odd: {}", m_comment.item_vec.size()); } + m_comment.item_vec[0] += strlen("METADATA_BLOCK_PICTURE="); + for (int i = 0; i < m_comment.item_vec.size(); i += 2) { + m_comment.pic_vec.push_back(m_comment.item_vec[i]); // start pos + m_comment.pic_vec.push_back(m_comment.item_vec[i + 1] - m_comment.item_vec[i]); // len = end pos - start pos + } + m_comment.item_vec.clear(); + m_f_opusNewMetadataBlockPicture = true; + // for (int i = 0; i < m_comment.pic_vec.size(); i += 2) { OPUS_LOG_INFO("Segment {} {} - {}", i / 2, m_comment.pic_vec[i], m_comment.pic_vec[i + 1]); } + OPUS_LOG_DEBUG("Skipping embedded picture ({} bytes)", val.size()); + return; + } + if (key.starts_with_icase("artist")) { + if (!m_comment.stream_title.valid()) { + m_comment.stream_title.assign(val.c_get()); + } else { + m_comment.stream_title.append(" - "); + m_comment.stream_title.append(val.c_get()); + } + audio.info(audio, Audio::evt_id3data, "Artist: {}", val.c_get()); + } + if (key.starts_with_icase("title")) { + if (!m_comment.stream_title.valid()) { + m_comment.stream_title.assign(val.c_get()); + } else { + m_comment.stream_title.append(" - "); + m_comment.stream_title.append(val.c_get()); + } + audio.info(audio, Audio::evt_id3data, "Title: {}", val.c_get()); + } + if (key.starts_with_icase("work")) { + audio.info(audio, Audio::evt_id3data, "Work: {}", val.c_get()); + } + if (key.starts_with_icase("composer")) { + audio.info(audio, Audio::evt_id3data, "Composer: {}", val.c_get()); + } + if (key.starts_with_icase("genre")) { + audio.info(audio, Audio::evt_id3data, "Genre: {}", val.c_get()); + } + if (key.starts_with_icase("date")) { + audio.info(audio, Audio::evt_id3data, "Date: {}", val.c_get()); + } + if (key.starts_with_icase("album")) { + audio.info(audio, Audio::evt_id3data, "Album: {}", val.c_get()); + } + if (key.starts_with_icase("comment")) { + audio.info(audio, Audio::evt_id3data, "Comments: {}", val.c_get()); + } + if (key.starts_with_icase("tracknumber")) { + audio.info(audio, Audio::evt_id3data, "Track number/Position in set: {}", val.c_get()); + } + if (m_comment.stream_title.valid()) m_f_newSteamTitle = true; + // comment.println(); // optional output + m_comment.item_vec.clear(); + }; + + auto fill_content = [&](uint8_t* buff, uint32_t len) -> void { + // defensive guards (avoid signed/unsigned confusion) + const uint32_t S_MAX = MAX_COMMENT_SIZE; + uint32_t s = m_comment.comment_content.strlen(); // vorhandene länge + if (s >= S_MAX) { + // already full — nothing more to add + OPUS_LOG_DEBUG("comment_content already at or above MAX_COMMENT_SIZE ({} >= {})", s, S_MAX); + return; + } + + // clamp len to something sensible (len can come from the caller, so check) + uint32_t available_space = S_MAX - s; + uint32_t to_fill = (len <= available_space) ? len : available_space; + + OPUS_LOG_DEBUG("strlen {}, incoming len {}, to_fill {}", s, len, to_fill); + + // defensive: wenn to_fill == 0, nichts tun + if (to_fill == 0) return; + + // copy/append execute safely + const char* src = reinterpret_cast(buff); + if (s == 0) { + // initial copy + m_comment.comment_content.copy_from(src, to_fill); + } else { + // append, ensure append argument limited to to_fill + m_comment.comment_content.append(src, to_fill); + } + }; + + // 🔹 1. If the previous comment block was incomplete → continue now + if (m_comment.oob) { + int64_t tmp_to_read = (int64_t)m_comment.comment_size - (int64_t)m_comment.save_len; + if (tmp_to_read < 0) tmp_to_read = 0; + uint32_t to_read = (uint32_t)tmp_to_read; + if (available_bytes <= 0) { // clamp to available_bytes (available_bytes ist signed int) + // nothing to do + if (m_comment.list_length == 0) return OPUS_COMMENT_DONE; + return OPUS_COMMENT_NEED_MORE; + } + if ((uint32_t)available_bytes < to_read) to_read = (uint32_t)available_bytes; + + OPUS_LOG_DEBUG("to_read {}, available_bytes {}", to_read, available_bytes); + m_comment.start_pos = current_file_pos; + OPUS_LOG_DEBUG("partial start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf, to_read); + m_comment.save_len += to_read; + m_comment.pointer = to_read; + available_bytes -= to_read; + if (m_comment.save_len == m_comment.comment_size) { + OPUS_LOG_DEBUG("end {}", m_comment.start_pos + to_read); + m_comment.item_vec.push_back(m_comment.start_pos + to_read); + // m_comment.comment_content.println(); + parse_comment(m_comment.comment_content); + m_comment.comment_content.reset(); + m_comment.oob = false; + m_comment.list_length--; + } else { + OPUS_LOG_DEBUG("partial end {}", m_comment.start_pos + nBytes); + m_comment.item_vec.push_back(m_comment.start_pos + nBytes); + } + if (m_comment.list_length == 0) return OPUS_COMMENT_DONE; + if (available_bytes == 0) return OPUS_COMMENT_NEED_MORE; + // fall through + } + + // 🔹 2. If this is the first page → read header + bool first_call = (m_comment.pointer == 0 && m_comment.list_length == 0); + if (first_call) { + int32_t idx = OPUS_specialIndexOf(inbuf, "OpusTags", 10); + if (idx != 0) return OPUS_COMMENT_INVALID; + + m_comment.pointer = 8; // skip "OpusTags" + available_bytes -= 8; + uint32_t vendorLength = little_endian(inbuf + m_comment.pointer); + m_comment.pointer += 4 + vendorLength; // skip vendor string + available_bytes -= 4 + vendorLength; + m_comment.list_length = little_endian(inbuf + m_comment.pointer); + m_comment.pointer += 4; + available_bytes -= 4; + OPUS_LOG_DEBUG("VendorLen={}, CommentCount={}", vendorLength, m_comment.list_length); + if(m_comment.list_length == 0){ + return OPUS_COMMENT_DONE; + } + } + + // 🔹 3. read comments + while (m_comment.list_length > 0) { + + // --- handle possible split 4-byte comment length --- + if (m_comment.partial_length > 0 || available_bytes < 4) { + uint8_t bytes_to_copy = std::min(4 - m_comment.partial_length, available_bytes); + memcpy(m_comment.length_bytes + m_comment.partial_length, inbuf + (nBytes - available_bytes), bytes_to_copy); + + m_comment.partial_length += bytes_to_copy; + available_bytes -= bytes_to_copy; + m_comment.pointer += bytes_to_copy; + + OPUS_LOG_DEBUG("Partial length bytes collected: {}/4", m_comment.partial_length); + + if (m_comment.partial_length < 4) { + // still incomplete → need more data next call + return OPUS_COMMENT_NEED_MORE; + } + + // now we have all 4 bytes + m_comment.comment_size = little_endian(m_comment.length_bytes); + m_comment.partial_length = 0; // reset for next comment + OPUS_LOG_DEBUG("m_comment.comment_size (assembled) {}", m_comment.comment_size); + } else { + memcpy(m_comment.length_bytes, inbuf + (nBytes - available_bytes), 4); + m_comment.comment_size = little_endian(m_comment.length_bytes); + m_comment.pointer += 4; + available_bytes -= 4; + OPUS_LOG_DEBUG("m_comment.comment_size {}", m_comment.comment_size); + } + + if (m_comment.comment_size <= available_bytes) { // can completely read + m_comment.start_pos = current_file_pos + m_comment.pointer; + OPUS_LOG_DEBUG("start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf + (nBytes - available_bytes), m_comment.comment_size); + m_comment.end_pos = m_comment.start_pos + m_comment.comment_size; + OPUS_LOG_DEBUG("end {}", m_comment.end_pos); + m_comment.item_vec.push_back(m_comment.end_pos); + m_comment.pointer += m_comment.comment_size; + available_bytes -= m_comment.comment_size; + parse_comment(m_comment.comment_content); + m_comment.comment_content.reset(); + m_comment.list_length--; + if (m_comment.list_length == 0) return OPUS_COMMENT_DONE; + } + + else { // out of bounds + m_comment.start_pos = current_file_pos + nBytes - available_bytes; + OPUS_LOG_DEBUG("start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf + (nBytes - available_bytes), available_bytes); + m_comment.save_len = available_bytes; + OPUS_LOG_DEBUG("partial_end {}", m_comment.start_pos + m_comment.save_len); + m_comment.item_vec.push_back(m_comment.start_pos + m_comment.save_len); + m_comment.pointer = 0; + m_comment.oob = true; + return OPUS_COMMENT_NEED_MORE; + } + } + return OPUS_COMMENT_NEED_MORE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::parseOpusHead(uint8_t* inbuf, int32_t nBytes) { // reference https://wiki.xiph.org/OggOpus + + int32_t idx = OPUS_specialIndexOf(inbuf, "OpusHead", 10); + if (idx != 0) { + return 0; // is not OpusHead + } + uint8_t version = *(inbuf + 8); + (void)version; + uint8_t channelCount = *(inbuf + 9); // nr of channels + uint16_t preSkip = *(inbuf + 11) << 8; + preSkip += *(inbuf + 10); + uint32_t sampleRate = *(inbuf + 15) << 24; // informational only + sampleRate += *(inbuf + 14) << 16; + sampleRate += *(inbuf + 13) << 8; + sampleRate += *(inbuf + 12); + uint16_t outputGain = *(inbuf + 17) << 8; // Q7.8 in dB + outputGain += *(inbuf + 16); + uint8_t channelMap = *(inbuf + 18); + + if (channelCount == 0 || channelCount > 2) { + OPUS_LOG_ERROR("Opus channels out of range, ch: {}", channelCount); + return OPUS_ERR; + } + m_opusChannels = channelCount; + // OPUS_LOG_INFO("sampleRate {}", sampleRate); + // if(sampleRate != 48000 && sampleRate != 44100) return ERR_OPUS_INVALID_SAMPLERATE; + m_opusSamplerate = sampleRate; + if (channelMap > 1) { + OPUS_LOG_ERROR("Opus extra channels not supported"); + return OPUS_ERR; + } + + (void)outputGain; + + m_opusError = celtdec->celt_decoder_init(m_opusChannels); + if (m_opusError < 0) { + OPUS_LOG_ERROR("The CELT Decoder could not be initialized"); + return OPUS_ERR; + } + m_opusError = celtdec->celt_decoder_ctl(CELT_SET_SIGNALLING_REQUEST, 0); + if (m_opusError < 0) { + OPUS_LOG_ERROR("The CELT Decoder could not be initialized"); + return OPUS_ERR; + } + m_opusError = celtdec->celt_decoder_ctl(CELT_SET_END_BAND_REQUEST, 21); + if (m_opusError < 0) { + OPUS_LOG_ERROR("The CELT Decoder could not be initialized"); + return OPUS_ERR; + } + + return 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::parseOGG(uint8_t* inbuf, int32_t* bytesLeft) { // reference https://www.xiph.org/ogg/doc/rfc3533.txt + + int32_t idx = OPUS_specialIndexOf(inbuf, "OggS", 6); + if (idx != 0) { + OPUS_LOG_ERROR("Opus dec async, OGG capture pattern \"OggS\" not found"); + return OPUS_ERR; + } + + int16_t segmentTableWrPtr = -1; + + uint8_t version = *(inbuf + 4); + (void)version; + uint8_t headerType = *(inbuf + 5); + (void)headerType; + uint64_t granulePosition = (uint64_t)*(inbuf + 13) << 56; // granule_position: an 8 Byte field containing - + granulePosition += (uint64_t)*(inbuf + 12) << 48; // position information. For an audio stream, it MAY + granulePosition += (uint64_t)*(inbuf + 11) << 40; // contain the total number of PCM samples encoded + granulePosition += (uint64_t)*(inbuf + 10) << 32; // after including all frames finished on this page. + granulePosition += *(inbuf + 9) << 24; // This is a hint for the decoder and gives it some timing + granulePosition += *(inbuf + 8) << 16; // and position information. A special value of -1 (in two's + granulePosition += *(inbuf + 7) << 8; // complement) indicates that no packets finish on this page. + granulePosition += *(inbuf + 6); + (void)granulePosition; + uint32_t bitstreamSerialNr = *(inbuf + 17) << 24; // bitstream_serial_number: a 4 Byte field containing the + bitstreamSerialNr += *(inbuf + 16) << 16; // unique serial number by which the logical bitstream + bitstreamSerialNr += *(inbuf + 15) << 8; // is identified. + bitstreamSerialNr += *(inbuf + 14); + (void)bitstreamSerialNr; + uint32_t pageSequenceNr = *(inbuf + 21) << 24; // page_sequence_number: a 4 Byte field containing the sequence + pageSequenceNr += *(inbuf + 20) << 16; // number of the page so the decoder can identify page loss + pageSequenceNr += *(inbuf + 19) << 8; // This sequence number is increasing on each logical bitstream + pageSequenceNr += *(inbuf + 18); + (void)pageSequenceNr; + uint32_t CRCchecksum = *(inbuf + 25) << 24; + CRCchecksum += *(inbuf + 24) << 16; + CRCchecksum += *(inbuf + 23) << 8; + CRCchecksum += *(inbuf + 22); + (void)CRCchecksum; + uint8_t pageSegments = *(inbuf + 26); // giving the number of segment entries + + // read the segment table (contains pageSegments bytes), 1...251: Length of the frame in bytes, + // 255: A second byte is needed. The total length is first_byte + second byte + m_opusSegmentLength = 0; + segmentTableWrPtr = -1; + + for (int32_t i = 0; i < pageSegments; i++) { + int32_t n = *(inbuf + 27 + i); + while (*(inbuf + 27 + i) == 255) { + i++; + if (i == pageSegments) break; + n += *(inbuf + 27 + i); + } + segmentTableWrPtr++; + m_opusSegmentTable[segmentTableWrPtr] = n; + m_opusSegmentLength += n; + } + m_opusSegmentTableSize = segmentTableWrPtr + 1; + m_opusCompressionRatio = (float)(960 * 2 * pageSegments) / m_opusSegmentLength; // const 960 validBytes out + + m_f_continuedPage = headerType & 0x01; // set: page contains data of a packet continued from the previous page + m_f_firstPage = headerType & 0x02; // set: this is the first page of a logical bitstream (bos) + m_f_lastPage = headerType & 0x04; // set: this is the last page of a logical bitstream (eos) + + if (m_f_firstPage) { m_opusPageNr = 0; } + + OPUS_LOG_DEBUG("firstPage {}, continuedPage {}, lastPage {}", m_f_firstPage, m_f_continuedPage, m_f_lastPage); + + uint16_t headerSize = pageSegments + 27; + *bytesLeft -= headerSize; + // m_opusCurrentFilePos += headerSize; + m_opusOggHeaderSize = headerSize; + + int32_t pLen = _min((int32_t)m_opusSegmentLength, m_opusRemainBlockPicLen); + // OPUS_LOG_INFO("s_opusSegmentLength {}, m_opusRemainBlockPicLen {}", m_opusSegmentLength, m_opusRemainBlockPicLen); + if (m_opusBlockPicLen && pLen > 0) { + m_opusBlockPicItem.push_back(m_opusCurrentFilePos); + m_opusBlockPicItem.push_back(pLen); + } + return OPUS_NONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + // assume we have a ogg wrapper + int32_t idx = OPUS_specialIndexOf(buf, "OggS", nBytes); + if (idx >= 0) { // Magic Word found + // OPUS_LOG_INFO("OggS found at {}", idx); + m_f_opusParseOgg = true; + return idx; + } + m_f_opusParseOgg = false; + OPUS_LOG_ERROR("Opus syncword not found"); + return OPUS_ERR; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::OPUS_specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact) { + int32_t result = -1; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int32_t i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int32_t j = 0; j < strlen(str) + exact; j++) { + if (*(base + i + j) != *(str + j)) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t OpusDecoder::OPUS_specialIndexOf_icase(uint8_t* base, const char* str, int32_t baselen, bool exact) { + int32_t result = -1; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int32_t i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int32_t j = 0; j < strlen(str) + exact; j++) { + if (tolower(*(base + i + j)) != tolower(*(str + j))) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t OpusDecoder::little_endian(uint8_t* data) { + return (uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[3]) << 24)); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.h b/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.h new file mode 100644 index 0000000..be157fc --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/opus_decoder.h @@ -0,0 +1,228 @@ +// based on Xiph.Org Foundation celt decoder +#pragma once + +#include "../Audio.h" +#include "../psram_unique_ptr.hpp" +#include "celt.h" +#include "range_decoder.h" +#include "silk.h" +#include + +#define ANSI_ESC_RESET "\033[0m" +#define ANSI_ESC_BLACK "\033[30m" +#define ANSI_ESC_RED "\033[31m" +#define ANSI_ESC_GREEN "\033[32m" +#define ANSI_ESC_YELLOW "\033[33m" +#define ANSI_ESC_BLUE "\033[34m" +#define ANSI_ESC_MAGENTA "\033[35m" +#define ANSI_ESC_CYAN "\033[36m" +#define ANSI_ESC_WHITE "\033[37m" + +class OpusDecoder : public Decoder { + + public: + OpusDecoder(Audio& audioRef) + : Decoder(audioRef), rangedec(std::make_unique()), silkdec(std::make_unique(*rangedec)), celtdec(std::make_unique(*rangedec)), audio(audioRef) {} + ~OpusDecoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; + const char* arg2() override; + virtual int32_t val1() override; + virtual int32_t val2() override; + + std::unique_ptr rangedec; + std::unique_ptr silkdec; + std::unique_ptr celtdec; + + enum : int8_t { OPUS_END = 120, OPUS_CONTINUE = 10, OPUS_PARSE_OGG_DONE = 100, OPUS_NONE = 0, OPUS_ERR = -1 }; + + private: + Audio& audio; + typedef struct _ofp2 { + uint16_t firstFrameLength{}; + uint16_t secondFrameLength{}; + + void reset() { + *this = _ofp2{}; // sauber neu initialisieren + } + } ofp2_t; + + typedef struct _ofp3 { // opus_FramePacking_Code + bool firstCall{}; + bool v{}; // VBR indicator + bool p{}; // padding exists + int16_t fs{}; // frame size + uint8_t M{}; // nr of frames + int32_t spf{}; // samples per frame + int32_t paddingLength{}; + uint16_t c1fs{}; + uint16_t vfs[48]{}; // variable frame size + uint32_t idx{}; + + void reset() { + *this = _ofp3{}; // sauber neu initialisieren + } + } ofp3_t; + + typedef struct _odp3 { + int8_t configNr{}; + uint16_t samplesPerFrame{}; + + void reset() { + // Default-initialize alles neu (inklusive Array) + *this = _odp3{}; + } + + } odp3_t; + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_MODE_REQUEST 10015 + + enum { OPUS_BANDWIDTH_NARROWBAND = 1101, OPUS_BANDWIDTH_MEDIUMBAND = 1102, OPUS_BANDWIDTH_WIDEBAND = 1103, OPUS_BANDWIDTH_SUPERWIDEBAND = 1104, OPUS_BANDWIDTH_FULLBAND = 1105 }; + enum ParseResult { OPUS_COMMENT_INVALID = -1, OPUS_COMMENT_NEED_MORE = 1, OPUS_COMMENT_DONE = 2 }; + + uint8_t m_opusChannels = 0; + uint8_t m_opusCountCode = 0; + uint8_t m_opusPageNr = 0; + uint8_t m_frameCount = 0; + uint8_t m_opusSegmentTableSize = 0; + uint16_t m_mode = 0; + uint16_t m_opusOggHeaderSize = 0; + uint16_t m_bandWidth = 0; + uint16_t m_internalSampleRate = 0; + uint16_t m_endband = 0; + uint32_t m_opusSamplerate = 0; + uint32_t m_opusSegmentLength = 0; + uint32_t m_opusCurrentFilePos = 0; + uint32_t m_opusAudioDataStart = 0; + uint32_t m_opusBlockPicPos = 0; + uint32_t m_opusBlockLen = 0; + bool m_f_opusParseOgg = false; + bool m_f_newSteamTitle = false; // streamTitle + bool m_f_opusNewMetadataBlockPicture = false; // new metadata block picture + bool m_f_opusStereoFlag = false; + bool m_f_continuedPage = false; + bool m_f_firstPage = false; + bool m_f_lastPage = false; + bool m_f_nextChunk = false; + bool m_isValid = false; + int8_t m_opusError = 0; + int16_t m_opusSegmentTableRdPtr = -1; + int16_t m_prev_mode = 0; + int32_t m_opusValidSamples = 0; + int32_t m_opusBlockPicLen = 0; + int32_t m_blockPicLenUntilFrameEnd = 0; + int32_t m_opusRemainBlockPicLen = 0; + int32_t m_opusCommentBlockSize = 0; + float m_opusCompressionRatio = 0; + ps_ptr m_out16; + + struct picture_segment_t { + uint32_t start_page_index{}; + uint32_t start_offset{}; + uint32_t end_page_index{}; + uint32_t end_offset{}; + bool in_progress{}; + }; + + typedef struct _comment { + uint32_t pointer{}; + uint32_t list_length{}; + bool oob{}; // out of bounds (block overflow) + uint32_t save_len{}; + uint32_t comment_size{}; + uint32_t start_pos{}; // comment start file position + uint32_t end_pos{}; // comment end file position + uint8_t length_bytes[4]{}; // 🆕 Addition for split 4-byte length fields + uint8_t partial_length{}; // how many of the 4 bytes have already been read + uint32_t bytes_available{}; + + ps_ptr stream_title{}; + ps_ptr comment_content{}; + std::vector item_vec; + std::vector pic_vec; + + void reset() { *this = _comment{}; } + } comment_t; + comment_t m_comment; + + ps_ptr m_opusSegmentTable; + + ofp2_t m_ofp2; // used in opus_FramePacking_Code2 + ofp3_t m_ofp3; // used in opus_FramePacking_Code3 + odp3_t m_odp3; // used in opusDecodePage3 + + std::vector m_opusBlockPicItem; + + void OPUSsetDefaults(); + int32_t opusDecodePage0(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength); + int32_t opusDecodePage3(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, int16_t* outbuf); + int8_t opus_FramePacking_Code0(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame); + int8_t opus_FramePacking_Code1(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount); + int8_t opus_FramePacking_Code2(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount); + int8_t opus_FramePacking_Code3(uint8_t* inbuf, int32_t* bytesLeft, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame, uint8_t* frameCount); + int32_t parseOGG(uint8_t* inbuf, int32_t* bytesLeft); + int32_t parseOpusHead(uint8_t* inbuf, int32_t nBytes); + int32_t parseOpusComment(uint8_t* inbuf, int32_t nBytes, uint32_t current_file_pos); + int8_t parseOpusTOC(uint8_t TOC_Byte); + int32_t opus_packet_get_samples_per_frame(const uint8_t* data, int32_t Fs); + int32_t opus_decode_frame(uint8_t* inbuf, int16_t* outbuf, int32_t packetLen, uint16_t samplesPerFrame); + + // some helper functions + int32_t OPUS_specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + int32_t OPUS_specialIndexOf_icase(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + uint32_t little_endian(uint8_t* data); + enum { MODE_NONE = 0, MODE_SILK_ONLY = 1000, MODE_HYBRID = 1001, MODE_CELT_ONLY = 1002 }; + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // Macro for comfortable calls +#define OPUS_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define OPUS_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define OPUS_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define OPUS_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define OPUS_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // Macro for time measuring + // PROFILE_START(decodeNative); + // ret = decodeNative(inbuf, bytesLeft, outbuf); + // PROFILE_END_N(decodeNative, 1000); + +#define PROFILE_START(name) \ + static uint64_t _prof_##name##_start = 0; \ + _prof_##name##_start = esp_timer_get_time() + +#define PROFILE_END_N(name, N) \ + do { \ + static uint64_t _prof_##name##_sum = 0; \ + static uint32_t _prof_##name##_count = 0; \ + uint64_t _prof_##name##_elapsed = esp_timer_get_time() - _prof_##name##_start; \ + _prof_##name##_sum += _prof_##name##_elapsed; \ + _prof_##name##_count++; \ + if (_prof_##name##_count >= (N)) { \ + printf("%-20s avg: %.2f µs over %u runs\n", #name, (double)_prof_##name##_sum / _prof_##name##_count, _prof_##name##_count); \ + _prof_##name##_sum = 0; \ + _prof_##name##_count = 0; \ + } \ + } while (0) +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.cpp b/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.cpp new file mode 100644 index 0000000..f459e3a --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.cpp @@ -0,0 +1,223 @@ +#include "range_decoder.h" + +RangeDecoder::RangeDecoder() : m_buf(nullptr) {} + +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This is a faster version of ec_tell_frac() that takes advantage of the low (1/8 bit) resolution to use just a linear function followed by a lookup to determine the exact transition thresholds. */ +uint32_t RangeDecoder::tell_frac() { + const uint32_t correction[8] = {35733, 38967, 42495, 46340, 50535, 55109, 60097, 65535}; + uint32_t nbits; + uint32_t r; + int32_t l; + uint32_t b; + nbits = m_nbits_total << EC_BITRES; + l = EC_ILOG(m_rng); + r = m_rng >> (l - 16); + b = (r >> 12) - 8; + b += r > correction[b]; + l = (l << 3) + b; + return nbits - l; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t RangeDecoder::read_byte() { return m_offs < m_storage ? m_buf[m_offs++] : 0; } +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t RangeDecoder::read_byte_from_end() { + return m_end_offs < m_storage ? m_buf[m_storage - ++(m_end_offs)] : 0; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/*Normalizes the contents of val and rng so that rng lies entirely in the high-order symbol.*/ +void RangeDecoder::dec_normalize() { + /*If the range is too small, rescale it and input some bits.*/ + while (m_rng <= EC_CODE_BOT) { + int32_t sym; + m_nbits_total += EC_SYM_BITS; + m_rng <<= EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym = m_rem; + /*Read the next value from the input.*/ + m_rem = read_byte(); + /*Take the rest of the bits we need from this new symbol.*/ + sym = (sym << EC_SYM_BITS | m_rem) >> (EC_SYM_BITS - EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + m_val = ((m_val << EC_SYM_BITS) + (EC_SYM_MAX & ~sym)) & ((EC_CODE_TOP) - 1); + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void RangeDecoder::dec_init(uint8_t *_buf, uint32_t _storage) { + + m_buf = _buf; + m_storage = _storage; + m_end_offs = 0; + m_end_window = 0; + m_nend_bits = 0; + m_nbits_total = EC_CODE_BITS + 1 - ((EC_CODE_BITS - EC_CODE_EXTRA) / EC_SYM_BITS) * EC_SYM_BITS; + m_offs = 0; + m_rng = 1U << EC_CODE_EXTRA; + m_rem = read_byte(); + m_val = m_rng - 1 - (m_rem >> (EC_SYM_BITS - EC_CODE_EXTRA)); + m_error = 0; + /*Normalize the interval.*/ + dec_normalize(); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t RangeDecoder::decode(uint32_t _ft) { + uint32_t s; + m_ext = m_rng / _ft; + s = (uint32_t)(m_val / m_ext); + return _ft - EC_MINI(s + 1, _ft); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t RangeDecoder::decode_bin(uint32_t _bits) { + uint32_t s; + m_ext = m_rng >> _bits; + s = (uint32_t)(m_val / m_ext); + return (1U << _bits) - EC_MINI(s + 1U, 1U << _bits); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void RangeDecoder::dec_update(uint32_t _fl, uint32_t _fh, uint32_t _ft) { + uint32_t s; + s = m_ext * (_ft - _fh); + m_val -= s; + + if(_fl > 0){ + m_rng = m_ext * (_fh - _fl); + } + else{ + m_rng = m_rng - s; + } + dec_normalize(); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/*The probability of having a "one" is 1/(1<<_logp).*/ +int32_t RangeDecoder::dec_bit_logp( uint32_t _logp) { + uint32_t r; + uint32_t d; + uint32_t s; + int32_t ret; + r = m_rng; + d = m_val; + s = r >> _logp; + ret = d < s; + if (!ret) m_val = d - s; + m_rng = ret ? s : r - s; + dec_normalize(); + return ret; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t RangeDecoder::dec_icdf(const uint8_t *_icdf, uint32_t _ftb) { + uint32_t r; + uint32_t d; + uint32_t s; + uint32_t t; + int32_t ret; + s = m_rng; + d = m_val; + r = s >> _ftb; + ret = -1; + do { + t = s; + s = r * _icdf[++ret]; + } while (d < s); + m_val = d - s; + m_rng = t - s; + dec_normalize(); + return ret; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t RangeDecoder::dec_uint(uint32_t _ft) { + uint32_t ft; + uint32_t s; + int32_t ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + assert(_ft > 1); + _ft--; + ftb = EC_ILOG(_ft); + if (ftb > EC_UINT_BITS) { + uint32_t t; + ftb -= EC_UINT_BITS; + ft = (uint32_t)(_ft >> ftb) + 1; + s = decode(ft); + dec_update(s, s + 1, ft); + t = (uint32_t)s << ftb | dec_bits(ftb); + if (t <= _ft) return t; + m_error = 1; + return _ft; + } else { + _ft++; + s = decode((uint32_t)_ft); + dec_update(s, s + 1, (uint32_t)_ft); + return s; + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t RangeDecoder::dec_bits(uint32_t _bits) { + uint32_t window; + int32_t available; + uint32_t ret; + window = m_end_window; + available = m_nend_bits; + if ((uint32_t)available < _bits) { + do { + window |= (uint32_t)read_byte_from_end() << available; + available += EC_SYM_BITS; + } while (available <= EC_WINDOW_SIZE - EC_SYM_BITS); + } + ret = (uint32_t)window & (((uint32_t)1 << _bits) - 1U); + window >>= _bits; + available -= _bits; + m_end_window = window; + m_nend_bits = available; + m_nbits_total += _bits; + return ret; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t RangeDecoder::tell(){return m_nbits_total-EC_ILOG(m_rng);} +void RangeDecoder::add_nbits_total(int32_t nbits_total){m_nbits_total += nbits_total;} +uint32_t RangeDecoder::get_storage(){return m_storage;} +int32_t RangeDecoder::get_error(){return m_error;} +uint32_t RangeDecoder::get_rng(){return m_rng;} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* When called, decay is positive and at most 11456. */ +uint32_t RangeDecoder::laplace_get_freq1(uint32_t fs0, int32_t decay) { + uint32_t ft; + ft = 32768 - LAPLACE_MINP * (2 * LAPLACE_NMIN) - fs0; + return ft * (int32_t)(16384 - decay) >> 15; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t RangeDecoder::laplace_decode(uint32_t fs, int32_t decay) { + int32_t val = 0; + uint32_t fl; + uint32_t fm; + fm = decode_bin(15); + fl = 0; + if (fm >= fs) { + val++; + fl = fs; + fs = laplace_get_freq1(fs, decay) + LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while (fs > LAPLACE_MINP && fm >= fl + 2 * fs) { + fs *= 2; + fl += fs; + fs = ((fs - 2 * LAPLACE_MINP) * (int32_t)decay) >> 15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) { + int32_t di; + di = (fm - fl) >> (LAPLACE_LOG_MINP + 1); + val += di; + fl += 2 * di * LAPLACE_MINP; + } + if (fm < fl + fs) + val = -val; + else + fl += fs; + } + assert(fl < 32768); + assert(fs > 0); + assert(fl <= fm); + assert(fm < min((uint32_t)(fl + fs), (uint32_t)32768)); + dec_update(fl, min((uint32_t)(fl + fs), (uint32_t)32768), (uint32_t)32768); + return val; +} \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.h b/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.h new file mode 100644 index 0000000..4a57736 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/range_decoder.h @@ -0,0 +1,64 @@ +#pragma once + +#include "Arduino.h" + +class RangeDecoder { +public: + RangeDecoder(); + ~RangeDecoder(){} + void dec_init(uint8_t *_buf, uint32_t _storage); + uint32_t get_storage(); + uint32_t dec_bits(uint32_t _bits); + uint32_t dec_uint(uint32_t _ft); + uint32_t decode(uint32_t _ft); + uint32_t decode_bin(uint32_t _bits); + void dec_update(uint32_t _fl, uint32_t _fh, uint32_t _ft); + int32_t dec_bit_logp( uint32_t _logp); + uint32_t tell_frac(); + int32_t dec_icdf(const uint8_t *_icdf, uint32_t _ftb); + int32_t tell(); + void add_nbits_total(int32_t nbits_total); + int32_t get_error(); + uint32_t get_rng(); + int32_t laplace_decode(uint32_t fs, int32_t decay); + +private: + #define EC_WINDOW_SIZE ((int32_t)sizeof(uint32_t)*CHAR_BIT) + #define EC_UINT_BITS (8) + #define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + #define EC_CLZ0s ((int32_t)sizeof(uint32_t)*CHAR_BIT) + #define EC_CLZ(_x) (__builtin_clz(_x)) + #define EC_ILOG(_x) (EC_CLZ0s-EC_CLZ(_x)) + #define EC_BITRES 3 + + #define EC_SYM_BITS 8 + #define EC_CODE_BITS 32 + #define EC_SYM_MAX ((1U << EC_SYM_BITS) - 1) + #define EC_CODE_TOP 1U << (EC_CODE_BITS - 1) + #define EC_CODE_BOT EC_CODE_TOP >> EC_SYM_BITS + #define EC_CODE_EXTRA ((EC_CODE_BITS-2) % EC_SYM_BITS + 1) + + #define LAPLACE_LOG_MINP (0) + #define LAPLACE_MINP (1< 1; n--) { out[n] += out[n - 2] - (int32_t)silk_RSHIFT_ROUND64(silk_SMULL(ftmp, out[n - 1]), QA16); } + out[1] -= ftmp; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* compute whitening filter coefficients from normalized line spectral frequencies(monic whitening filter coefficients in Q12, normalized line spectral frequencies in Q15, filter order) */ +void SilkDecoder::silk_NLSF2A(int16_t* a_Q12, const int16_t* NLSF, const int32_t d) { + /* This ordering was found to maximize quality. It improves numerical accuracy of silk_NLSF2A_find_poly() compared to "standard" ordering. */ + const unsigned char ordering16[16] = {0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1}; + const unsigned char ordering10[10] = {0, 9, 6, 3, 4, 5, 8, 1, 2, 7}; + const unsigned char* ordering; + uint8_t QA16 = 16; + int32_t k, i, dd; + ps_ptr cos_LSF_QA; + cos_LSF_QA.alloc_array(SILK_MAX_ORDER_LPC); + ps_ptr P; + P.alloc_array(SILK_MAX_ORDER_LPC / 2 + 1); + ps_ptr Q; + Q.alloc_array(SILK_MAX_ORDER_LPC / 2 + 1); + int32_t Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + ps_ptr a32_QA1; + a32_QA1.alloc_array(SILK_MAX_ORDER_LPC); + + assert(LSF_COS_TAB_SZ_FIX == 128); + assert(d == 10 || d == 16); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for (k = 0; k < d; k++) { + assert(NLSF[k] >= 0); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT(NLSF[k], 15 - 7); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT(f_int, 15 - 7); + + assert(f_int >= 0); + assert(f_int < LSF_COS_TAB_SZ_FIX); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[f_int]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[f_int + 1] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND(silk_LSHIFT(cos_val, 8) + silk_MUL(delta, f_frac), 20 - QA16); /* QA16 */ + } + + dd = silk_RSHIFT(d, 1); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly(P.get(), &cos_LSF_QA[0], dd); + silk_NLSF2A_find_poly(Q.get(), &cos_LSF_QA[1], dd); + + /* convert even and odd polynomials to int32_t Q12 filter coefs */ + for (k = 0; k < dd; k++) { + Ptmp = P[k + 1] + P[k]; + Qtmp = Q[k + 1] - Q[k]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[k] = -Qtmp - Ptmp; + a32_QA1[d - k - 1] = Qtmp - Ptmp; + } + + /* Convert int32 coefficients to Q12 int16 coefs */ + silk_LPC_fit(a_Q12, a32_QA1.get(), 12, QA16 + 1, d); + + for (i = 0; silk_LPC_inverse_pred_gain(a_Q12, d) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32(a32_QA1.get(), d, 65536 - silk_LSHIFT(2, i)); + for (k = 0; k < d; k++) { a_Q12[k] = (int16_t)silk_RSHIFT_ROUND(a32_QA1[k], QA16 + 1 - 12); /* QA16+1 -> Q12 */ } + } +} +//---------------------------------------------------------------------------------------------------------------------- +/* Decode side-information parameters from payload */ +void SilkDecoder::silk_decode_indices(uint8_t n, int32_t FrameIndex, /* I Frame number */ + int32_t decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + int32_t condCoding /* I The type of conditional coding to use */ +) { + int32_t i, k, Ix; + int32_t decode_absolute_lagIndex, delta_lagIndex; + int16_t ec_ix[MAX_LPC_ORDER]; + uint8_t pred_Q8[MAX_LPC_ORDER]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if (decode_LBRR || m_channel_state[n].VAD_flags[FrameIndex]) { + Ix = rd.dec_icdf(silk_type_offset_VAD_iCDF, 8) + 2; + } else { + Ix = rd.dec_icdf(silk_type_offset_no_VAD_iCDF, 8); + } + m_channel_state[n].indices.signalType = (int8_t)silk_RSHIFT(Ix, 1); + m_channel_state[n].indices.quantOffsetType = (int8_t)(Ix & 1); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if (condCoding == CODE_CONDITIONALLY) { + /* Conditional coding */ + m_channel_state[n].indices.GainsIndices[0] = (int8_t)rd.dec_icdf(silk_delta_gain_iCDF, 8); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + m_channel_state[n].indices.GainsIndices[0] = (int8_t)silk_LSHIFT(rd.dec_icdf(silk_gain_iCDF[m_channel_state[n].indices.signalType], 8), 3); + m_channel_state[n].indices.GainsIndices[0] += (int8_t)rd.dec_icdf(silk_uniform8_iCDF, 8); + } + + /* Remaining subframes */ + for (i = 1; i < m_channel_state[n].nb_subfr; i++) { + if (i < MAX_NB_SUBFR) { m_channel_state[n].indices.GainsIndices[i] = (int8_t)rd.dec_icdf(silk_delta_gain_iCDF, 8); } + } + /**********************/ + /* Decode LSF Indices */ + /**********************/ + m_channel_state[n].indices.NLSFIndices[0] = (int8_t)rd.dec_icdf(&m_channel_state[n].psNLSF_CB->CB1_iCDF[(m_channel_state[n].indices.signalType >> 1) * m_channel_state[n].psNLSF_CB->nVectors], 8); + silk_NLSF_unpack(ec_ix, pred_Q8, m_channel_state[n].psNLSF_CB, m_channel_state[n].indices.NLSFIndices[0]); + assert(m_channel_state[n].psNLSF_CB->order == m_channel_state[n].LPC_order); + for (i = 0; i < m_channel_state[n].psNLSF_CB->order; i++) { + Ix = rd.dec_icdf(&m_channel_state[n].psNLSF_CB->ec_iCDF[ec_ix[i]], 8); + if (Ix == 0) { + Ix -= rd.dec_icdf(silk_NLSF_EXT_iCDF, 8); + } else if (Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE) { + Ix += rd.dec_icdf(silk_NLSF_EXT_iCDF, 8); + } + m_channel_state[n].indices.NLSFIndices[i + 1] = (int8_t)(Ix - NLSF_QUANT_MAX_AMPLITUDE); + } + + /* Decode LSF interpolation factor */ + if (m_channel_state[n].nb_subfr == MAX_NB_SUBFR) { + m_channel_state[n].indices.NLSFInterpCoef_Q2 = (int8_t)rd.dec_icdf(silk_NLSF_interpolation_factor_iCDF, 8); + } else { + m_channel_state[n].indices.NLSFInterpCoef_Q2 = 4; + } + + if (m_channel_state[n].indices.signalType == TYPE_VOICED) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if (condCoding == CODE_CONDITIONALLY && m_channel_state[n].ec_prevSignalType == TYPE_VOICED) { + /* Decode Delta index */ + delta_lagIndex = (int16_t)rd.dec_icdf(silk_pitch_delta_iCDF, 8); + if (delta_lagIndex > 0) { + delta_lagIndex = delta_lagIndex - 9; + m_channel_state[n].indices.lagIndex = (int16_t)(m_channel_state[n].ec_prevLagIndex + delta_lagIndex); + decode_absolute_lagIndex = 0; + } + } + if (decode_absolute_lagIndex) { + /* Absolute decoding */ + m_channel_state[n].indices.lagIndex = (int16_t)rd.dec_icdf(silk_pitch_lag_iCDF, 8) * silk_RSHIFT(m_channel_state[n].fs_kHz, 1); + m_channel_state[n].indices.lagIndex += (int16_t)rd.dec_icdf(m_channel_state[n].pitch_lag_low_bits_iCDF, 8); + } + m_channel_state[n].ec_prevLagIndex = m_channel_state[n].indices.lagIndex; + + /* Get countour index */ + m_channel_state[n].indices.contourIndex = (int8_t)rd.dec_icdf(m_channel_state[n].pitch_contour_iCDF, 8); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + m_channel_state[n].indices.PERIndex = (int8_t)rd.dec_icdf(silk_LTP_per_index_iCDF, 8); + + for (k = 0; k < m_channel_state[n].nb_subfr; k++) { + if (k < MAX_NB_SUBFR) { m_channel_state[n].indices.LTPIndex[k] = (int8_t)rd.dec_icdf(silk_LTP_gain_iCDF_ptrs[m_channel_state[n].indices.PERIndex], 8); } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if (condCoding == CODE_INDEPENDENTLY) { + m_channel_state[n].indices.LTP_scaleIndex = (int8_t)rd.dec_icdf(silk_LTPscale_iCDF, 8); + } else { + m_channel_state[n].indices.LTP_scaleIndex = 0; + } + } + m_channel_state[n].ec_prevSignalType = m_channel_state[n].indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + m_channel_state[n].indices.Seed = (int8_t)rd.dec_icdf(silk_uniform4_iCDF, 8); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_decode_parameters(uint8_t n, int32_t condCoding) { + int32_t i, k, Ix; + int16_t pNLSF_Q15[MAX_LPC_ORDER], pNLSF0_Q15[MAX_LPC_ORDER]; + const int8_t* cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant(m_silk_decoder_control->Gains_Q16, m_channel_state[n].indices.GainsIndices, &m_channel_state[n].LastGainIndex, condCoding == CODE_CONDITIONALLY, m_channel_state[n].nb_subfr); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode(pNLSF_Q15, m_channel_state[n].indices.NLSFIndices, m_channel_state[n].psNLSF_CB); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A(m_silk_decoder_control->PredCoef_Q12[1], pNLSF_Q15, m_channel_state[n].LPC_order); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if (m_channel_state[n].first_frame_after_reset == 1) { m_channel_state[n].indices.NLSFInterpCoef_Q2 = 4; } + + if (m_channel_state[n].indices.NLSFInterpCoef_Q2 < 4) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, the previous NLSF1, and the current NLSF1 */ + for (i = 0; i < m_channel_state[n].LPC_order; i++) { + pNLSF0_Q15[i] = m_channel_state[n].prevNLSF_Q15[i] + silk_RSHIFT(silk_MUL(m_channel_state[n].indices.NLSFInterpCoef_Q2, pNLSF_Q15[i] - m_channel_state[n].prevNLSF_Q15[i]), 2); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A(m_silk_decoder_control->PredCoef_Q12[0], pNLSF0_Q15, m_channel_state[n].LPC_order); + } else { + /* Copy LPC coefficients for first half from second half */ + memcpy(m_silk_decoder_control->PredCoef_Q12[0], m_silk_decoder_control->PredCoef_Q12[1], m_channel_state[n].LPC_order * sizeof(int16_t)); + } + memcpy(m_channel_state[n].prevNLSF_Q15, pNLSF_Q15, m_channel_state[n].LPC_order * sizeof(int16_t)); + + /* After a packet loss do BWE of LPC coefs */ + if (m_channel_state[n].lossCnt) { + silk_bwexpander(m_silk_decoder_control->PredCoef_Q12[0], m_channel_state[n].LPC_order, BWE_AFTER_LOSS_Q16); + silk_bwexpander(m_silk_decoder_control->PredCoef_Q12[1], m_channel_state[n].LPC_order, BWE_AFTER_LOSS_Q16); + } + + if (m_channel_state[n].indices.signalType == TYPE_VOICED) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch(m_channel_state[n].indices.lagIndex, m_channel_state[n].indices.contourIndex, m_silk_decoder_control->pitchL, m_channel_state[n].fs_kHz, m_channel_state[n].nb_subfr); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[m_channel_state[n].indices.PERIndex]; /* set pointer to start of codebook */ + + for (k = 0; k < m_channel_state[n].nb_subfr; k++) { + Ix = m_channel_state[n].indices.LTPIndex[k]; + for (i = 0; i < LTP_ORDER; i++) { m_silk_decoder_control->LTPCoef_Q14[k * LTP_ORDER + i] = silk_LSHIFT(cbk_ptr_Q7[Ix * LTP_ORDER + i], 7); } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = m_channel_state[n].indices.LTP_scaleIndex; + m_silk_decoder_control->LTP_scale_Q14 = silk_LTPScales_table_Q14[Ix]; + } else { + memset(m_silk_decoder_control->pitchL, 0, m_channel_state[n].nb_subfr * sizeof(int32_t)); + memset(m_silk_decoder_control->LTPCoef_Q14, 0, LTP_ORDER * m_channel_state[n].nb_subfr * sizeof(int16_t)); + m_channel_state[n].indices.PERIndex = 0; + m_silk_decoder_control->LTP_scale_Q14 = 0; + } +} +//---------------------------------------------------------------------------------------------------------------------- +/* Decode quantization indices of excitation */ + +void SilkDecoder::silk_decode_pulses(int16_t pulses[], /* O Excitation signal */ + const int32_t signalType, /* I Sigtype */ + const int32_t quantOffsetType, /* I quantOffsetType */ + const int32_t frame_length /* I Frame length */ +) { + int32_t i, j, k, iter, abs_q, nLS, RateLevelIndex; + ps_ptr sum_pulses; + sum_pulses.alloc_array(MAX_NB_SHELL_BLOCKS); + ps_ptr nLshifts; + nLshifts.alloc_array(MAX_NB_SHELL_BLOCKS); + int16_t* pulses_ptr; + const uint8_t* cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = rd.dec_icdf(silk_rate_levels_iCDF[signalType >> 1], 8); + + /* Calculate number of shell blocks */ + assert(1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH); + iter = silk_RSHIFT(frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH); + if (iter * SHELL_CODEC_FRAME_LENGTH < frame_length) { + assert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[RateLevelIndex]; + for (i = 0; i < iter; i++) { + nLshifts[i] = 0; + sum_pulses[i] = rd.dec_icdf(cdf_ptr, 8); + + /* LSB indication */ + while (sum_pulses[i] == SILK_MAX_PULSES + 1) { + nLshifts[i]++; + /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ + sum_pulses[i] = rd.dec_icdf(silk_pulses_per_block_iCDF[N_RATE_LEVELS - 1] + (nLshifts[i] == 10), 8); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for (i = 0; i < iter; i++) { + if (sum_pulses[i] > 0) { + silk_shell_decoder(&pulses[silk_SMULBB(i, SHELL_CODEC_FRAME_LENGTH)], sum_pulses[i]); + } else { + memset(&pulses[silk_SMULBB(i, SHELL_CODEC_FRAME_LENGTH)], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(pulses[0])); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for (i = 0; i < iter; i++) { + if (nLshifts[i] > 0) { + nLS = nLshifts[i]; + pulses_ptr = &pulses[silk_SMULBB(i, SHELL_CODEC_FRAME_LENGTH)]; + for (k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++) { + abs_q = pulses_ptr[k]; + for (j = 0; j < nLS; j++) { + abs_q = silk_LSHIFT(abs_q, 1); + abs_q += rd.dec_icdf(silk_lsb_iCDF, 8); + } + pulses_ptr[k] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[i] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs(pulses, frame_length, signalType, quantOffsetType, sum_pulses.get()); +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Set decoder sampling rate (Decoder state pointer , Sampling frequency (kHz) , API Sampling frequency (Hz))*/ +int32_t SilkDecoder::silk_decoder_set_fs(uint8_t n, int32_t fs_kHz, int32_t fs_API_Hz) { + int32_t frame_length, ret = 0; + + assert(fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16); + assert(m_channel_state[n].nb_subfr == MAX_NB_SUBFR || m_channel_state[n].nb_subfr == MAX_NB_SUBFR / 2); + + /* New (sub)frame length */ + m_channel_state[n].subfr_length = silk_SMULBB(SUB_FRAME_LENGTH_MS, fs_kHz); + frame_length = silk_SMULBB(m_channel_state[n].nb_subfr, m_channel_state[n].subfr_length); + + /* Initialize resampler when switching internal or external sampling frequency */ + if (m_channel_state[n].fs_kHz != fs_kHz || m_channel_state[n].fs_API_hz != fs_API_Hz) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + + ret += silk_resampler_init(n, silk_SMULBB(fs_kHz, 1000), fs_API_Hz, 0); + + m_channel_state[n].fs_API_hz = fs_API_Hz; + } + + if (m_channel_state[n].fs_kHz != fs_kHz || frame_length != m_channel_state[n].frame_length) { + if (fs_kHz == 8) { + if (m_channel_state[n].nb_subfr == MAX_NB_SUBFR) { + m_channel_state[n].pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + m_channel_state[n].pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if (m_channel_state[n].nb_subfr == MAX_NB_SUBFR) { + m_channel_state[n].pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + m_channel_state[n].pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if (m_channel_state[n].fs_kHz != fs_kHz) { + m_channel_state[n].ltp_mem_length = silk_SMULBB(LTP_MEM_LENGTH_MS, fs_kHz); + if (fs_kHz == 8 || fs_kHz == 12) { + m_channel_state[n].LPC_order = MIN_LPC_ORDER; + m_channel_state[n].psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + m_channel_state[n].LPC_order = MAX_LPC_ORDER; + m_channel_state[n].psNLSF_CB = &silk_NLSF_CB_WB; + } + if (fs_kHz == 16) { + m_channel_state[n].pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if (fs_kHz == 12) { + m_channel_state[n].pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if (fs_kHz == 8) { + m_channel_state[n].pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + assert(0); + } + m_channel_state[n].first_frame_after_reset = 1; + m_channel_state[n].lagPrev = 100; + m_channel_state[n].LastGainIndex = 10; + m_channel_state[n].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + memset(m_channel_state[n].outBuf, 0, sizeof(m_channel_state[n].outBuf)); + memset(m_channel_state[n].sLPC_Q14_buf, 0, sizeof(m_channel_state[n].sLPC_Q14_buf)); + } + + m_channel_state[n].fs_kHz = fs_kHz; + m_channel_state[n].frame_length = frame_length; + } + + /* Check that settings are valid */ + assert(m_channel_state[n].frame_length > 0 && m_channel_state[n].frame_length <= MAX_FRAME_LENGTH); + + return ret; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Encode quantization indices of excitation */ +int32_t SilkDecoder::combine_and_check( /* return ok */ + int32_t* pulses_comb, /* O */ + const int32_t* pulses_in, /* I */ + int32_t max_pulses, /* I max value for sum of pulses */ + int32_t len /* I number of output values */ +) { + int32_t k, sum; + + for (k = 0; k < len; k++) { + sum = pulses_in[2 * k] + pulses_in[2 * k + 1]; + if (sum > max_pulses) { return 1; } + pulses_comb[k] = sum; + } + + return 0; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_quant_LTP_gains(int16_t B_Q14[MAX_NB_SUBFR * LTP_ORDER], /* O Quantized LTP gains */ + int8_t cbk_index[MAX_NB_SUBFR], /* O Codebook Index */ + int8_t* periodicity_index, /* O Periodicity Index */ + int32_t* sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + int32_t* pred_gain_dB_Q7, /* O LTP prediction gain */ + const int32_t XX_Q17[MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER], /* I Correlation matrix in Q18 */ + const int32_t xX_Q17[MAX_NB_SUBFR * LTP_ORDER], /* I Correlation vector in Q18 */ + const int32_t subfr_len, /* I Number of samples per subframe */ + const int32_t nb_subfr /* I Number of subframes */ +) { + int32_t j, k, cbk_size; + int8_t temp_idx[MAX_NB_SUBFR]; + const uint8_t* cl_ptr_Q5; + const int8_t* cbk_ptr_Q7; + const uint8_t* cbk_gain_ptr_Q7; + const int32_t *XX_Q17_ptr, *xX_Q17_ptr; + int32_t res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7; + int32_t sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7; + int32_t gain_Q7; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q7 = silk_int32_MAX; + best_sum_log_gain_Q7 = 0; + for (k = 0; k < 3; k++) { + /* Safety margin for pitch gain control, to take into account factors + such as state rescaling/rewhitening. */ + int32_t gain_safety = SILK_FIX_CONST(0.4, 7); + + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[k]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[k]; + cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[k]; + cbk_size = silk_LTP_vq_sizes[k]; + + /* Set up pointers to first subframe */ + XX_Q17_ptr = XX_Q17; + xX_Q17_ptr = xX_Q17; + + res_nrg_Q15 = 0; + rate_dist_Q7 = 0; + sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; + for (j = 0; j < nb_subfr; j++) { + max_gain_Q7 = silk_log2lin((SILK_FIX_CONST(MAX_SUM_LOG_GAIN_DB / 6.0L, 7) - sum_log_gain_tmp_Q7) + SILK_FIX_CONST(7, 7)) - gain_safety; + silk_VQ_WMat_EC(&temp_idx[j], /* O index of best codebook vector */ + &res_nrg_Q15_subfr, /* O residual energy */ + &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */ + &gain_Q7, /* O sum of absolute LTP coefficients */ + XX_Q17_ptr, /* I correlation matrix */ + xX_Q17_ptr, /* I correlation vector */ + cbk_ptr_Q7, /* I codebook */ + cbk_gain_ptr_Q7, /* I codebook effective gains */ + cl_ptr_Q5, /* I code length for each codebook vector */ + subfr_len, /* I number of samples per subframe */ + max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + cbk_size /* I number of vectors in codebook */ + ); + + res_nrg_Q15 = silk_ADD_POS_SAT32(res_nrg_Q15, res_nrg_Q15_subfr); + rate_dist_Q7 = silk_ADD_POS_SAT32(rate_dist_Q7, rate_dist_Q7_subfr); + sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + silk_lin2log(gain_safety + gain_Q7) - SILK_FIX_CONST(7, 7)); + + XX_Q17_ptr += LTP_ORDER * LTP_ORDER; + xX_Q17_ptr += LTP_ORDER; + } + + if (rate_dist_Q7 <= min_rate_dist_Q7) { + min_rate_dist_Q7 = rate_dist_Q7; + *periodicity_index = (int8_t)k; + memcpy(cbk_index, temp_idx, nb_subfr * sizeof(int8_t)); + best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[*periodicity_index]; + for (j = 0; j < nb_subfr; j++) { + for (k = 0; k < LTP_ORDER; k++) { B_Q14[j * LTP_ORDER + k] = silk_LSHIFT(cbk_ptr_Q7[cbk_index[j] * LTP_ORDER + k], 7); } + } + + if (nb_subfr == 2) { + res_nrg_Q15 = silk_RSHIFT32(res_nrg_Q15, 1); + } else { + res_nrg_Q15 = silk_RSHIFT32(res_nrg_Q15, 2); + } + + *sum_log_gain_Q7 = best_sum_log_gain_Q7; + *pred_gain_dB_Q7 = (int32_t)silk_SMULBB(-3, silk_lin2log(res_nrg_Q15) - (15 << 7)); +} +//---------------------------------------------------------------------------------------------------------------------- +void SilkDecoder::decode_split(int16_t* p_child1, /* O pulse amplitude of first child subframe */ + int16_t* p_child2, /* O pulse amplitude of second child subframe */ + const int32_t p, /* I pulse amplitude of current subframe */ + const uint8_t* shell_table /* I table of shell cdfs */ +) { + if (p > 0) { + p_child1[0] = rd.dec_icdf(&shell_table[silk_shell_code_table_offsets[p]], 8); + p_child2[0] = p - p_child1[0]; + } else { + p_child1[0] = 0; + p_child2[0] = 0; + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void SilkDecoder::silk_shell_decoder(int16_t* pulses0, /* O data: nonnegative pulse amplitudes */ + const int32_t pulses4 /* I number of pulses per pulse-subframe */ +) { + int16_t pulses3[2], pulses2[4], pulses1[8]; + + /* this function operates on one shell code frame of 16 pulses */ + assert(SHELL_CODEC_FRAME_LENGTH == 16); + decode_split(&pulses3[0], &pulses3[1], pulses4, silk_shell_code_table3); + decode_split(&pulses2[0], &pulses2[1], pulses3[0], silk_shell_code_table2); + decode_split(&pulses1[0], &pulses1[1], pulses2[0], silk_shell_code_table1); + decode_split(&pulses0[0], &pulses0[1], pulses1[0], silk_shell_code_table0); + decode_split(&pulses0[2], &pulses0[3], pulses1[1], silk_shell_code_table0); + decode_split(&pulses1[2], &pulses1[3], pulses2[1], silk_shell_code_table1); + decode_split(&pulses0[4], &pulses0[5], pulses1[2], silk_shell_code_table0); + decode_split(&pulses0[6], &pulses0[7], pulses1[3], silk_shell_code_table0); + decode_split(&pulses2[2], &pulses2[3], pulses3[1], silk_shell_code_table2); + decode_split(&pulses1[4], &pulses1[5], pulses2[2], silk_shell_code_table1); + decode_split(&pulses0[8], &pulses0[9], pulses1[4], silk_shell_code_table0); + decode_split(&pulses0[10], &pulses0[11], pulses1[5], silk_shell_code_table0); + decode_split(&pulses1[6], &pulses1[7], pulses2[3], silk_shell_code_table1); + decode_split(&pulses0[12], &pulses0[13], pulses1[6], silk_shell_code_table0); + decode_split(&pulses0[14], &pulses0[15], pulses1[7], silk_shell_code_table0); +} +//---------------------------------------------------------------------------------------------------------------------- +/* Quantize mid/side predictors */ +void SilkDecoder::silk_stereo_quant_pred(int32_t pred_Q13[], /* I/O Predictors (out: quantized) */ + int8_t ix[2][3] /* O Quantization indices */ +) { + int32_t i, j, n; + int32_t low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for (n = 0; n < 2; n++) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for (i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++) { + low_Q13 = silk_stereo_pred_quant_Q13[i]; + step_Q13 = silk_SMULWB(silk_stereo_pred_quant_Q13[i + 1] - low_Q13, SILK_FIX_CONST(0.5 / STEREO_QUANT_SUB_STEPS, 16)); + for (j = 0; j < STEREO_QUANT_SUB_STEPS; j++) { + lvl_Q13 = silk_SMLABB(low_Q13, step_Q13, 2 * j + 1); + err_Q13 = silk_abs(pred_Q13[n] - lvl_Q13); + if (err_Q13 < err_min_Q13) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[n][0] = i; + ix[n][1] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[n][2] = silk_DIV32_16(ix[n][0], 3); + ix[n][0] -= ix[n][2] * 3; + pred_Q13[n] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[0] -= pred_Q13[1]; +} +//---------------------------------------------------------------------------------------------------------------------- +/* Helper function, interpolates the filter taps */ +void SilkDecoder::silk_LP_interpolate_filter_taps(int32_t B_Q28[TRANSITION_NB], int32_t A_Q28[TRANSITION_NA], const int32_t ind, const int32_t fac_Q16) { + int32_t nb, na; + + if (ind < TRANSITION_INT_NUM - 1) { + if (fac_Q16 > 0) { + if (fac_Q16 < 32768) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for (nb = 0; nb < TRANSITION_NB; nb++) { + B_Q28[nb] = silk_SMLAWB(silk_Transition_LP_B_Q28[ind][nb], silk_Transition_LP_B_Q28[ind + 1][nb] - silk_Transition_LP_B_Q28[ind][nb], fac_Q16); + } + for (na = 0; na < TRANSITION_NA; na++) { + A_Q28[na] = silk_SMLAWB(silk_Transition_LP_A_Q28[ind][na], silk_Transition_LP_A_Q28[ind + 1][na] - silk_Transition_LP_A_Q28[ind][na], fac_Q16); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + assert(fac_Q16 - (1 << 16) == silk_SAT16(fac_Q16 - (1 << 16))); + /* Piece-wise linear interpolation of B and A */ + for (nb = 0; nb < TRANSITION_NB; nb++) { + B_Q28[nb] = silk_SMLAWB(silk_Transition_LP_B_Q28[ind + 1][nb], silk_Transition_LP_B_Q28[ind + 1][nb] - silk_Transition_LP_B_Q28[ind][nb], fac_Q16 - ((int32_t)1 << 16)); + } + for (na = 0; na < TRANSITION_NA; na++) { + A_Q28[na] = silk_SMLAWB(silk_Transition_LP_A_Q28[ind + 1][na], silk_Transition_LP_A_Q28[ind + 1][na] - silk_Transition_LP_A_Q28[ind][na], fac_Q16 - ((int32_t)1 << 16)); + } + } + } else { + memcpy(B_Q28, silk_Transition_LP_B_Q28[ind], TRANSITION_NB * sizeof(int32_t)); + memcpy(A_Q28, silk_Transition_LP_A_Q28[ind], TRANSITION_NA * sizeof(int32_t)); + } + } else { + memcpy(B_Q28, silk_Transition_LP_B_Q28[TRANSITION_INT_NUM - 1], TRANSITION_NB * sizeof(int32_t)); + memcpy(A_Q28, silk_Transition_LP_A_Q28[TRANSITION_INT_NUM - 1], TRANSITION_NA * sizeof(int32_t)); + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void SilkDecoder::silk_LP_variable_cutoff(silk_LP_state_t* psLP, /* I/O LP filter state */ + int16_t* frame, /* I/O Low-pass filtered output signal */ + const int32_t frame_length /* I Frame length */ +) { + int32_t B_Q28[TRANSITION_NB], A_Q28[TRANSITION_NA], fac_Q16 = 0; + int32_t ind = 0; + + assert(psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES); + + /* Run filter if needed */ + if (psLP->mode != 0) { + /* Calculate index and interpolation factor for interpolation */ +#if (TRANSITION_INT_STEPS == 64) + fac_Q16 = silk_LSHIFT(TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6); +#else + fac_Q16 = silk_DIV32_16(silk_LSHIFT(TRANSITION_FRAMES - psLP->transition_frame_no, 16), TRANSITION_FRAMES); +#endif + ind = silk_RSHIFT(fac_Q16, 16); + fac_Q16 -= silk_LSHIFT(ind, 16); + + assert(ind >= 0); + assert(ind < TRANSITION_INT_NUM); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps(B_Q28, A_Q28, ind, fac_Q16); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT(psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES); + + /* ARMA low-pass filtering */ + assert(TRANSITION_NB == 3 && TRANSITION_NA == 2); + silk_biquad_alt_stride1(frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length); + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Generates excitation for CNG LPC synthesis */ +void SilkDecoder::silk_CNG_exc(int32_t exc_Q14[], /* O CNG excitation signal Q10 */ + int32_t exc_buf_Q14[], /* I Random samples buffer Q10 */ + int32_t length, /* I Length */ + int32_t* rand_seed /* I/O Seed to random index generator */ +) { + int32_t seed; + int32_t i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while (exc_mask > length) { exc_mask = silk_RSHIFT(exc_mask, 1); } + + seed = *rand_seed; + for (i = 0; i < length; i++) { + seed = silk_RAND(seed); + idx = (int32_t)(silk_RSHIFT(seed, 24) & exc_mask); + assert(idx >= 0); + assert(idx <= CNG_BUF_MASK_MAX); + exc_Q14[i] = exc_buf_Q14[idx]; + } + *rand_seed = seed; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_CNG_Reset(uint8_t n) { + int32_t i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16(silk_int16_MAX, m_channel_state[n].LPC_order + 1); + NLSF_acc_Q15 = 0; + for (i = 0; i < m_channel_state[n].LPC_order; i++) { + NLSF_acc_Q15 += NLSF_step_Q15; + m_channel_state[n].sCNG.CNG_smth_NLSF_Q15[i] = NLSF_acc_Q15; + } + m_channel_state[n].sCNG.CNG_smth_Gain_Q16 = 0; + m_channel_state[n].sCNG.rand_seed = 3176576; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void SilkDecoder::silk_CNG(uint8_t n, int16_t frame[], int32_t length) { + int32_t i, subfr; + int32_t LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10; + int16_t A_Q12[MAX_LPC_ORDER]; + silk_CNG_struct_t* psCNG = &m_channel_state[n].sCNG; + + if (m_channel_state[n].fs_kHz != psCNG->fs_kHz) { + /* Reset state */ + silk_CNG_Reset(n); + + psCNG->fs_kHz = m_channel_state[n].fs_kHz; + } + if (m_channel_state[n].lossCnt == 0 && m_channel_state[n].prevSignalType == TYPE_NO_VOICE_ACTIVITY) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for (i = 0; i < m_channel_state[n].LPC_order; i++) { + psCNG->CNG_smth_NLSF_Q15[i] += silk_SMULWB((int32_t)m_channel_state[n].prevNLSF_Q15[i] - (int32_t)psCNG->CNG_smth_NLSF_Q15[i], CNG_NLSF_SMTH_Q16); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for (i = 0; i < m_channel_state[n].nb_subfr; i++) { + if (m_silk_decoder_control->Gains_Q16[i] > max_Gain_Q16) { + max_Gain_Q16 = m_silk_decoder_control->Gains_Q16[i]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + memmove(&psCNG->CNG_exc_buf_Q14[m_channel_state[n].subfr_length], psCNG->CNG_exc_buf_Q14, (m_channel_state[n].nb_subfr - 1) * m_channel_state[n].subfr_length * sizeof(int32_t)); + memcpy(psCNG->CNG_exc_buf_Q14, &m_channel_state[n].exc_Q14[subfr * m_channel_state[n].subfr_length], m_channel_state[n].subfr_length * sizeof(int32_t)); + + /* Smooth gains */ + for (i = 0; i < m_channel_state[n].nb_subfr; i++) { psCNG->CNG_smth_Gain_Q16 += silk_SMULWB(m_silk_decoder_control->Gains_Q16[i] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16); } + } + /* Add CNG when packet is lost or during DTX */ + if (m_channel_state[n].lossCnt) { + ps_ptr CNG_sig_Q14; + CNG_sig_Q14.alloc_array(length + MAX_LPC_ORDER); + + /* Generate CNG excitation */ + gain_Q16 = silk_SMULWW(m_channel_state[n].sPLC.randScale_Q14, m_channel_state[n].sPLC.prevGain_Q16[1]); + if (gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23)) { + gain_Q16 = silk_SMULTT(gain_Q16, gain_Q16); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT(psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16), gain_Q16, 5); + gain_Q16 = silk_LSHIFT32(silk_SQRT_APPROX(gain_Q16), 16); + } else { + gain_Q16 = silk_SMULWW(gain_Q16, gain_Q16); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW(psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16), gain_Q16, 5); + gain_Q16 = silk_LSHIFT32(silk_SQRT_APPROX(gain_Q16), 8); + } + gain_Q10 = silk_RSHIFT(gain_Q16, 6); + + silk_CNG_exc(CNG_sig_Q14.get() + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A(A_Q12, psCNG->CNG_smth_NLSF_Q15, m_channel_state[n].LPC_order); + + /* Generate CNG signal, by synthesis filtering */ + memcpy(CNG_sig_Q14.get(), psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof(int32_t)); + assert(m_channel_state[n].LPC_order == 10 || m_channel_state[n].LPC_order == 16); + for (i = 0; i < length; i++) { + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT(m_channel_state[n].LPC_order, 1); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 1], A_Q12[0]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 2], A_Q12[1]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 3], A_Q12[2]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 4], A_Q12[3]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 5], A_Q12[4]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 6], A_Q12[5]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 7], A_Q12[6]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 8], A_Q12[7]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 9], A_Q12[8]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 10], A_Q12[9]); + if (m_channel_state[n].LPC_order == 16) { + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 11], A_Q12[10]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 12], A_Q12[11]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 13], A_Q12[12]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 14], A_Q12[13]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 15], A_Q12[14]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, CNG_sig_Q14[MAX_LPC_ORDER + i - 16], A_Q12[15]); + } + + /* Update states */ + CNG_sig_Q14[MAX_LPC_ORDER + i] = silk_ADD_SAT32(CNG_sig_Q14[MAX_LPC_ORDER + i], silk_LSHIFT_SAT32(LPC_pred_Q10, 4)); + + /* Scale with Gain and add to input signal */ + frame[i] = (int16_t)silk_ADD_SAT16(frame[i], silk_SAT16(silk_RSHIFT_ROUND(silk_SMULWW(CNG_sig_Q14[MAX_LPC_ORDER + i], gain_Q10), 8))); + } + std::ranges::copy(CNG_sig_Q14.span().subspan(length, MAX_LPC_ORDER), psCNG->CNG_synth_state); + // memcpy(psCNG->CNG_synth_state, &CNG_sig_Q14[length], MAX_LPC_ORDER * sizeof(int32_t)); + } else { + memset(psCNG->CNG_synth_state, 0, m_channel_state[n].LPC_order * sizeof(int32_t)); + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Decodes signs of excitation */ +void SilkDecoder::silk_decode_signs(int16_t pulses[], /* I/O pulse signal */ + int32_t length, /* I length of input */ + const int32_t signalType, /* I Signal type */ + const int32_t quantOffsetType, /* I Quantization offset type */ + const int32_t sum_pulses[MAX_NB_SHELL_BLOCKS] /* I Sum of absolute pulses per block */ +) { + int32_t i, j, p; + uint8_t icdf[2]; + int16_t* q_ptr; + const uint8_t* icdf_ptr; + + icdf[1] = 0; + q_ptr = pulses; + i = silk_SMULBB(7, silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); + icdf_ptr = &silk_sign_iCDF[i]; + length = silk_RSHIFT(length + SHELL_CODEC_FRAME_LENGTH / 2, LOG2_SHELL_CODEC_FRAME_LENGTH); + for (i = 0; i < length; i++) { + p = sum_pulses[i]; + if (p > 0) { + icdf[0] = icdf_ptr[silk_min(p & 0x1F, 6)]; + for (j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++) { + if (q_ptr[j] > 0) { + /* attach sign */ + /* implementation with shift, subtraction, multiplication */ + q_ptr[j] *= silk_dec_map(rd.dec_icdf(icdf, 8)); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_setRawParams(uint8_t channels, uint8_t API_channels, uint8_t payloadSize_ms, uint32_t internalSampleRate, uint32_t API_samleRate) { + m_channelsInternal = channels; + m_API_channels = API_channels; + m_payloadSize_ms = payloadSize_ms; + m_silk_internalSampleRate = internalSampleRate; + m_API_sampleRate = API_samleRate; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t SilkDecoder::silk_getPrevPitchLag() { + return m_prevPitchLag; +} +//---------------------------------------------------------------------------------------------------------------------- +/* Decode a frame */ +int32_t SilkDecoder::silk_Decode(/* O Returns error code */ + + int32_t lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + int32_t newPacketFlag, /* I Indicates first decoder call for this packet */ + int16_t* samplesOut, /* O Decoded output speech vector */ + int32_t* nSamplesOut /* O Number of samples decoded */ +) { + + uint8_t n = 0; + int32_t i, decode_only_middle = 0, ret = SILK_NO_ERROR; + int32_t nSamplesOutDec = 0, LBRR_symbol; + int16_t* samplesOut1_tmp[2]; + int32_t MS_pred_Q13[2] = {0}; + int16_t* resample_out_ptr; + // silk_decoder_state_t *m_channel_state = m_channel_state; + int32_t has_side; + int32_t stereo_to_mono; + int delay_stack_alloc; + + assert(m_silk_DecControlStruct->nChannelsInternal == 1 || m_silk_DecControlStruct->nChannelsInternal == 2); + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if (newPacketFlag) { + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { m_channel_state[n].nFramesDecoded = 0; /* Used to count frames in packet */ } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if (m_silk_DecControlStruct->nChannelsInternal > m_silk_decoder.get()->nChannelsInternal) { ret += silk_init_decoder(1); } + + stereo_to_mono = m_silk_DecControlStruct->nChannelsInternal == 1 && m_silk_decoder.get()->nChannelsInternal == 2 && (m_silk_internalSampleRate == 1000 * m_channel_state[0].fs_kHz); + + if (m_channel_state[0].nFramesDecoded == 0) { + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { + int32_t fs_kHz_dec; + if (m_payloadSize_ms == 0) { + /* Assuming packet loss, use 10 ms */ + m_channel_state[n].nFramesPerPacket = 1; + m_channel_state[n].nb_subfr = 2; + } else if (m_payloadSize_ms == 10) { + m_channel_state[n].nFramesPerPacket = 1; + m_channel_state[n].nb_subfr = 2; + } else if (m_payloadSize_ms == 20) { + m_channel_state[n].nFramesPerPacket = 1; + m_channel_state[n].nb_subfr = 4; + } else if (m_payloadSize_ms == 40) { + m_channel_state[n].nFramesPerPacket = 2; + m_channel_state[n].nb_subfr = 4; + } else if (m_payloadSize_ms == 60) { + m_channel_state[n].nFramesPerPacket = 3; + m_channel_state[n].nb_subfr = 4; + } else { + OPUS_LOG_ERROR("Opus SILK: invalid frame size"); + return OPUS_BAD_ARG; + } + fs_kHz_dec = (m_silk_internalSampleRate >> 10) + 1; + if (fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16) { + OPUS_LOG_ERROR("Opus SILK, invalid sampling frequency: {}", fs_kHz_dec); + return OPUS_BAD_ARG; + } + ret += silk_decoder_set_fs(n, fs_kHz_dec, m_silk_DecControlStruct->API_sampleRate); + } + } + + if (m_silk_DecControlStruct->nChannelsAPI == 2 && m_silk_DecControlStruct->nChannelsInternal == 2 && (m_silk_decoder->nChannelsAPI == 1 || m_silk_decoder->nChannelsInternal == 1)) { + memset(m_silk_decoder->sStereo.pred_prev_Q13, 0, sizeof(m_silk_decoder->sStereo.pred_prev_Q13)); + memset(m_silk_decoder->sStereo.sSide, 0, sizeof(m_silk_decoder->sStereo.sSide)); + memcpy(&m_resampler_state[n], &m_resampler_state[n], sizeof(silk_resampler_state_struct_t)); + } + m_silk_decoder->nChannelsAPI = m_silk_DecControlStruct->nChannelsAPI; + m_silk_decoder->nChannelsInternal = m_silk_DecControlStruct->nChannelsInternal; + + if (m_silk_DecControlStruct->API_sampleRate > (int32_t)MAX_API_FS_KHZ * 1000 || m_silk_DecControlStruct->API_sampleRate < 8000) { + OPUS_LOG_ERROR("Opus SILK, invalid sampling rate: {}", m_silk_DecControlStruct->API_sampleRate); + ret = OPUS_BAD_ARG; + + return (ret); + } + + if (lostFlag != FLAG_PACKET_LOST && m_channel_state[0].nFramesDecoded == 0) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { + for (i = 0; i < m_channel_state[n].nFramesPerPacket; i++) { m_channel_state[n].VAD_flags[i] = rd.dec_bit_logp(1); } + m_channel_state[n].LBRR_flag = rd.dec_bit_logp(1); + } + /* Decode LBRR flags */ + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { + memset(m_channel_state[n].LBRR_flags, 0, sizeof(m_channel_state[n].LBRR_flags)); + if (m_channel_state[n].LBRR_flag) { + if (m_channel_state[n].nFramesPerPacket == 1) { + m_channel_state[n].LBRR_flags[0] = 1; + } else { + LBRR_symbol = rd.dec_icdf(silk_LBRR_flags_iCDF_ptr[m_channel_state[n].nFramesPerPacket - 2], 8) + 1; + for (i = 0; i < m_channel_state[n].nFramesPerPacket; i++) { m_channel_state[n].LBRR_flags[i] = silk_RSHIFT(LBRR_symbol, i) & 1; } + } + } + } + + if (lostFlag == FLAG_DECODE_NORMAL) { + /* Regular decoding: skip all LBRR data */ + for (i = 0; i < m_channel_state[0].nFramesPerPacket; i++) { + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { + if (m_channel_state[n].LBRR_flags[i]) { + int16_t pulses[MAX_FRAME_LENGTH]; + int32_t condCoding; + + if (m_silk_DecControlStruct->nChannelsInternal == 2 && n == 0) { + silk_stereo_decode_pred(MS_pred_Q13); + if (m_channel_state[1].LBRR_flags[i] == 0) { silk_stereo_decode_mid_only(&decode_only_middle); } + } + /* Use conditional coding if previous frame available */ + if (i > 0 && m_channel_state[n].LBRR_flags[i - 1]) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices(n, i, 1, condCoding); + silk_decode_pulses(pulses, m_channel_state[n].indices.signalType, m_channel_state[n].indices.quantOffsetType, m_channel_state[n].frame_length); + } + } + } + } + } + + /* Get MS predictor index */ + if (m_silk_DecControlStruct->nChannelsInternal == 2) { + if (lostFlag == FLAG_DECODE_NORMAL || (lostFlag == FLAG_DECODE_LBRR && m_channel_state[0].LBRR_flags[m_channel_state[0].nFramesDecoded] == 1)) { + silk_stereo_decode_pred(MS_pred_Q13); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if ((lostFlag == FLAG_DECODE_NORMAL && m_channel_state[1].VAD_flags[m_channel_state[0].nFramesDecoded] == 0) || + (lostFlag == FLAG_DECODE_LBRR && m_channel_state[1].LBRR_flags[m_channel_state[0].nFramesDecoded] == 0)) { + silk_stereo_decode_mid_only(&decode_only_middle); + } else { + decode_only_middle = 0; + } + } else { + for (n = 0; n < 2; n++) { MS_pred_Q13[n] = m_silk_decoder->sStereo.pred_prev_Q13[n]; } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if (m_silk_DecControlStruct->nChannelsInternal == 2 && decode_only_middle == 0 && m_silk_decoder->prev_decode_only_middle == 1) { + memset(m_channel_state[1].outBuf, 0, sizeof(m_channel_state[1].outBuf)); + memset(m_channel_state[1].sLPC_Q14_buf, 0, sizeof(m_channel_state[1].sLPC_Q14_buf)); + m_channel_state[1].lagPrev = 100; + m_channel_state[1].LastGainIndex = 10; + m_channel_state[1].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + m_channel_state[1].first_frame_after_reset = 1; + } + + /* Check if the temp buffer fits into the output PCM buffer. If it fits, + we can delay allocating the temp buffer until after the SILK peak stack + usage. We need to use a < and not a <= because of the two extra samples. */ + delay_stack_alloc = m_silk_DecControlStruct->internalSampleRate * m_silk_DecControlStruct->nChannelsInternal < m_silk_DecControlStruct->API_sampleRate * m_silk_DecControlStruct->nChannelsAPI; + + size_t samplesOut1_tmp_storage1_len = delay_stack_alloc ? SILK_ALLOC_NONE : m_silk_DecControlStruct->nChannelsInternal * (m_channel_state[0].frame_length + 2); + ps_ptr samplesOut1_tmp_storage1; + samplesOut1_tmp_storage1.alloc_array(samplesOut1_tmp_storage1_len); + + if (delay_stack_alloc) { + samplesOut1_tmp[0] = samplesOut; + samplesOut1_tmp[1] = samplesOut + m_channel_state[0].frame_length + 2; + } else { + samplesOut1_tmp[0] = samplesOut1_tmp_storage1.get(); + samplesOut1_tmp[1] = samplesOut1_tmp_storage1.get() + m_channel_state[0].frame_length + 2; + } + + if (lostFlag == FLAG_DECODE_NORMAL) { + has_side = !decode_only_middle; + } else { + has_side = !m_silk_decoder->prev_decode_only_middle || + (m_silk_DecControlStruct->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && m_channel_state[1].LBRR_flags[m_channel_state[1].nFramesDecoded] == 1); + } + /* Call decoder for one frame */ + for (n = 0; n < m_silk_DecControlStruct->nChannelsInternal; n++) { + if (n == 0 || has_side) { + int32_t FrameIndex; + int32_t condCoding; + + FrameIndex = m_channel_state[0].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if (FrameIndex <= 0) { + condCoding = CODE_INDEPENDENTLY; + } else if (lostFlag == FLAG_DECODE_LBRR) { + condCoding = m_channel_state[n].LBRR_flags[FrameIndex - 1] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if (n > 0 && m_silk_decoder->prev_decode_only_middle) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame(n, &samplesOut1_tmp[n][2], &nSamplesOutDec, lostFlag, condCoding); + } else { + memset(&samplesOut1_tmp[n][2], 0, nSamplesOutDec * sizeof(int16_t)); + } + m_channel_state[n].nFramesDecoded++; + } + + if (m_silk_DecControlStruct->nChannelsAPI == 2 && m_silk_DecControlStruct->nChannelsInternal == 2) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR(&m_silk_decoder->sStereo, samplesOut1_tmp[0], samplesOut1_tmp[1], MS_pred_Q13, m_channel_state[0].fs_kHz, nSamplesOutDec); + } else { + /* Buffering */ + memcpy(samplesOut1_tmp[0], m_silk_decoder->sStereo.sMid, 2 * sizeof(int16_t)); + memcpy(m_silk_decoder->sStereo.sMid, &samplesOut1_tmp[0][nSamplesOutDec], 2 * sizeof(int16_t)); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32(nSamplesOutDec * m_silk_DecControlStruct->API_sampleRate, silk_SMULBB(m_channel_state[0].fs_kHz, 1000)); + + /* Set up pointers to temp buffers */ + size_t samplesOut2_tmp_len = m_silk_DecControlStruct->nChannelsAPI == 2 ? *nSamplesOut : SILK_ALLOC_NONE; + ps_ptr samplesOut2_tmp; + samplesOut2_tmp.alloc_array(samplesOut2_tmp_len); + + if (m_silk_DecControlStruct->nChannelsAPI == 2) { + resample_out_ptr = samplesOut2_tmp.get(); + } else { + resample_out_ptr = samplesOut; + } + + size_t samplesOut1_tmp_storage2_len = delay_stack_alloc ? m_silk_DecControlStruct->nChannelsInternal * (m_channel_state[0].frame_length + 2) : SILK_ALLOC_NONE; + ps_ptr samplesOut1_tmp_storage2; + samplesOut1_tmp_storage2.alloc_array(samplesOut1_tmp_storage2_len); + + if (delay_stack_alloc) { + // size_t val1 = m_silk_DecControlStruct->nChannelsInternal * (m_channel_state[0].frame_length + 2); + size_t val2 = samplesOut1_tmp_storage2_len * sizeof(int16_t); + // size_t n = val1 * val2; + memcpy(samplesOut1_tmp_storage2.get(), samplesOut, val2); + samplesOut1_tmp[0] = samplesOut1_tmp_storage2.get(); + samplesOut1_tmp[1] = samplesOut1_tmp_storage2.get() + m_channel_state[0].frame_length + 2; + } + for (n = 0; n < silk_min(m_silk_DecControlStruct->nChannelsAPI, m_silk_DecControlStruct->nChannelsInternal); n++) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler(n, resample_out_ptr, &samplesOut1_tmp[n][1], nSamplesOutDec); + + /* Interleave if stereo output and stereo stream */ + if (m_silk_DecControlStruct->nChannelsAPI == 2) { + for (i = 0; i < *nSamplesOut; i++) { samplesOut[n + 2 * i] = resample_out_ptr[i]; } + } + } + /* Create two channel output from mono stream */ + if (m_silk_DecControlStruct->nChannelsAPI == 2 && m_silk_DecControlStruct->nChannelsInternal == 1) { + if (stereo_to_mono) { + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler(n, resample_out_ptr, &samplesOut1_tmp[0][1], nSamplesOutDec); + + for (i = 0; i < *nSamplesOut; i++) { samplesOut[1 + 2 * i] = resample_out_ptr[i]; } + } else { + for (i = 0; i < *nSamplesOut; i++) { samplesOut[1 + 2 * i] = samplesOut[0 + 2 * i]; } + } + } + /* Export pitch lag, measured at 48 kHz sampling rate */ + if (m_channel_state[0].prevSignalType == TYPE_VOICED) { + int mult_tab[3] = {6, 4, 3}; + m_silk_DecControlStruct->prevPitchLag = m_channel_state[0].lagPrev * mult_tab[(m_channel_state[0].fs_kHz - 8) >> 2]; + } else { + m_silk_DecControlStruct->prevPitchLag = 0; + } + + if (lostFlag == FLAG_PACKET_LOST) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for (i = 0; i < m_silk_decoder->nChannelsInternal; i++) m_channel_state[i].LastGainIndex = 10; + } else { + m_silk_decoder->prev_decode_only_middle = decode_only_middle; + } + return ret; +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Decoder functions */ +int32_t SilkDecoder::silk_Get_Decoder_Size(int32_t* decSizeBytes) { + int32_t ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof(silk_decoder_t) + sizeof(silk_decoder_state_t); + + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Reset decoder state */ +int32_t SilkDecoder::silk_InitDecoder() { + int32_t n, ret = SILK_NO_ERROR; + // m_channel_state = (silk_decoder_state_t*) &decState->m_channel_state; + + for (n = 0; n < DECODER_NUM_CHANNELS; n++) { ret = silk_init_decoder(n); } + memset(&m_silk_decoder->sStereo, 0, sizeof(m_silk_decoder->sStereo)); + m_silk_decoder->prev_decode_only_middle = 0; + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void SilkDecoder::silk_decode_core(uint8_t n, int16_t xq[], const int16_t pulses[MAX_FRAME_LENGTH]) { + int32_t i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + int16_t *A_Q12, *B_Q14, *pxq, A_Q12_tmp[MAX_LPC_ORDER]; + int32_t LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + int32_t *pred_lag_ptr, *pexc_Q14, *pres_Q14; + + assert(m_channel_state[n].prev_gain_Q16 != 0); + + ps_ptr sLTP; + sLTP.alloc_array(m_channel_state[n].ltp_mem_length); + ps_ptr sLTP_Q15; + sLTP_Q15.alloc_array(m_channel_state[n].ltp_mem_length + m_channel_state[n].frame_length); + ps_ptr res_Q14; + res_Q14.alloc_array(m_channel_state[n].subfr_length); + ps_ptr sLPC_Q14; + sLPC_Q14.alloc_array(m_channel_state[n].subfr_length + MAX_LPC_ORDER); + + offset_Q10 = silk_Quantization_Offsets_Q10[m_channel_state[n].indices.signalType >> 1][m_channel_state[n].indices.quantOffsetType]; + + if (m_channel_state[n].indices.NLSFInterpCoef_Q2 < 1 << 2) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = m_channel_state[n].indices.Seed; + for (i = 0; i < m_channel_state[n].frame_length; i++) { + rand_seed = silk_RAND(rand_seed); + m_channel_state[n].exc_Q14[i] = silk_LSHIFT((int32_t)pulses[i], 14); + if (m_channel_state[n].exc_Q14[i] > 0) { + m_channel_state[n].exc_Q14[i] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else if (m_channel_state[n].exc_Q14[i] < 0) { + m_channel_state[n].exc_Q14[i] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + m_channel_state[n].exc_Q14[i] += offset_Q10 << 4; + if (rand_seed < 0) { m_channel_state[n].exc_Q14[i] = -m_channel_state[n].exc_Q14[i]; } + + rand_seed = silk_ADD32_ovflw(rand_seed, pulses[i]); + } + + /* Copy LPC state */ + memcpy(sLPC_Q14.get(), m_channel_state[n].sLPC_Q14_buf, MAX_LPC_ORDER * sizeof(int32_t)); + + pexc_Q14 = m_channel_state[n].exc_Q14; + pxq = xq; + sLTP_buf_idx = m_channel_state[n].ltp_mem_length; + /* Loop over subframes */ + for (k = 0; k < m_channel_state[n].nb_subfr; k++) { + pres_Q14 = res_Q14.get(); + A_Q12 = m_silk_decoder_control->PredCoef_Q12[k >> 1]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + memcpy(A_Q12_tmp, A_Q12, m_channel_state[n].LPC_order * sizeof(int16_t)); + B_Q14 = &m_silk_decoder_control->LTPCoef_Q14[k * LTP_ORDER]; + signalType = m_channel_state[n].indices.signalType; + + Gain_Q10 = silk_RSHIFT(m_silk_decoder_control->Gains_Q16[k], 6); + inv_gain_Q31 = silk_INVERSE32_varQ(m_silk_decoder_control->Gains_Q16[k], 47); + + /* Calculate gain adjustment factor */ + if (m_silk_decoder_control->Gains_Q16[k] != m_channel_state[n].prev_gain_Q16) { + gain_adj_Q16 = silk_DIV32_varQ(m_channel_state[n].prev_gain_Q16, m_silk_decoder_control->Gains_Q16[k], 16); + + /* Scale short term state */ + for (i = 0; i < MAX_LPC_ORDER; i++) { sLPC_Q14[i] = silk_SMULWW(gain_adj_Q16, sLPC_Q14[i]); } + } else { + gain_adj_Q16 = (int32_t)1 << 16; + } + + /* Save inv_gain */ + assert(inv_gain_Q31 != 0); + m_channel_state[n].prev_gain_Q16 = m_silk_decoder_control->Gains_Q16[k]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if (m_channel_state[n].lossCnt && m_channel_state[n].prevSignalType == TYPE_VOICED && m_channel_state[n].indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR / 2) { + memset(B_Q14, 0, LTP_ORDER * sizeof(int16_t)); + B_Q14[LTP_ORDER / 2] = SILK_FIX_CONST(0.25, 14); + + signalType = TYPE_VOICED; + m_silk_decoder_control->pitchL[k] = m_channel_state[n].lagPrev; + } + + if (signalType == TYPE_VOICED) { + /* Voiced */ + lag = m_silk_decoder_control->pitchL[k]; + + /* Re-whitening */ + if (k == 0 || (k == 2 && NLSF_interpolation_flag)) { + /* Rewhiten with new A coefs */ + start_idx = m_channel_state[n].ltp_mem_length - lag - m_channel_state[n].LPC_order - LTP_ORDER / 2; + assert(start_idx > 0); + + if (k == 2) { memcpy(&m_channel_state[n].outBuf[m_channel_state[n].ltp_mem_length], xq, 2 * m_channel_state[n].subfr_length * sizeof(int16_t)); } + + silk_LPC_analysis_filter(&sLTP[start_idx], &m_channel_state[n].outBuf[start_idx + k * m_channel_state[n].subfr_length], A_Q12, m_channel_state[n].ltp_mem_length - start_idx, + m_channel_state[n].LPC_order); + + /* After rewhitening the LTP state is unscaled */ + if (k == 0) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT(silk_SMULWB(inv_gain_Q31, m_silk_decoder_control->LTP_scale_Q14), 2); + } + for (i = 0; i < lag + LTP_ORDER / 2; i++) { sLTP_Q15[sLTP_buf_idx - i - 1] = silk_SMULWB(inv_gain_Q31, sLTP[m_channel_state[n].ltp_mem_length - i - 1]); } + } else { + /* Update LTP state when Gain changes */ + if (gain_adj_Q16 != (int32_t)1 << 16) { + for (i = 0; i < lag + LTP_ORDER / 2; i++) { sLTP_Q15[sLTP_buf_idx - i - 1] = silk_SMULWW(gain_adj_Q16, sLTP_Q15[sLTP_buf_idx - i - 1]); } + } + } + } + + /* Long-term prediction */ + if (signalType == TYPE_VOICED) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[sLTP_buf_idx - lag + LTP_ORDER / 2]; + for (i = 0; i < m_channel_state[n].subfr_length; i++) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB(LTP_pred_Q13, pred_lag_ptr[0], B_Q14[0]); + LTP_pred_Q13 = silk_SMLAWB(LTP_pred_Q13, pred_lag_ptr[-1], B_Q14[1]); + LTP_pred_Q13 = silk_SMLAWB(LTP_pred_Q13, pred_lag_ptr[-2], B_Q14[2]); + LTP_pred_Q13 = silk_SMLAWB(LTP_pred_Q13, pred_lag_ptr[-3], B_Q14[3]); + LTP_pred_Q13 = silk_SMLAWB(LTP_pred_Q13, pred_lag_ptr[-4], B_Q14[4]); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[i] = silk_ADD_LSHIFT32(pexc_Q14[i], LTP_pred_Q13, 1); + + /* Update states */ + sLTP_Q15[sLTP_buf_idx] = silk_LSHIFT(pres_Q14[i], 1); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for (i = 0; i < m_channel_state[n].subfr_length; i++) { + /* Short-term prediction */ + assert(m_channel_state[n].LPC_order == 10 || m_channel_state[n].LPC_order == 16); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT(m_channel_state[n].LPC_order, 1); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 1], A_Q12_tmp[0]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 2], A_Q12_tmp[1]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 3], A_Q12_tmp[2]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 4], A_Q12_tmp[3]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 5], A_Q12_tmp[4]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 6], A_Q12_tmp[5]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 7], A_Q12_tmp[6]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 8], A_Q12_tmp[7]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 9], A_Q12_tmp[8]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 10], A_Q12_tmp[9]); + if (m_channel_state[n].LPC_order == 16) { + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 11], A_Q12_tmp[10]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 12], A_Q12_tmp[11]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 13], A_Q12_tmp[12]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 14], A_Q12_tmp[13]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 15], A_Q12_tmp[14]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[MAX_LPC_ORDER + i - 16], A_Q12_tmp[15]); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[MAX_LPC_ORDER + i] = silk_ADD_SAT32(pres_Q14[i], silk_LSHIFT_SAT32(LPC_pred_Q10, 4)); + + /* Scale with gain */ + pxq[i] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(silk_SMULWW(sLPC_Q14[MAX_LPC_ORDER + i], Gain_Q10), 8)); + } + + /* Update LPC filter state */ + memcpy(sLPC_Q14.get(), &sLPC_Q14[m_channel_state[n].subfr_length], MAX_LPC_ORDER * sizeof(int32_t)); + pexc_Q14 += m_channel_state[n].subfr_length; + pxq += m_channel_state[n].subfr_length; + } + + /* Save LPC state */ + memcpy(m_channel_state[n].sLPC_Q14_buf, sLPC_Q14.get(), MAX_LPC_ORDER * sizeof(int32_t)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Decode frame */ +int32_t SilkDecoder::silk_decode_frame(uint8_t n, int16_t pOut[], /* O Pointer to output speech frame */ + int32_t* pN, /* O Pointer to size of output frame */ + int32_t lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + int32_t condCoding /* I The type of conditional coding to use */ +) { + int32_t L, mv_len, ret = 0; + L = m_channel_state[n].frame_length; + m_silk_decoder_control->LTP_scale_Q14 = 0; + + /* Safety checks */ + assert(L > 0 && L <= MAX_FRAME_LENGTH); + + if (lostFlag == FLAG_DECODE_NORMAL || (lostFlag == FLAG_DECODE_LBRR && m_channel_state[n].LBRR_flags[m_channel_state[n].nFramesDecoded] == 1)) { + int16_t pulses[(L + SHELL_CODEC_FRAME_LENGTH - 1) & ~(SHELL_CODEC_FRAME_LENGTH - 1)]; + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices(n, m_channel_state[n].nFramesDecoded, lostFlag, condCoding); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses(pulses, m_channel_state[n].indices.signalType, m_channel_state[n].indices.quantOffsetType, m_channel_state[n].frame_length); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters(n, condCoding); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core(n, pOut, pulses); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC(n, pOut, 0); + + m_channel_state[n].lossCnt = 0; + m_channel_state[n].prevSignalType = m_channel_state[n].indices.signalType; + assert(m_channel_state[n].prevSignalType >= 0 && m_channel_state[n].prevSignalType <= 2); + + /* A frame has been decoded without errors */ + m_channel_state[n].first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + m_channel_state[n].indices.signalType = m_channel_state[n].prevSignalType; + silk_PLC(n, pOut, 1); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + assert(m_channel_state[n].ltp_mem_length >= m_channel_state[n].frame_length); + mv_len = m_channel_state[n].ltp_mem_length - m_channel_state[n].frame_length; + memmove(m_channel_state[n].outBuf, &m_channel_state[n].outBuf[m_channel_state[n].frame_length], mv_len * sizeof(int16_t)); + memcpy(&m_channel_state[n].outBuf[mv_len], pOut, m_channel_state[n].frame_length * sizeof(int16_t)); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG(n, pOut, L); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames(n, pOut, L); + + /* Update some decoder state variables */ + m_channel_state[n].lagPrev = m_silk_decoder_control->pitchL[m_channel_state[n].nb_subfr - 1]; + + /* Set output frame length */ + *pN = L; + + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_decode_pitch(int16_t lagIndex, /* I */ + int8_t contourIndex, /* O */ + int32_t pitch_lags[], /* O 4 pitch values */ + const int32_t Fs_kHz, /* I sampling frequency (kHz) */ + const int32_t nb_subfr /* I number of sub frames */ +) { + int32_t lag, k, min_lag, max_lag, cbk_size; + const int8_t* Lag_CB_ptr; + + if (Fs_kHz == 8) { + if (nb_subfr == PE_MAX_NB_SUBFR) { + Lag_CB_ptr = &silk_CB_lags_stage2[0][0]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + assert(nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[0][0]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if (nb_subfr == PE_MAX_NB_SUBFR) { + Lag_CB_ptr = &silk_CB_lags_stage3[0][0]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + assert(nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[0][0]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB(PE_MIN_LAG_MS, Fs_kHz); + max_lag = silk_SMULBB(PE_MAX_LAG_MS, Fs_kHz); + lag = min_lag + lagIndex; + + for (k = 0; k < nb_subfr; k++) { + pitch_lags[k] = lag + matrix_ptr(Lag_CB_ptr, k, contourIndex, cbk_size); + pitch_lags[k] = silk_LIMIT(pitch_lags[k], min_lag, max_lag); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void SilkDecoder::silk_gains_quant(int8_t ind[MAX_NB_SUBFR], /* O gain indices */ + int32_t gain_Q16[MAX_NB_SUBFR], /* I/O gains (quantized out) */ + int8_t* prev_ind, /* I/O last index in previous frame */ + const int32_t conditional, /* I first gain is delta coded if 1 */ + const int32_t nb_subfr /* I number of subframes */ +) { + int32_t k, double_step_size_threshold; + + for (k = 0; k < nb_subfr; k++) { + /* Convert to log scale, scale, floor() */ + ind[k] = silk_SMULWB(SCALE_Q16, silk_lin2log(gain_Q16[k]) - OFFSET); + + /* Round towards previous quantized gain (hysteresis) */ + if (ind[k] < *prev_ind) { ind[k]++; } + ind[k] = silk_LIMIT_int(ind[k], 0, N_LEVELS_QGAIN - 1); + + /* Compute delta indices and limit */ + if (k == 0 && conditional == 0) { + /* Full index */ + ind[k] = silk_LIMIT_int(ind[k], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1); + *prev_ind = ind[k]; + } else { + /* Delta index */ + ind[k] = ind[k] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if (ind[k] > double_step_size_threshold) { ind[k] = double_step_size_threshold + silk_RSHIFT(ind[k] - double_step_size_threshold + 1, 1); } + + ind[k] = silk_LIMIT_int(ind[k], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT); + + /* Accumulate deltas */ + if (ind[k] > double_step_size_threshold) { + *prev_ind += silk_LSHIFT(ind[k], 1) - double_step_size_threshold; + *prev_ind = silk_min_int(*prev_ind, N_LEVELS_QGAIN - 1); + } else { + *prev_ind += ind[k]; + } + + /* Shift to make non-negative */ + ind[k] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[k] = silk_log2lin(silk_min_32(silk_SMULWB(INV_SCALE_Q16, *prev_ind) + OFFSET, 3967)); /* 3967 = 31 in Q7 */ + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Gains scalar dequantization, uniform on log scale */ +void SilkDecoder::silk_gains_dequant(int32_t gain_Q16[MAX_NB_SUBFR], /* O quantized gains */ + const int8_t ind[MAX_NB_SUBFR], /* I gain indices */ + int8_t* prev_ind, /* I/O last index in previous frame */ + const int32_t conditional, /* I first gain is delta coded if 1 */ + const int32_t nb_subfr /* I number of subframes */ +) { + int32_t k, ind_tmp, double_step_size_threshold; + + for (k = 0; k < nb_subfr; k++) { + if (k == 0 && conditional == 0) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int(ind[k], *prev_ind - 16); + } else { + /* Delta index */ + ind_tmp = ind[k] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if (ind_tmp > double_step_size_threshold) { + *prev_ind += silk_LSHIFT(ind_tmp, 1) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int(*prev_ind, 0, N_LEVELS_QGAIN - 1); + + /* Scale and convert to linear scale */ + gain_Q16[k] = silk_log2lin(silk_min_32(silk_SMULWB(INV_SCALE_Q16, *prev_ind) + OFFSET, 3967)); /* 3967 = 31 in Q7 */ + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Compute unique identifier of gain indices vector */ +int32_t SilkDecoder::silk_gains_ID( /* O returns unique identifier of gains */ + const int8_t ind[MAX_NB_SUBFR], /* I gain indices */ + const int32_t nb_subfr /* I number of subframes */ +) { + int32_t k; + int32_t gainsID; + + gainsID = 0; + for (k = 0; k < nb_subfr; k++) { gainsID = silk_ADD_LSHIFT32(ind[k], gainsID, 8); } + + return gainsID; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t SilkDecoder::silk_init_decoder(uint8_t n) { + /* Clear the entire encoder state, except anything copied */ + memset(&m_channel_state[n], 0, sizeof(silk_decoder_state_t)); + + /* Used to deactivate LSF interpolation */ + m_channel_state[n].first_frame_after_reset = 1; + m_channel_state[n].prev_gain_Q16 = 65536; + + /* Reset CNG state */ + silk_CNG_Reset(n); + + /* Reset PLC state */ + silk_PLC_Reset(n); + + return (0); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t SilkDecoder::silk_inner_prod_aligned_scale(const int16_t* const inVec1, /* I input vector 1 */ + const int16_t* const inVec2, /* I input vector 2 */ + const int32_t scale, /* I number of bits to shift */ + const int32_t len /* I vector lengths */ +) { + int32_t i; + int32_t sum = 0; + for (i = 0; i < len; i++) { sum = silk_ADD_RSHIFT32(sum, silk_SMULBB(inVec1[i], inVec2[i]), scale); } + return sum; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Interpolate two vectors */ +void SilkDecoder::silk_interpolate(int16_t xi[MAX_LPC_ORDER], /* O interpolated vector */ + const int16_t x0[MAX_LPC_ORDER], /* I first vector */ + const int16_t x1[MAX_LPC_ORDER], /* I second vector */ + const int32_t ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const int32_t d /* I number of parameters */ +) { + int32_t i; + + assert(ifact_Q2 >= 0); + assert(ifact_Q2 <= 4); + + for (i = 0; i < d; i++) { xi[i] = (int16_t)silk_ADD_RSHIFT(x0[i], silk_SMULBB(x1[i] - x0[i], ifact_Q2), 2); } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +int32_t SilkDecoder::silk_lin2log(const int32_t inLin /* I input in linear scale */ +) { + int32_t lz, frac_Q7; + + silk_CLZ_FRAC(inLin, &lz, &frac_Q7); + + /* Piece-wise parabolic approximation */ + return silk_ADD_LSHIFT32(silk_SMLAWB(frac_Q7, silk_MUL(frac_Q7, 128 - frac_Q7), 179), 31 - lz, 7); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Approximation of 2^() (very close inverse of silk_lin2log()) Convert input to a linear scale */ +int32_t SilkDecoder::silk_log2lin(const int32_t inLog_Q7) { + int32_t out, frac_Q7; + + if (inLog_Q7 < 0) { + return 0; + } else if (inLog_Q7 >= 3967) { + return silk_int32_MAX; + } + + out = silk_LSHIFT(1, silk_RSHIFT(inLog_Q7, 7)); + frac_Q7 = inLog_Q7 & 0x7F; + if (inLog_Q7 < 2048) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32(out, silk_MUL(out, silk_SMLAWB(frac_Q7, silk_SMULBB(frac_Q7, 128 - frac_Q7), -174)), 7); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA(out, silk_RSHIFT(out, 7), silk_SMLAWB(frac_Q7, silk_SMULBB(frac_Q7, 128 - frac_Q7), -174)); + } + return out; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_LPC_analysis_filter(int16_t* out, /* O Output signal */ + const int16_t* in, /* I Input signal */ + const int16_t* B, /* I MA prediction coefficients, Q12 [order] */ + const int32_t len, /* I Signal length */ + const int32_t d /* I Filter order */ +) { + int32_t j; + int ix; + int32_t out32_Q12, out32; + const int16_t* in_ptr; + assert(d >= 6); + assert((d & 1) == 0); + assert(d <= len); + + for (ix = d; ix < len; ix++) { + in_ptr = &in[ix - 1]; + + out32_Q12 = silk_SMULBB(in_ptr[0], B[0]); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-1], B[1]); + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-2], B[2]); + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-3], B[3]); + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-4], B[4]); + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-5], B[5]); + for (j = 6; j < d; j += 2) { + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-j], B[j]); + out32_Q12 = silk_SMLABB_ovflw(out32_Q12, in_ptr[-j - 1], B[j + 1]); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw(silk_LSHIFT((int32_t)in_ptr[1], 12), out32_Q12); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND(out32_Q12, 12); + + /* Saturate output */ + out[ix] = (int16_t)silk_SAT16(out32); + } + + /* Set first d output samples to zero */ + memset(out, 0, d * sizeof(int16_t)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void SilkDecoder::silk_LPC_fit(int16_t* a_QOUT, /* O Output signal */ + int32_t* a_QIN, /* I/O Input signal */ + const int32_t QOUT, /* I Input Q domain */ + const int32_t QIN, /* I Input Q domain */ + const int32_t d /* I Filter order */ +) { + int32_t i, k, idx = 0; + int32_t maxabs, absval, chirp_Q16; + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for (i = 0; i < 10; i++) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for (k = 0; k < d; k++) { + absval = silk_abs(a_QIN[k]); + if (absval > maxabs) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND(maxabs, QIN - QOUT); + + if (maxabs > silk_int16_MAX) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min(maxabs, 163838); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + chirp_Q16 = SILK_FIX_CONST(0.999, 16) - silk_DIV32(silk_LSHIFT(maxabs - silk_int16_MAX, 14), silk_RSHIFT32(silk_MUL(maxabs, idx + 1), 2)); + silk_bwexpander_32(a_QIN, d, chirp_Q16); + } else { + break; + } + } + + if (i == 10) { + /* Reached the last iteration, clip the coefficients */ + for (k = 0; k < d; k++) { + a_QOUT[k] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(a_QIN[k], QIN - QOUT)); + a_QIN[k] = silk_LSHIFT((int32_t)a_QOUT[k], QIN - QOUT); + } + } else { + for (k = 0; k < d; k++) { a_QOUT[k] = (int16_t)silk_RSHIFT_ROUND(a_QIN[k], QIN - QOUT); } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +int32_t SilkDecoder::LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + int32_t A_QA[SILK_MAX_ORDER_LPC], /* I Prediction coefficients */ + const int32_t order /* I Prediction order */ +) { + const uint8_t QA24 = 24; + int32_t k, n, mult2Q; + int32_t invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + + invGain_Q30 = SILK_FIX_CONST(1, 30); + for (k = order - 1; k > 0; k--) { + /* Check for stability */ + if ((A_QA[k] > A_LIMIT) || (A_QA[k] < -A_LIMIT)) { return 0; } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT(A_QA[k], 31 - QA24); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32(SILK_FIX_CONST(1, 30), silk_SMMUL(rc_Q31, rc_Q31)); + assert(rc_mult1_Q30 > (1 << 15)); /* reduce A_LIMIT if fails */ + assert(rc_mult1_Q30 <= (1 << 30)); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT(silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2); + assert(invGain_Q30 >= 0); + assert(invGain_Q30 <= (1 << 30)); + if (invGain_Q30 < SILK_FIX_CONST(1.0f / MAX_PREDICTION_POWER_GAIN, 30)) { return 0; } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32(silk_abs(rc_mult1_Q30)); + rc_mult2 = silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30); + + /* Update AR coefficient */ + for (n = 0; n < (k + 1) >> 1; n++) { + int64_t tmp64; + tmp1 = A_QA[n]; + tmp2 = A_QA[k - n - 1]; + tmp64 = silk_RSHIFT_ROUND64(silk_SMULL(silk_SUB_SAT32(tmp1, MUL32_FRAC_Q(tmp2, rc_Q31, 31)), rc_mult2), mult2Q); + if (tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN) { return 0; } + A_QA[n] = (int32_t)tmp64; + tmp64 = silk_RSHIFT_ROUND64(silk_SMULL(silk_SUB_SAT32(tmp2, MUL32_FRAC_Q(tmp1, rc_Q31, 31)), rc_mult2), mult2Q); + if (tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN) { return 0; } + A_QA[k - n - 1] = (int32_t)tmp64; + } + } + + /* Check for stability */ + if ((A_QA[k] > A_LIMIT) || (A_QA[k] < -A_LIMIT)) { return 0; } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT(A_QA[0], 31 - QA24); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32(SILK_FIX_CONST(1, 30), silk_SMMUL(rc_Q31, rc_Q31)); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT(silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2); + assert(invGain_Q30 >= 0); + assert(invGain_Q30 <= (1 << 30)); + if (invGain_Q30 < SILK_FIX_CONST(1.0f / MAX_PREDICTION_POWER_GAIN, 30)) { return 0; } + + return invGain_Q30; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* For input in Q12 domain */ +int32_t SilkDecoder::silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const int16_t* A_Q12, /* I Prediction coefficients, Q12 [order] */ + const int32_t order /* I Prediction order */ +) { + int32_t k; + int32_t Atmp_QA[SILK_MAX_ORDER_LPC]; + int32_t DC_resp = 0; + const uint32_t QA24 = 24; + + /* Increase Q domain of the AR coefficients */ + for (k = 0; k < order; k++) { + DC_resp += (int32_t)A_Q12[k]; + Atmp_QA[k] = silk_LSHIFT32((int32_t)A_Q12[k], QA24 - 12); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if (DC_resp >= 4096) { return 0; } + return LPC_inverse_pred_gain_QA_c(Atmp_QA, order); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Predictive dequantizer for NLSF residuals */ +void SilkDecoder::silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + int16_t x_Q10[], /* O Output [ order ] */ + const int8_t indices[], /* I Quantization indices [ order ] */ + const uint8_t pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const int32_t quant_step_size_Q16, /* I Quantization step size */ + const int16_t order /* I Number of input values */ +) { + int32_t i, out_Q10, pred_Q10; + + out_Q10 = 0; + for (i = order - 1; i >= 0; i--) { + pred_Q10 = silk_RSHIFT(silk_SMULBB(out_Q10, (int16_t)pred_coef_Q8[i]), 8); + out_Q10 = silk_LSHIFT(indices[i], 10); + if (out_Q10 > 0) { + out_Q10 = silk_SUB16(out_Q10, SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10)); + } else if (out_Q10 < 0) { + out_Q10 = out_Q10 + SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10); + } + out_Q10 = silk_SMLAWB(pred_Q10, (int32_t)out_Q10, quant_step_size_Q16); + x_Q10[i] = out_Q10; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* NLSF vector decoder */ +void SilkDecoder::silk_NLSF_decode(int16_t* pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + int8_t* NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct_t* psNLSF_CB /* I Codebook object */ +) { + int32_t i; + uint8_t pred_Q8[MAX_LPC_ORDER]; + int16_t ec_ix[MAX_LPC_ORDER]; + int16_t res_Q10[MAX_LPC_ORDER]; + int32_t NLSF_Q15_tmp; + const uint8_t* pCB_element; + const int16_t* pCB_Wght_Q9; + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack(ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[0]); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant(res_Q10, &NLSFIndices[1], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order); + + /* Apply inverse square-rooted weights to first stage and add to output */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[NLSFIndices[0] * psNLSF_CB->order]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[NLSFIndices[0] * psNLSF_CB->order]; + for (i = 0; i < psNLSF_CB->order; i++) { + NLSF_Q15_tmp = silk_ADD_LSHIFT32(silk_DIV32_16(silk_LSHIFT((int32_t)res_Q10[i], 14), pCB_Wght_Q9[i]), (int16_t)pCB_element[i], 7); + pNLSF_Q15[i] = (int16_t)silk_LIMIT(NLSF_Q15_tmp, 0, 32767); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Delayed-decision quantizer for NLSF residuals */ +int32_t SilkDecoder::silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + int8_t indices[], /* O Quantization indices [ order ] */ + const int16_t x_Q10[], /* I Input [ order ] */ + const int16_t w_Q5[], /* I Weights [ order ] */ + const uint8_t pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const int16_t ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const uint8_t ec_rates_Q5[], /* I Rates [] */ + const int32_t quant_step_size_Q16, /* I Quantization step size */ + const int16_t inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const int32_t mu_Q20, /* I R/D tradeoff */ + const int16_t order /* I Number of input values */ +) { + int32_t i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + int32_t pred_Q10, diff_Q10, rate0_Q5, rate1_Q5; + int16_t out0_Q10, out1_Q10; + int32_t RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25; + int32_t ind_sort[NLSF_QUANT_DEL_DEC_STATES]; + int8_t ind[NLSF_QUANT_DEL_DEC_STATES][MAX_LPC_ORDER]; + int16_t prev_out_Q10[2 * NLSF_QUANT_DEL_DEC_STATES]; + int32_t RD_Q25[2 * NLSF_QUANT_DEL_DEC_STATES]; + int32_t RD_min_Q25[NLSF_QUANT_DEL_DEC_STATES]; + int32_t RD_max_Q25[NLSF_QUANT_DEL_DEC_STATES]; + const uint8_t* rates_Q5; + + int32_t out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + int32_t out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT - 1; i++) { + out0_Q10 = silk_LSHIFT(i, 10); + out1_Q10 = out0_Q10 + 1024; + if (i > 0) { + out0_Q10 = silk_SUB16(out0_Q10, SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10)); + out1_Q10 = silk_SUB16(out1_Q10, SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10)); + } else if (i == 0) { + out1_Q10 = silk_SUB16(out1_Q10, SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10)); + } else if (i == -1) { + out0_Q10 = out0_Q10 + SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10); + } else { + out0_Q10 = out0_Q10 + SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10); + out1_Q10 = out1_Q10 + SILK_FIX_CONST(NLSF_QUANT_LEVEL_ADJ, 10); + } + out0_Q10_table[i + NLSF_QUANT_MAX_AMPLITUDE_EXT] = silk_RSHIFT(silk_SMULBB(out0_Q10, quant_step_size_Q16), 16); + out1_Q10_table[i + NLSF_QUANT_MAX_AMPLITUDE_EXT] = silk_RSHIFT(silk_SMULBB(out1_Q10, quant_step_size_Q16), 16); + } + + assert((NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES - 1)) == 0); /* must be power of two */ + + nStates = 1; + RD_Q25[0] = 0; + prev_out_Q10[0] = 0; + for (i = order - 1; i >= 0; i--) { + rates_Q5 = &ec_rates_Q5[ec_ix[i]]; + in_Q10 = x_Q10[i]; + for (j = 0; j < nStates; j++) { + pred_Q10 = silk_RSHIFT(silk_SMULBB((int16_t)pred_coef_Q8[i], prev_out_Q10[j]), 8); + res_Q10 = silk_SUB16(in_Q10, pred_Q10); + ind_tmp = silk_RSHIFT(silk_SMULBB(inv_quant_step_size_Q6, res_Q10), 16); + ind_tmp = silk_LIMIT(ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT - 1); + ind[j][i] = (int8_t)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = out0_Q10_table[ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT]; + out1_Q10 = out1_Q10_table[ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + out0_Q10 = out0_Q10 + pred_Q10; + out1_Q10 = out1_Q10 + pred_Q10; + prev_out_Q10[j] = out0_Q10; + prev_out_Q10[j + nStates] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if (ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE) { + if (ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE) { + rate0_Q5 = rates_Q5[ind_tmp + NLSF_QUANT_MAX_AMPLITUDE]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB(280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp); + rate1_Q5 = rate0_Q5 + 43; + } + } else if (ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE) { + if (ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE]; + } else { + rate0_Q5 = silk_SMLABB(280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp); + rate1_Q5 = silk_SUB16(rate0_Q5, 43); + } + } else { + rate0_Q5 = rates_Q5[ind_tmp + NLSF_QUANT_MAX_AMPLITUDE]; + rate1_Q5 = rates_Q5[ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE]; + } + RD_tmp_Q25 = RD_Q25[j]; + diff_Q10 = silk_SUB16(in_Q10, out0_Q10); + RD_Q25[j] = silk_SMLABB(silk_MLA(RD_tmp_Q25, silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate0_Q5); + diff_Q10 = silk_SUB16(in_Q10, out1_Q10); + RD_Q25[j + nStates] = silk_SMLABB(silk_MLA(RD_tmp_Q25, silk_SMULBB(diff_Q10, diff_Q10), w_Q5[i]), mu_Q20, rate1_Q5); + } + + if (nStates <= NLSF_QUANT_DEL_DEC_STATES / 2) { + /* double number of states and copy */ + for (j = 0; j < nStates; j++) { ind[j + nStates][i] = ind[j][i] + 1; } + nStates = silk_LSHIFT(nStates, 1); + for (j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++) { ind[j][i] = ind[j - nStates][i]; } + } else { + /* sort lower and upper half of RD_Q25, pairwise */ + for (j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++) { + if (RD_Q25[j] > RD_Q25[j + NLSF_QUANT_DEL_DEC_STATES]) { + RD_max_Q25[j] = RD_Q25[j]; + RD_min_Q25[j] = RD_Q25[j + NLSF_QUANT_DEL_DEC_STATES]; + RD_Q25[j] = RD_min_Q25[j]; + RD_Q25[j + NLSF_QUANT_DEL_DEC_STATES] = RD_max_Q25[j]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[j]; + prev_out_Q10[j] = prev_out_Q10[j + NLSF_QUANT_DEL_DEC_STATES]; + prev_out_Q10[j + NLSF_QUANT_DEL_DEC_STATES] = out0_Q10; + ind_sort[j] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[j] = RD_Q25[j]; + RD_max_Q25[j] = RD_Q25[j + NLSF_QUANT_DEL_DEC_STATES]; + ind_sort[j] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if + * necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while (1) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for (j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++) { + if (min_max_Q25 > RD_max_Q25[j]) { + min_max_Q25 = RD_max_Q25[j]; + ind_min_max = j; + } + if (max_min_Q25 < RD_min_Q25[j]) { + max_min_Q25 = RD_min_Q25[j]; + ind_max_min = j; + } + } + if (min_max_Q25 >= max_min_Q25) { break; } + /* copy ind_min_max to ind_max_min */ + ind_sort[ind_max_min] = ind_sort[ind_min_max] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ind_max_min] = RD_Q25[ind_min_max + NLSF_QUANT_DEL_DEC_STATES]; + prev_out_Q10[ind_max_min] = prev_out_Q10[ind_min_max + NLSF_QUANT_DEL_DEC_STATES]; + RD_min_Q25[ind_max_min] = 0; + RD_max_Q25[ind_min_max] = silk_int32_MAX; + memcpy(ind[ind_max_min], ind[ind_min_max], MAX_LPC_ORDER * sizeof(int8_t)); + } + /* increment index if it comes from the upper half */ + for (j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++) { ind[j][i] += silk_RSHIFT(ind_sort[j], NLSF_QUANT_DEL_DEC_STATES_LOG2); } + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for (j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++) { + if (min_Q25 > RD_Q25[j]) { + min_Q25 = RD_Q25[j]; + ind_tmp = j; + } + } + for (j = 0; j < order; j++) { + indices[j] = ind[ind_tmp & (NLSF_QUANT_DEL_DEC_STATES - 1)][j]; + assert(indices[j] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT); + assert(indices[j] <= NLSF_QUANT_MAX_AMPLITUDE_EXT); + } + indices[0] += silk_RSHIFT(ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2); + assert(indices[0] <= NLSF_QUANT_MAX_AMPLITUDE_EXT); + assert(min_Q25 >= 0); + return min_Q25; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* NLSF stabilizer, for a single input data vector */ +void SilkDecoder::silk_NLSF_stabilize(int16_t* NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const int16_t* NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const int32_t L /* I Number of NLSF parameters in the input vector */ +) { + int32_t i, I = 0, k, loops; + int16_t center_freq_Q15; + int32_t diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a int16_t */ + assert(NDeltaMin_Q15[L] >= 1); + + for (loops = 0; loops < MAX_LOOPS; loops++) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for (i = 1; i <= L - 1; i++) { + diff_Q15 = NLSF_Q15[i] - (NLSF_Q15[i - 1] + NDeltaMin_Q15[i]); + if (diff_Q15 < min_diff_Q15) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = (1 << 15) - (NLSF_Q15[L - 1] + NDeltaMin_Q15[L]); + if (diff_Q15 < min_diff_Q15) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if (min_diff_Q15 >= 0) { return; } + + if (I == 0) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + } else if (I == L) { + /* Move away from higher limit */ + NLSF_Q15[L - 1] = (1 << 15) - NDeltaMin_Q15[L]; + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for (k = 0; k < I; k++) { min_center_Q15 += NDeltaMin_Q15[k]; } + min_center_Q15 += silk_RSHIFT(NDeltaMin_Q15[I], 1); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for (k = L; k > I; k--) { max_center_Q15 -= NDeltaMin_Q15[k]; } + max_center_Q15 -= silk_RSHIFT(NDeltaMin_Q15[I], 1); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (int16_t)silk_LIMIT_32(silk_RSHIFT_ROUND((int32_t)NLSF_Q15[I - 1] + (int32_t)NLSF_Q15[I], 1), min_center_Q15, max_center_Q15); + NLSF_Q15[I - 1] = center_freq_Q15 - silk_RSHIFT(NDeltaMin_Q15[I], 1); + NLSF_Q15[I] = NLSF_Q15[I - 1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if (loops == MAX_LOOPS) { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16(&NLSF_Q15[0], L); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int(NLSF_Q15[0], NDeltaMin_Q15[0]); + + /* Keep delta_min distance between the NLSFs */ + for (i = 1; i < L; i++) NLSF_Q15[i] = silk_max_int(NLSF_Q15[i], silk_ADD_SAT16(NLSF_Q15[i - 1], NDeltaMin_Q15[i])); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L - 1] = silk_min_int(NLSF_Q15[L - 1], (1 << 15) - NDeltaMin_Q15[L]); + + /* Keep NDeltaMin distance between the NLSFs */ + for (i = L - 2; i >= 0; i--) NLSF_Q15[i] = silk_min_int(NLSF_Q15[i], NLSF_Q15[i + 1] - NDeltaMin_Q15[i + 1]); + } +} +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Unpack predictor values and indices for entropy coding tables */ +void SilkDecoder::silk_NLSF_unpack(int16_t ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + uint8_t pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct_t* psNLSF_CB, /* I Codebook object */ + const int32_t CB1_index /* I Index of vector in first LSF codebook */ +) { + int32_t i; + uint8_t entry; + const uint8_t* ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[CB1_index * psNLSF_CB->order / 2]; + for (i = 0; i < psNLSF_CB->order; i += 2) { + entry = *ec_sel_ptr++; + ec_ix[i] = silk_SMULBB(silk_RSHIFT(entry, 1) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1); + pred_Q8[i] = psNLSF_CB->pred_Q8[i + (entry & 1) * (psNLSF_CB->order - 1)]; + ec_ix[i + 1] = silk_SMULBB(silk_RSHIFT(entry, 5) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1); + pred_Q8[i + 1] = psNLSF_CB->pred_Q8[i + (silk_RSHIFT(entry, 4) & 1) * (psNLSF_CB->order - 1) + 1]; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Laroia low complexity NLSF weights */ +void SilkDecoder::silk_NLSF_VQ_weights_laroia(int16_t* pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const int16_t* pNLSF_Q15, /* I Pointer to input vector [D] */ + const int32_t D /* I Input vector dimension (even) */ +) { + int32_t k; + int32_t tmp1_int, tmp2_int; + + assert(D > 0); + assert((D & 1) == 0); + + /* First value */ + tmp1_int = silk_max_int(pNLSF_Q15[0], 1); + tmp1_int = silk_DIV32_16((int32_t)1 << (15 + NLSF_W_Q), tmp1_int); + tmp2_int = silk_max_int(pNLSF_Q15[1] - pNLSF_Q15[0], 1); + tmp2_int = silk_DIV32_16((int32_t)1 << (15 + NLSF_W_Q), tmp2_int); + pNLSFW_Q_OUT[0] = (int16_t)silk_min_int(tmp1_int + tmp2_int, silk_int16_MAX); + assert(pNLSFW_Q_OUT[0] > 0); + + /* Main loop */ + for (k = 1; k < D - 1; k += 2) { + tmp1_int = silk_max_int(pNLSF_Q15[k + 1] - pNLSF_Q15[k], 1); + tmp1_int = silk_DIV32_16((int32_t)1 << (15 + NLSF_W_Q), tmp1_int); + pNLSFW_Q_OUT[k] = (int16_t)silk_min_int(tmp1_int + tmp2_int, silk_int16_MAX); + assert(pNLSFW_Q_OUT[k] > 0); + + tmp2_int = silk_max_int(pNLSF_Q15[k + 2] - pNLSF_Q15[k + 1], 1); + tmp2_int = silk_DIV32_16((int32_t)1 << (15 + NLSF_W_Q), tmp2_int); + pNLSFW_Q_OUT[k + 1] = (int16_t)silk_min_int(tmp1_int + tmp2_int, silk_int16_MAX); + assert(pNLSFW_Q_OUT[k + 1] > 0); + } + + /* Last value */ + tmp1_int = silk_max_int((1 << 15) - pNLSF_Q15[D - 1], 1); + tmp1_int = silk_DIV32_16((int32_t)1 << (15 + NLSF_W_Q), tmp1_int); + pNLSFW_Q_OUT[D - 1] = (int16_t)silk_min_int(tmp1_int + tmp2_int, silk_int16_MAX); + assert(pNLSFW_Q_OUT[D - 1] > 0); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void SilkDecoder::silk_NLSF_VQ(int32_t err_Q24[], /* O Quantization errors [K] */ + const int16_t in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const uint8_t pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const int16_t pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const int32_t K, /* I Number of codebook vectors */ + const int32_t LPC_order /* I Number of LPCs */ +) { + int32_t i, m; + int32_t diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24; + const int16_t* w_Q9_ptr; + const uint8_t* cb_Q8_ptr; + + assert((LPC_order & 1) == 0); + + /* Loop over codebook */ + cb_Q8_ptr = pCB_Q8; + w_Q9_ptr = pWght_Q9; + for (i = 0; i < K; i++) { + sum_error_Q24 = 0; + pred_Q24 = 0; + for (m = LPC_order - 2; m >= 0; m -= 2) { + /* Compute weighted absolute predictive quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32(in_Q15[m + 1], (int32_t)cb_Q8_ptr[m + 1], 7); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB(diff_Q15, w_Q9_ptr[m + 1]); + sum_error_Q24 = sum_error_Q24 + silk_abs(silk_SUB_RSHIFT32(diffw_Q24, pred_Q24, 1)); + pred_Q24 = diffw_Q24; + + /* Compute weighted absolute predictive quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32(in_Q15[m], (int32_t)cb_Q8_ptr[m], 7); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB(diff_Q15, w_Q9_ptr[m]); + sum_error_Q24 = sum_error_Q24 + silk_abs(silk_SUB_RSHIFT32(diffw_Q24, pred_Q24, 1)); + pred_Q24 = diffw_Q24; + + assert(sum_error_Q24 >= 0); + } + err_Q24[i] = sum_error_Q24; + cb_Q8_ptr += LPC_order; + w_Q9_ptr += LPC_order; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::silk_PLC_Reset(uint8_t n) { /* I/O Decoder state */ + m_channel_state[n].sPLC.pitchL_Q8 = silk_LSHIFT(m_channel_state[n].frame_length, 8 - 1); + m_channel_state[n].sPLC.prevGain_Q16[0] = SILK_FIX_CONST(1, 16); + m_channel_state[n].sPLC.prevGain_Q16[1] = SILK_FIX_CONST(1, 16); + m_channel_state[n].sPLC.subfr_length = 20; + m_channel_state[n].sPLC.nb_subfr = 2; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_PLC(uint8_t n, int16_t frame[], int32_t lost) { + /* PLC control function */ + if (m_channel_state[n].fs_kHz != m_channel_state[n].sPLC.fs_kHz) { + silk_PLC_Reset(n); + m_channel_state[n].sPLC.fs_kHz = m_channel_state[n].fs_kHz; + } + + if (lost) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal(n, frame); + + m_channel_state[n].lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update(n); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Update state of PLC */ +void SilkDecoder::silk_PLC_update(uint8_t n) { + int32_t LTP_Gain_Q14, temp_LTP_Gain_Q14; + int32_t i, j; + silk_PLC_struct_t* psPLC; + + psPLC = &m_channel_state[n].sPLC; + + /* Update parameters used in case of packet loss */ + m_channel_state[n].prevSignalType = m_channel_state[n].indices.signalType; + LTP_Gain_Q14 = 0; + if (m_channel_state[n].indices.signalType == TYPE_VOICED) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for (j = 0; j * m_channel_state[n].subfr_length < m_silk_decoder_control->pitchL[m_channel_state[n].nb_subfr - 1]; j++) { + if (j == m_channel_state[n].nb_subfr) { break; } + temp_LTP_Gain_Q14 = 0; + for (i = 0; i < LTP_ORDER; i++) { temp_LTP_Gain_Q14 += m_silk_decoder_control->LTPCoef_Q14[(m_channel_state[n].nb_subfr - 1 - j) * LTP_ORDER + i]; } + if (temp_LTP_Gain_Q14 > LTP_Gain_Q14) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + memcpy(psPLC->LTPCoef_Q14, &m_silk_decoder_control->LTPCoef_Q14[silk_SMULBB(m_channel_state[n].nb_subfr - 1 - j, LTP_ORDER)], LTP_ORDER * sizeof(int16_t)); + psPLC->pitchL_Q8 = silk_LSHIFT(m_silk_decoder_control->pitchL[m_channel_state[n].nb_subfr - 1 - j], 8); + } + } + + memset(psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof(int16_t)); + psPLC->LTPCoef_Q14[LTP_ORDER / 2] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if (LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14) { + int32_t scale_Q10; + int32_t tmp; + + tmp = silk_LSHIFT(V_PITCH_GAIN_START_MIN_Q14, 10); + scale_Q10 = silk_DIV32(tmp, silk_max(LTP_Gain_Q14, 1)); + for (i = 0; i < LTP_ORDER; i++) { psPLC->LTPCoef_Q14[i] = silk_RSHIFT(silk_SMULBB(psPLC->LTPCoef_Q14[i], scale_Q10), 10); } + } else if (LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14) { + int32_t scale_Q14; + int32_t tmp; + + tmp = silk_LSHIFT(V_PITCH_GAIN_START_MAX_Q14, 14); + scale_Q14 = silk_DIV32(tmp, silk_max(LTP_Gain_Q14, 1)); + for (i = 0; i < LTP_ORDER; i++) { psPLC->LTPCoef_Q14[i] = silk_RSHIFT(silk_SMULBB(psPLC->LTPCoef_Q14[i], scale_Q14), 14); } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT(silk_SMULBB(m_channel_state[n].fs_kHz, 18), 8); + memset(psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof(int16_t)); + } + + /* Save LPC coeficients */ + memcpy(psPLC->prevLPC_Q12, m_silk_decoder_control->PredCoef_Q12[1], m_channel_state[n].LPC_order * sizeof(int16_t)); + psPLC->prevLTP_scale_Q14 = m_silk_decoder_control->LTP_scale_Q14; + + /* Save last two gains */ + memcpy(psPLC->prevGain_Q16, &m_silk_decoder_control->Gains_Q16[m_channel_state[n].nb_subfr - 2], 2 * sizeof(int32_t)); + + psPLC->subfr_length = m_channel_state[n].subfr_length; + psPLC->nb_subfr = m_channel_state[n].nb_subfr; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_PLC_energy(int32_t* energy1, int32_t* shift1, int32_t* energy2, int32_t* shift2, const int32_t* exc_Q14, const int32_t* prevGain_Q10, int subfr_length, int nb_subfr) { + int i, k; + int16_t* exc_buf_ptr; + ps_ptr exc_buf; + exc_buf.alloc_array(2 * subfr_length); + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf.get(); + for (k = 0; k < 2; k++) { + for (i = 0; i < subfr_length; i++) { exc_buf_ptr[i] = (int16_t)silk_SAT16(silk_RSHIFT(silk_SMULWW(exc_Q14[i + (k + nb_subfr - 2) * subfr_length], prevGain_Q10[k]), 8)); } + exc_buf_ptr += subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift(energy1, shift1, exc_buf.get(), subfr_length); + silk_sum_sqr_shift(energy2, shift2, &exc_buf[subfr_length], subfr_length); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_PLC_conceal(uint8_t n, int16_t frame[]) { + int32_t i, j, k; + int32_t lag, idx, sLTP_buf_idx, shift1, shift2; + int32_t rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + int32_t energy1, energy2, *rand_ptr, *pred_lag_ptr; + int32_t LPC_pred_Q10, LTP_pred_Q12; + int16_t rand_scale_Q14; + int16_t* B_Q14; + int32_t* sLPC_Q14_ptr; + int16_t A_Q12[MAX_LPC_ORDER]; + silk_PLC_struct_t* psPLC = &m_channel_state[n].sPLC; + int32_t prevGain_Q10[2]; + + ps_ptr sLTP_Q14; + sLTP_Q14.alloc_array(m_channel_state[n].ltp_mem_length + m_channel_state[n].frame_length); + ps_ptr sLTP; + sLTP.alloc_array(m_channel_state[n].ltp_mem_length); + + prevGain_Q10[0] = silk_RSHIFT(psPLC->prevGain_Q16[0], 6); + prevGain_Q10[1] = silk_RSHIFT(psPLC->prevGain_Q16[1], 6); + + if (m_channel_state[n].first_frame_after_reset) { memset(psPLC->prevLPC_Q12, 0, sizeof(psPLC->prevLPC_Q12)); } + + silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, m_channel_state[n].exc_Q14, prevGain_Q10, m_channel_state[n].subfr_length, m_channel_state[n].nb_subfr); + + if (silk_RSHIFT(energy1, shift2) < silk_RSHIFT(energy2, shift1)) { + /* First sub-frame has lowest energy */ + rand_ptr = &m_channel_state[n].exc_Q14[silk_max_int(0, (psPLC->nb_subfr - 1) * psPLC->subfr_length - RAND_BUF_SIZE)]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &m_channel_state[n].exc_Q14[silk_max_int(0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE)]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[silk_min_int(NB_ATT - 1, m_channel_state[n].lossCnt)]; + if (m_channel_state[n].prevSignalType == TYPE_VOICED) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[silk_min_int(NB_ATT - 1, m_channel_state[n].lossCnt)]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[silk_min_int(NB_ATT - 1, m_channel_state[n].lossCnt)]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander(psPLC->prevLPC_Q12, m_channel_state[n].LPC_order, SILK_FIX_CONST(BWE_COEF, 16)); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + memcpy(A_Q12, psPLC->prevLPC_Q12, m_channel_state[n].LPC_order * sizeof(int16_t)); + + /* First Lost frame */ + if (m_channel_state[n].lossCnt == 0) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if (m_channel_state[n].prevSignalType == TYPE_VOICED) { + for (i = 0; i < LTP_ORDER; i++) { rand_scale_Q14 -= B_Q14[i]; } + rand_scale_Q14 = silk_max_16(3277, rand_scale_Q14); /* 0.2 */ + rand_scale_Q14 = (int16_t)silk_RSHIFT(silk_SMULBB(rand_scale_Q14, psPLC->prevLTP_scale_Q14), 14); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + int32_t invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain(psPLC->prevLPC_Q12, m_channel_state[n].LPC_order); + + down_scale_Q30 = silk_min_32(silk_RSHIFT((int32_t)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES), invGain_Q30); + down_scale_Q30 = silk_max_32(silk_RSHIFT((int32_t)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES), down_scale_Q30); + down_scale_Q30 = silk_LSHIFT(down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES); + + rand_Gain_Q15 = silk_RSHIFT(silk_SMULWB(down_scale_Q30, rand_Gain_Q15), 14); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND(psPLC->pitchL_Q8, 8); + sLTP_buf_idx = m_channel_state[n].ltp_mem_length; + + /* Rewhiten LTP state */ + idx = m_channel_state[n].ltp_mem_length - lag - m_channel_state[n].LPC_order - LTP_ORDER / 2; + assert(idx > 0); + silk_LPC_analysis_filter(&sLTP[idx], &m_channel_state[n].outBuf[idx], A_Q12, m_channel_state[n].ltp_mem_length - idx, m_channel_state[n].LPC_order); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ(psPLC->prevGain_Q16[1], 46); + inv_gain_Q30 = silk_min(inv_gain_Q30, silk_int32_MAX >> 1); + for (i = idx + m_channel_state[n].LPC_order; i < m_channel_state[n].ltp_mem_length; i++) { sLTP_Q14[i] = silk_SMULWB(inv_gain_Q30, sLTP[i]); } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for (k = 0; k < m_channel_state[n].nb_subfr; k++) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[sLTP_buf_idx - lag + LTP_ORDER / 2]; + for (i = 0; i < m_channel_state[n].subfr_length; i++) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB(LTP_pred_Q12, pred_lag_ptr[0], B_Q14[0]); + LTP_pred_Q12 = silk_SMLAWB(LTP_pred_Q12, pred_lag_ptr[-1], B_Q14[1]); + LTP_pred_Q12 = silk_SMLAWB(LTP_pred_Q12, pred_lag_ptr[-2], B_Q14[2]); + LTP_pred_Q12 = silk_SMLAWB(LTP_pred_Q12, pred_lag_ptr[-3], B_Q14[3]); + LTP_pred_Q12 = silk_SMLAWB(LTP_pred_Q12, pred_lag_ptr[-4], B_Q14[4]); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND(rand_seed); + idx = silk_RSHIFT(rand_seed, 25) & RAND_BUF_MASK; + sLTP_Q14[sLTP_buf_idx] = silk_LSHIFT32(silk_SMLAWB(LTP_pred_Q12, rand_ptr[idx], rand_scale_Q14), 2); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for (j = 0; j < LTP_ORDER; j++) { B_Q14[j] = silk_RSHIFT(silk_SMULBB(harm_Gain_Q15, B_Q14[j]), 15); } + if (m_channel_state[n].indices.signalType != TYPE_NO_VOICE_ACTIVITY) { + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT(silk_SMULBB(rand_scale_Q14, rand_Gain_Q15), 15); + } + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB(psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16); + psPLC->pitchL_Q8 = silk_min_32(psPLC->pitchL_Q8, silk_LSHIFT(silk_SMULBB(MAX_PITCH_LAG_MS, m_channel_state[n].fs_kHz), 8)); + lag = silk_RSHIFT_ROUND(psPLC->pitchL_Q8, 8); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[m_channel_state[n].ltp_mem_length - MAX_LPC_ORDER]; + + /* Copy LPC state */ + memcpy(sLPC_Q14_ptr, m_channel_state[n].sLPC_Q14_buf, MAX_LPC_ORDER * sizeof(int32_t)); + + assert(m_channel_state[n].LPC_order >= 10); /* check that unrolling works */ + for (i = 0; i < m_channel_state[n].frame_length; i++) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT(m_channel_state[n].LPC_order, 1); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 1], A_Q12[0]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 2], A_Q12[1]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 3], A_Q12[2]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 4], A_Q12[3]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 5], A_Q12[4]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 6], A_Q12[5]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 7], A_Q12[6]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 8], A_Q12[7]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 9], A_Q12[8]); + LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - 10], A_Q12[9]); + for (j = 10; j < m_channel_state[n].LPC_order; j++) { LPC_pred_Q10 = silk_SMLAWB(LPC_pred_Q10, sLPC_Q14_ptr[MAX_LPC_ORDER + i - j - 1], A_Q12[j]); } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[MAX_LPC_ORDER + i] = silk_ADD_SAT32(sLPC_Q14_ptr[MAX_LPC_ORDER + i], silk_LSHIFT_SAT32(LPC_pred_Q10, 4)); + + /* Scale with Gain */ + frame[i] = (int16_t)silk_SAT16(silk_SAT16(silk_RSHIFT_ROUND(silk_SMULWW(sLPC_Q14_ptr[MAX_LPC_ORDER + i], prevGain_Q10[1]), 8))); + } + + /* Save LPC state */ + memcpy(m_channel_state[n].sLPC_Q14_buf, &sLPC_Q14_ptr[m_channel_state[n].frame_length], MAX_LPC_ORDER * sizeof(int32_t)); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for (i = 0; i < MAX_NB_SUBFR; i++) { m_silk_decoder_control->pitchL[i] = lag; } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Glues concealed frames with new good received frames */ +void SilkDecoder::silk_PLC_glue_frames(uint8_t n, int16_t frame[], int32_t length) { + int32_t i, energy_shift; + int32_t energy; + silk_PLC_struct_t* psPLC; + psPLC = &m_channel_state[n].sPLC; + + if (m_channel_state[n].lossCnt) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift(&psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length); + + psPLC->last_frame_lost = 1; + } else { + if (m_channel_state[n].sPLC.last_frame_lost) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift(&energy, &energy_shift, frame, length); + + /* Normalize energies */ + if (energy_shift > psPLC->conc_energy_shift) { + psPLC->conc_energy = silk_RSHIFT(psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift); + } else if (energy_shift < psPLC->conc_energy_shift) { + energy = silk_RSHIFT(energy, psPLC->conc_energy_shift - energy_shift); + } + + /* Fade in the energy difference */ + if (energy > psPLC->conc_energy) { + int32_t frac_Q24, LZ; + int32_t gain_Q16, slope_Q16; + + LZ = silk_CLZ32(psPLC->conc_energy); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT(psPLC->conc_energy, LZ); + energy = silk_RSHIFT(energy, silk_max_32(24 - LZ, 0)); + + frac_Q24 = silk_DIV32(psPLC->conc_energy, silk_max(energy, 1)); + + gain_Q16 = silk_LSHIFT(silk_SQRT_APPROX(frac_Q24), 4); + slope_Q16 = silk_DIV32_16(((int32_t)1 << 16) - gain_Q16, length); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT(slope_Q16, 2); + + for (i = 0; i < length; i++) { + frame[i] = silk_SMULWB(gain_Q16, frame[i]); + gain_Q16 += slope_Q16; + if (gain_Q16 > (int32_t)1 << 16) { break; } + } + } + } + psPLC->last_frame_lost = 0; + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Downsample by a factor 2 */ +void SilkDecoder::silk_resampler_down2(int32_t* S, /* I/O State vector [ 2 ] */ + int16_t* out, /* O Output signal [ floor(len/2) ] */ + const int16_t* in, /* I Input signal [ len ] */ + int32_t inLen /* I Number of input samples */ +) { + int32_t k, len2 = silk_RSHIFT32(inLen, 1); + int32_t in32, out32, Y, X; + + assert(silk_resampler_down2_0 > 0); + assert(silk_resampler_down2_1 < 0); + + /* Internal variables and state are in Q10 format */ + for (k = 0; k < len2; k++) { + /* Convert to Q10 */ + in32 = silk_LSHIFT((int32_t)in[2 * k], 10); + + /* All-pass section for even input sample */ + Y = silk_SUB32(in32, S[0]); + X = silk_SMLAWB(Y, Y, silk_resampler_down2_1); + out32 = S[0] + X; + S[0] = in32 + X; + + /* Convert to Q10 */ + in32 = silk_LSHIFT((int32_t)in[2 * k + 1], 10); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32(in32, S[1]); + X = silk_SMULWB(Y, silk_resampler_down2_0); + out32 = out32 + S[1]; + out32 = out32 + X; + S[1] = in32 + X; + + /* Add, convert back to int16 and store to output */ + out[k] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(out32, 11)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Second order AR filter with single delay elements */ +void SilkDecoder::silk_resampler_private_AR2(int32_t S[], /* I/O State vector [ 2 ] */ + int32_t out_Q8[], /* O Output signal */ + const int16_t in[], /* I Input signal */ + const int16_t A_Q14[], /* I AR coefficients, Q14 */ + int32_t len /* I Signal length */ +) { + int32_t k; + int32_t out32; + + for (k = 0; k < len; k++) { + out32 = silk_ADD_LSHIFT32(S[0], (int32_t)in[k], 8); + out_Q8[k] = out32; + out32 = silk_LSHIFT(out32, 2); + S[0] = silk_SMLAWB(S[1], out32, A_Q14[0]); + S[1] = silk_SMULWB(out32, A_Q14[1]); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +int16_t* SilkDecoder::silk_resampler_private_down_FIR_INTERPOL(int16_t* out, int32_t* buf, const int16_t* FIR_Coefs, int32_t FIR_Order, int32_t FIR_Fracs, int32_t max_index_Q16, + int32_t index_increment_Q16) { + int32_t index_Q16, res_Q6; + int32_t* buf_ptr; + int32_t interpol_ind; + const int16_t* interpol_ptr; + + switch (FIR_Order) { + case RESAMPLER_DOWN_ORDER_FIR0: + for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT(index_Q16, 16); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB(index_Q16 & 0xFFFF, FIR_Fracs); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind]; + res_Q6 = silk_SMULWB(buf_ptr[0], interpol_ptr[0]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[1], interpol_ptr[1]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[2], interpol_ptr[2]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[3], interpol_ptr[3]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[4], interpol_ptr[4]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[5], interpol_ptr[5]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[6], interpol_ptr[6]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[7], interpol_ptr[7]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[8], interpol_ptr[8]); + interpol_ptr = &FIR_Coefs[RESAMPLER_DOWN_ORDER_FIR0 / 2 * (FIR_Fracs - 1 - interpol_ind)]; + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[17], interpol_ptr[0]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[16], interpol_ptr[1]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[15], interpol_ptr[2]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[14], interpol_ptr[3]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[13], interpol_ptr[4]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[12], interpol_ptr[5]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[11], interpol_ptr[6]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[10], interpol_ptr[7]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[9], interpol_ptr[8]); + + /* Scale down, saturate and store in output array */ + *out++ = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(res_Q6, 6)); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT(index_Q16, 16); + + /* Inner product */ + res_Q6 = silk_SMULWB(buf_ptr[0] + buf_ptr[23], FIR_Coefs[0]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[1] + buf_ptr[22], FIR_Coefs[1]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[2] + buf_ptr[21], FIR_Coefs[2]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[3] + buf_ptr[20], FIR_Coefs[3]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[4] + buf_ptr[19], FIR_Coefs[4]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[5] + buf_ptr[18], FIR_Coefs[5]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[6] + buf_ptr[17], FIR_Coefs[6]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[7] + buf_ptr[16], FIR_Coefs[7]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[8] + buf_ptr[15], FIR_Coefs[8]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[9] + buf_ptr[14], FIR_Coefs[9]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[10] + buf_ptr[13], FIR_Coefs[10]); + res_Q6 = silk_SMLAWB(res_Q6, buf_ptr[11] + buf_ptr[12], FIR_Coefs[11]); + + /* Scale down, saturate and store in output array */ + *out++ = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(res_Q6, 6)); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT(index_Q16, 16); + + /* Inner product */ + res_Q6 = silk_SMULWB(silk_ADD32(buf_ptr[0], buf_ptr[35]), FIR_Coefs[0]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[1], buf_ptr[34]), FIR_Coefs[1]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[2], buf_ptr[33]), FIR_Coefs[2]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[3], buf_ptr[32]), FIR_Coefs[3]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[4], buf_ptr[31]), FIR_Coefs[4]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[5], buf_ptr[30]), FIR_Coefs[5]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[6], buf_ptr[29]), FIR_Coefs[6]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[7], buf_ptr[28]), FIR_Coefs[7]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[8], buf_ptr[27]), FIR_Coefs[8]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[9], buf_ptr[26]), FIR_Coefs[9]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[10], buf_ptr[25]), FIR_Coefs[10]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[11], buf_ptr[24]), FIR_Coefs[11]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[12], buf_ptr[23]), FIR_Coefs[12]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[13], buf_ptr[22]), FIR_Coefs[13]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[14], buf_ptr[21]), FIR_Coefs[14]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[15], buf_ptr[20]), FIR_Coefs[15]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[16], buf_ptr[19]), FIR_Coefs[16]); + res_Q6 = silk_SMLAWB(res_Q6, silk_ADD32(buf_ptr[17], buf_ptr[18]), FIR_Coefs[17]); + + /* Scale down, saturate and store in output array */ + *out++ = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(res_Q6, 6)); + } + break; + default: { + ; + } + } + return out; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void SilkDecoder::silk_resampler_private_down_FIR(void* SS, /* I/O Resampler state */ + int16_t out[], /* O Output signal */ + const int16_t in[], /* I Input signal */ + int32_t inLen /* I Number of input samples */ +) { + silk_resampler_state_struct_t* S = (silk_resampler_state_struct_t*)SS; + int32_t nSamplesIn; + int32_t max_index_Q16, index_increment_Q16; + const int16_t* FIR_Coefs; + + ps_ptr buf; + buf.alloc_array(S->batchSize + S->FIR_Order); + + /* Copy buffered samples to start of buffer */ + memcpy(buf.get(), S->sFIR.i32, S->FIR_Order * sizeof(int32_t)); + + FIR_Coefs = &S->Coefs[2]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while (1) { + nSamplesIn = silk_min(inLen, S->batchSize); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2(S->sIIR, &buf[S->FIR_Order], in, S->Coefs, nSamplesIn); + + max_index_Q16 = silk_LSHIFT32(nSamplesIn, 16); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL(out, buf.get(), FIR_Coefs, S->FIR_Order, S->FIR_Fracs, max_index_Q16, index_increment_Q16); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if (inLen > 1) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + memcpy(buf.get(), &buf[nSamplesIn], S->FIR_Order * sizeof(int32_t)); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + memcpy(S->sFIR.i32, &buf[nSamplesIn], S->FIR_Order * sizeof(int32_t)); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +int16_t* SilkDecoder::silk_resampler_private_IIR_FIR_INTERPOL(int16_t* out, int16_t* buf, int32_t max_index_Q16, int32_t index_increment_Q16) { + int32_t index_Q16, res_Q15; + int16_t* buf_ptr; + int32_t table_index; + + /* Interpolate upsampled signal and store in output array */ + for (index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16) { + table_index = silk_SMULWB(index_Q16 & 0xFFFF, 12); + buf_ptr = &buf[index_Q16 >> 16]; + + res_Q15 = silk_SMULBB(buf_ptr[0], silk_resampler_frac_FIR_12[table_index][0]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[1], silk_resampler_frac_FIR_12[table_index][1]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[2], silk_resampler_frac_FIR_12[table_index][2]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[3], silk_resampler_frac_FIR_12[table_index][3]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[4], silk_resampler_frac_FIR_12[11 - table_index][3]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[5], silk_resampler_frac_FIR_12[11 - table_index][2]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[6], silk_resampler_frac_FIR_12[11 - table_index][1]); + res_Q15 = silk_SMLABB(res_Q15, buf_ptr[7], silk_resampler_frac_FIR_12[11 - table_index][0]); + *out++ = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(res_Q15, 15)); + } + return out; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void SilkDecoder::silk_resampler_private_IIR_FIR(void* SS, /* I/O Resampler state */ + int16_t out[], /* O Output signal */ + const int16_t in[], /* I Input signal */ + int32_t inLen /* I Number of input samples */ +) { + silk_resampler_state_struct_t* S = (silk_resampler_state_struct_t*)SS; + int32_t nSamplesIn; + int32_t max_index_Q16, index_increment_Q16; + + ps_ptr buf; + int32_t buf_size = 2 * S->batchSize + RESAMPLER_ORDER_FIR_12; + if (!buf.alloc_array(buf_size)) { + return; // Allocation failed + } + + /* Copy buffered samples to start of buffer */ + memcpy(buf.get(), S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof(int16_t)); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while (1) { + nSamplesIn = silk_min(inLen, S->batchSize); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ(S->sIIR, buf.get() + RESAMPLER_ORDER_FIR_12, in, nSamplesIn); + + max_index_Q16 = silk_LSHIFT32(nSamplesIn, 16 + 1); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL(out, buf.get(), max_index_Q16, index_increment_Q16); + in += nSamplesIn; + inLen -= nSamplesIn; + + if (inLen > 0) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + int32_t src_offset = nSamplesIn << 1; + if (src_offset + RESAMPLER_ORDER_FIR_12 <= buf_size) { memcpy(buf.get(), buf.get() + src_offset, RESAMPLER_ORDER_FIR_12 * sizeof(int16_t)); } + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + int32_t src_offset = nSamplesIn << 1; + if (src_offset + RESAMPLER_ORDER_FIR_12 <= buf_size) { memcpy(S->sFIR.i16, buf.get() + src_offset, RESAMPLER_ORDER_FIR_12 * sizeof(int16_t)); } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Upsample by a factor 2, high quality. Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void SilkDecoder::silk_resampler_private_up2_HQ(int32_t* S, /* I/O Resampler state [ 6 ] */ + int16_t* out, /* O Output signal [ 2 * len ] */ + const int16_t* in, /* I Input signal [ len ] */ + int32_t len /* I Number of input samples */ +) { + int32_t k; + int32_t in32, out32_1, out32_2, Y, X; + + assert(silk_resampler_up2_hq_0[0] > 0); + assert(silk_resampler_up2_hq_0[1] > 0); + assert(silk_resampler_up2_hq_0[2] < 0); + assert(silk_resampler_up2_hq_1[0] > 0); + assert(silk_resampler_up2_hq_1[1] > 0); + assert(silk_resampler_up2_hq_1[2] < 0); + + /* Internal variables and state are in Q10 format */ + for (k = 0; k < len; k++) { + /* Convert to Q10 */ + in32 = silk_LSHIFT((int32_t)in[k], 10); + + /* First all-pass section for even output sample */ + Y = silk_SUB32(in32, S[0]); + X = silk_SMULWB(Y, silk_resampler_up2_hq_0[0]); + out32_1 = silk_ADD32(S[0], X); + S[0] = silk_ADD32(in32, X); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32(out32_1, S[1]); + X = silk_SMULWB(Y, silk_resampler_up2_hq_0[1]); + out32_2 = silk_ADD32(S[1], X); + S[1] = silk_ADD32(out32_1, X); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32(out32_2, S[2]); + X = silk_SMLAWB(Y, Y, silk_resampler_up2_hq_0[2]); + out32_1 = silk_ADD32(S[2], X); + S[2] = silk_ADD32(out32_2, X); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[2 * k] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(out32_1, 10)); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32(in32, S[3]); + X = silk_SMULWB(Y, silk_resampler_up2_hq_1[0]); + out32_1 = silk_ADD32(S[3], X); + S[3] = silk_ADD32(in32, X); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32(out32_1, S[4]); + X = silk_SMULWB(Y, silk_resampler_up2_hq_1[1]); + out32_2 = silk_ADD32(S[4], X); + S[4] = silk_ADD32(out32_1, X); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32(out32_2, S[5]); + X = silk_SMLAWB(Y, Y, silk_resampler_up2_hq_1[2]); + out32_1 = silk_ADD32(S[5], X); + S[5] = silk_ADD32(out32_2, X); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[2 * k + 1] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(out32_1, 10)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_resampler_private_up2_HQ_wrapper(void* SS, /* I/O Resampler state (unused) */ + int16_t* out, /* O Output signal [ 2 * len ] */ + const int16_t* in, /* I Input signal [ len ] */ + int32_t len /* I Number of input samples */ +) { + silk_resampler_state_struct_t* S = (silk_resampler_state_struct_t*)SS; + silk_resampler_private_up2_HQ(S->sIIR, out, in, len); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +int32_t SilkDecoder::silk_resampler_init(uint8_t n, int32_t Fs_Hz_in, /* I Input sampling rate (Hz) */ + int32_t Fs_Hz_out, /* I Output sampling rate (Hz) */ + int32_t forEnc /* I If 1: encoder; if 0: decoder */ +) { + int32_t up2x; + /* Clear state */ + memset(&m_resampler_state[n], 0, sizeof(silk_resampler_state_struct_t)); + + /* Input checking */ + if (forEnc) { + if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000)) { return -1; } + m_resampler_state[n].inputDelay = delay_matrix_enc[rateID(Fs_Hz_in)][rateID(Fs_Hz_out)]; + } else { + if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000)) { return -1; } + m_resampler_state[n].inputDelay = delay_matrix_dec[rateID(Fs_Hz_in)][rateID(Fs_Hz_out)]; + } + + m_resampler_state[n].Fs_in_kHz = silk_DIV32_16(Fs_Hz_in, 1000); + m_resampler_state[n].Fs_out_kHz = silk_DIV32_16(Fs_Hz_out, 1000); + + /* Number of samples processed per batch */ + m_resampler_state[n].batchSize = m_resampler_state[n].Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if (Fs_Hz_out > Fs_Hz_in) { + /* Upsample */ + if (Fs_Hz_out == silk_MUL(Fs_Hz_in, 2)) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + m_resampler_state[n].resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + m_resampler_state[n].resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if (Fs_Hz_out < Fs_Hz_in) { + /* Downsample */ + m_resampler_state[n].resampler_function = USE_silk_resampler_private_down_FIR; + if (silk_MUL(Fs_Hz_out, 4) == silk_MUL(Fs_Hz_in, 3)) { /* Fs_out : Fs_in = 3 : 4 */ + m_resampler_state[n].FIR_Fracs = 3; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + m_resampler_state[n].Coefs = silk_Resampler_3_4_COEFS; + } else if (silk_MUL(Fs_Hz_out, 3) == silk_MUL(Fs_Hz_in, 2)) { /* Fs_out : Fs_in = 2 : 3 */ + m_resampler_state[n].FIR_Fracs = 2; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + m_resampler_state[n].Coefs = silk_Resampler_2_3_COEFS; + } else if (silk_MUL(Fs_Hz_out, 2) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 2 */ + m_resampler_state[n].FIR_Fracs = 1; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + m_resampler_state[n].Coefs = silk_Resampler_1_2_COEFS; + } else if (silk_MUL(Fs_Hz_out, 3) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 3 */ + m_resampler_state[n].FIR_Fracs = 1; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + m_resampler_state[n].Coefs = silk_Resampler_1_3_COEFS; + } else if (silk_MUL(Fs_Hz_out, 4) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 4 */ + m_resampler_state[n].FIR_Fracs = 1; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + m_resampler_state[n].Coefs = silk_Resampler_1_4_COEFS; + } else if (silk_MUL(Fs_Hz_out, 6) == Fs_Hz_in) { /* Fs_out : Fs_in = 1 : 6 */ + m_resampler_state[n].FIR_Fracs = 1; + m_resampler_state[n].FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + m_resampler_state[n].Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + m_resampler_state[n].resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + m_resampler_state[n].invRatio_Q16 = silk_LSHIFT32(silk_DIV32(silk_LSHIFT32(Fs_Hz_in, 14 + up2x), Fs_Hz_out), 2); + /* Make sure the ratio is rounded up */ + while (silk_SMULWW(m_resampler_state[n].invRatio_Q16, Fs_Hz_out) < silk_LSHIFT32(Fs_Hz_in, up2x)) { m_resampler_state[n].invRatio_Q16++; } + + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Resampler: convert from one sampling rate to another Input and output sampling rate are at most 48000 Hz */ +int32_t SilkDecoder::silk_resampler(uint8_t n, int16_t out[], /* O Output signal */ + const int16_t in[], /* I Input signal */ + int32_t inLen /* I Number of input samples */ +) { + int32_t nSamples; + + /* Need at least 1 ms of input data */ + assert(inLen >= m_resampler_state[n].Fs_in_kHz); + /* Delay can't exceed the 1 ms of buffering */ + assert(m_resampler_state[n].inputDelay <= m_resampler_state[n].Fs_in_kHz); + + nSamples = m_resampler_state[n].Fs_in_kHz - m_resampler_state[n].inputDelay; + + /* Copy to delay buffer */ + memcpy(&m_resampler_state[n].delayBuf[m_resampler_state[n].inputDelay], in, nSamples * sizeof(int16_t)); + + switch (m_resampler_state[n].resampler_function) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper(&m_resampler_state[n], out, m_resampler_state[n].delayBuf, m_resampler_state[n].Fs_in_kHz); + silk_resampler_private_up2_HQ_wrapper(&m_resampler_state[n], &out[m_resampler_state[n].Fs_out_kHz], &in[nSamples], inLen - m_resampler_state[n].Fs_in_kHz); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR(&m_resampler_state[n], out, m_resampler_state[n].delayBuf, m_resampler_state[n].Fs_in_kHz); + silk_resampler_private_IIR_FIR(&m_resampler_state[n], &out[m_resampler_state[n].Fs_out_kHz], &in[nSamples], inLen - m_resampler_state[n].Fs_in_kHz); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR(&m_resampler_state[n], out, m_resampler_state[n].delayBuf, m_resampler_state[n].Fs_in_kHz); + silk_resampler_private_down_FIR(&m_resampler_state[n], &out[m_resampler_state[n].Fs_out_kHz], &in[nSamples], inLen - m_resampler_state[n].Fs_in_kHz); + break; + default: + memcpy(out, m_resampler_state[n].delayBuf, m_resampler_state[n].Fs_in_kHz * sizeof(int16_t)); + memcpy(&out[m_resampler_state[n].Fs_out_kHz], &in[nSamples], (inLen - m_resampler_state[n].Fs_in_kHz) * sizeof(int16_t)); + } + + /* Copy to delay buffer */ + memcpy(m_resampler_state[n].delayBuf, &in[inLen - m_resampler_state[n].inputDelay], m_resampler_state[n].inputDelay * sizeof(int16_t)); + + return 0; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t SilkDecoder::silk_sigm_Q15(int32_t in_Q5) { + int32_t ind; + if (in_Q5 < 0) { + /* Negative input */ + in_Q5 = -in_Q5; + if (in_Q5 >= 6 * 32) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT(in_Q5, 5); + return (sigm_LUT_neg_Q15[ind] - silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F)); + } + } else { + /* Positive input */ + if (in_Q5 >= 6 * 32) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT(in_Q5, 5); + return (sigm_LUT_pos_Q15[ind] + silk_SMULBB(sigm_LUT_slope_Q10[ind], in_Q5 & 0x1F)); + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// silk_insertion_sort_increasing(Unsorted / Sorted vector, Index vector for the sorted elements, Vector length, Number of correctly sorted positions ) +void SilkDecoder::silk_insertion_sort_increasing(int32_t* a, int32_t* idx, const int32_t L, const int32_t K) { + int32_t value; + int32_t i, j; + + /* Safety checks */ + assert(K > 0); + assert(L > 0); + assert(L >= K); + + /* Write start indices in index vector */ + for (i = 0; i < K; i++) { idx[i] = i; } + + /* Sort vector elements by value, increasing order */ + for (i = 1; i < K; i++) { + value = a[i]; + for (j = i - 1; (j >= 0) && (value < a[j]); j--) { + a[j + 1] = a[j]; /* Shift value */ + idx[j + 1] = idx[j]; /* Shift index */ + } + a[j + 1] = value; /* Write value */ + idx[j + 1] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, but only spend CPU to ensure that the K first values are correct */ + for (i = K; i < L; i++) { + value = a[i]; + if (value < a[K - 1]) { + for (j = K - 2; (j >= 0) && (value < a[j]); j--) { + a[j + 1] = a[j]; /* Shift value */ + idx[j + 1] = idx[j]; /* Shift index */ + } + a[j + 1] = value; /* Write value */ + idx[j + 1] = i; /* Write index */ + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* This function is only used by the fixed-point build */ +void SilkDecoder::silk_insertion_sort_decreasing_int16(int16_t* a, /* I/O Unsorted / Sorted vector */ + int32_t* idx, /* O Index vector for the sorted elements */ + const int32_t L, /* I Vector length */ + const int32_t K /* I Number of correctly sorted positions */ +) { + int32_t i, j; + int32_t value; + + /* Safety checks */ + assert(K > 0); + assert(L > 0); + assert(L >= K); + + /* Write start indices in index vector */ + for (i = 0; i < K; i++) { idx[i] = i; } + + /* Sort vector elements by value, decreasing order */ + for (i = 1; i < K; i++) { + value = a[i]; + for (j = i - 1; (j >= 0) && (value > a[j]); j--) { + a[j + 1] = a[j]; /* Shift value */ + idx[j + 1] = idx[j]; /* Shift index */ + } + a[j + 1] = value; /* Write value */ + idx[j + 1] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for (i = K; i < L; i++) { + value = a[i]; + if (value > a[K - 1]) { + for (j = K - 2; (j >= 0) && (value > a[j]); j--) { + a[j + 1] = a[j]; /* Shift value */ + idx[j + 1] = idx[j]; /* Shift index */ + } + a[j + 1] = value; /* Write value */ + idx[j + 1] = i; /* Write index */ + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +void SilkDecoder::silk_insertion_sort_increasing_all_values_int16(int16_t* a, /* I/O Unsorted / Sorted vector */ + const int32_t L /* I Vector length */ +) { + int32_t value; + int32_t i, j; + + /* Safety checks */ + assert(L > 0); + + /* Sort vector elements by value, increasing order */ + for (i = 1; i < L; i++) { + value = a[i]; + for (j = i - 1; (j >= 0) && (value < a[j]); j--) { a[j + 1] = a[j]; /* Shift value */ } + a[j + 1] = value; /* Write value */ + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void SilkDecoder::silk_sum_sqr_shift(int32_t* energy, /* O Energy of x, after shifting to the right */ + int32_t* shift, /* O Number of bits right shift applied to energy */ + const int16_t* x, /* I Input vector */ + int32_t len /* I Length of input vector */ +) { + int32_t i, shft; + uint32_t nrg_tmp; + int32_t nrg; + + /* Do a first run with the maximum shift we could have. */ + shft = 31 - silk_CLZ32(len); + /* Let's be conservative with rounding and start with nrg=len. */ + nrg = len; + for (i = 0; i < len - 1; i += 2) { + nrg_tmp = silk_SMULBB(x[i], x[i]); + nrg_tmp = silk_SMLABB_ovflw(nrg_tmp, x[i + 1], x[i + 1]); + nrg = (int32_t)silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); + } + if (i < len) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB(x[i], x[i]); + nrg = (int32_t)silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); + } + assert(nrg >= 0); + /* Make sure the result will fit in a 32-bit signed integer with two bits + of headroom. */ + shft = silk_max_32(0, shft + 3 - silk_CLZ32(nrg)); + nrg = 0; + for (i = 0; i < len - 1; i += 2) { + nrg_tmp = silk_SMULBB(x[i], x[i]); + nrg_tmp = silk_SMLABB_ovflw(nrg_tmp, x[i + 1], x[i + 1]); + nrg = (int32_t)silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); + } + if (i < len) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB(x[i], x[i]); + nrg = (int32_t)silk_ADD_RSHIFT_uint(nrg, nrg_tmp, shft); + } + + assert(nrg >= 0); + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void SilkDecoder::silk_VQ_WMat_EC_c(int8_t* ind, /* O index of best codebook vector */ + int32_t* res_nrg_Q15, /* O best residual energy */ + int32_t* rate_dist_Q8, /* O best total bitrate */ + int32_t* gain_Q7, /* O sum of absolute LTP coefficients */ + const int32_t* XX_Q17, /* I correlation matrix */ + const int32_t* xX_Q17, /* I correlation vector */ + const int8_t* cb_Q7, /* I codebook */ + const uint8_t* cb_gain_Q7, /* I codebook effective gain */ + const uint8_t* cl_Q5, /* I code length for each codebook vector */ + const int32_t subfr_len, /* I number of samples per subframe */ + const int32_t max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const int32_t L /* I number of vectors in codebook */ +) { + int32_t k, gain_tmp_Q7; + const int8_t* cb_row_Q7; + int32_t neg_xX_Q24[5]; + int32_t sum1_Q15, sum2_Q24; + int32_t bits_res_Q8, bits_tot_Q8; + + /* Negate and convert to new Q domain */ + neg_xX_Q24[0] = -silk_LSHIFT32(xX_Q17[0], 7); + neg_xX_Q24[1] = -silk_LSHIFT32(xX_Q17[1], 7); + neg_xX_Q24[2] = -silk_LSHIFT32(xX_Q17[2], 7); + neg_xX_Q24[3] = -silk_LSHIFT32(xX_Q17[3], 7); + neg_xX_Q24[4] = -silk_LSHIFT32(xX_Q17[4], 7); + + /* Loop over codebook */ + *rate_dist_Q8 = silk_int32_MAX; + *res_nrg_Q15 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + /* In things go really bad, at least *ind is set to something safe. */ + *ind = 0; + for (k = 0; k < L; k++) { + int32_t penalty; + gain_tmp_Q7 = cb_gain_Q7[k]; + /* Weighted rate */ + /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ + sum1_Q15 = SILK_FIX_CONST(1.001, 15); + + /* Penalty for too large gain */ + penalty = silk_LSHIFT32(silk_max(silk_SUB32(gain_tmp_Q7, max_gain_Q7), 0), 11); + + /* first row of XX_Q17 */ + sum2_Q24 = silk_MLA(neg_xX_Q24[0], XX_Q17[1], cb_row_Q7[1]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[2], cb_row_Q7[2]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[3], cb_row_Q7[3]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[4], cb_row_Q7[4]); + sum2_Q24 = silk_LSHIFT32(sum2_Q24, 1); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[0], cb_row_Q7[0]); + sum1_Q15 = silk_SMLAWB(sum1_Q15, sum2_Q24, cb_row_Q7[0]); + + /* second row of XX_Q17 */ + sum2_Q24 = silk_MLA(neg_xX_Q24[1], XX_Q17[7], cb_row_Q7[2]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[8], cb_row_Q7[3]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[9], cb_row_Q7[4]); + sum2_Q24 = silk_LSHIFT32(sum2_Q24, 1); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[6], cb_row_Q7[1]); + sum1_Q15 = silk_SMLAWB(sum1_Q15, sum2_Q24, cb_row_Q7[1]); + + /* third row of XX_Q17 */ + sum2_Q24 = silk_MLA(neg_xX_Q24[2], XX_Q17[13], cb_row_Q7[3]); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[14], cb_row_Q7[4]); + sum2_Q24 = silk_LSHIFT32(sum2_Q24, 1); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[12], cb_row_Q7[2]); + sum1_Q15 = silk_SMLAWB(sum1_Q15, sum2_Q24, cb_row_Q7[2]); + + /* fourth row of XX_Q17 */ + sum2_Q24 = silk_MLA(neg_xX_Q24[3], XX_Q17[19], cb_row_Q7[4]); + sum2_Q24 = silk_LSHIFT32(sum2_Q24, 1); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[18], cb_row_Q7[3]); + sum1_Q15 = silk_SMLAWB(sum1_Q15, sum2_Q24, cb_row_Q7[3]); + + /* last row of XX_Q17 */ + sum2_Q24 = silk_LSHIFT32(neg_xX_Q24[4], 1); + sum2_Q24 = silk_MLA(sum2_Q24, XX_Q17[24], cb_row_Q7[4]); + sum1_Q15 = silk_SMLAWB(sum1_Q15, sum2_Q24, cb_row_Q7[4]); + + /* find best */ + if (sum1_Q15 >= 0) { + /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */ + bits_res_Q8 = silk_SMULBB(subfr_len, silk_lin2log(sum1_Q15 + penalty) - (15 << 7)); + /* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality + */ + bits_tot_Q8 = silk_ADD_LSHIFT32(bits_res_Q8, cl_Q5[k], 3 - 1); + if (bits_tot_Q8 <= *rate_dist_Q8) { + *rate_dist_Q8 = bits_tot_Q8; + *res_nrg_Q15 = sum1_Q15 + penalty; + *ind = (int8_t)k; + *gain_Q7 = gain_tmp_Q7; + } + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} +//----------------------------------------------------------------------------------------------------------- +/* Find least-squares prediction gain for one signal based on another and quantize it */ +int32_t SilkDecoder::silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + int32_t* ratio_Q14, /* O Ratio of residual and mid energies */ + const int16_t x[], /* I Basis signal */ + const int16_t y[], /* I Target signal */ + int32_t mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + int32_t length, /* I Number of samples */ + int32_t smooth_coef_Q16 /* I Smoothing coefficient */ +) { + int32_t scale, scale1, scale2; + int32_t nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift(&nrgx, &scale1, x, length); + silk_sum_sqr_shift(&nrgy, &scale2, y, length); + scale = silk_max_int(scale1, scale2); + scale = scale + (scale & 1); /* make even */ + nrgy = silk_RSHIFT32(nrgy, scale - scale2); + nrgx = silk_RSHIFT32(nrgx, scale - scale1); + nrgx = silk_max_int(nrgx, 1); + corr = silk_inner_prod_aligned_scale(x, y, scale, length); + pred_Q13 = silk_DIV32_varQ(corr, nrgx, 13); + pred_Q13 = silk_LIMIT(pred_Q13, -(1 << 14), 1 << 14); + pred2_Q10 = silk_SMULWB(pred_Q13, pred_Q13); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (int32_t)silk_max_int(smooth_coef_Q16, silk_abs(pred2_Q10)); + + /* Smoothed mid and residual norms */ + assert(smooth_coef_Q16 < 32768); + scale = silk_RSHIFT(scale, 1); + mid_res_amp_Q0[0] = silk_SMLAWB(mid_res_amp_Q0[0], silk_LSHIFT(silk_SQRT_APPROX(nrgx), scale) - mid_res_amp_Q0[0], smooth_coef_Q16); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32(nrgy, silk_SMULWB(corr, pred_Q13), 3 + 1); + nrgy = silk_ADD_LSHIFT32(nrgy, silk_SMULWB(nrgx, pred2_Q10), 6); + mid_res_amp_Q0[1] = silk_SMLAWB(mid_res_amp_Q0[1], silk_LSHIFT(silk_SQRT_APPROX(nrgy), scale) - mid_res_amp_Q0[1], smooth_coef_Q16); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ(mid_res_amp_Q0[1], silk_max(mid_res_amp_Q0[0], 1), 14); + *ratio_Q14 = silk_LIMIT(*ratio_Q14, 0, 32767); + + return pred_Q13; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void SilkDecoder::silk_stereo_MS_to_LR(stereo_dec_state_t* state, /* I/O State */ + int16_t x1[], /* I/O Left input signal, becomes mid signal */ + int16_t x2[], /* I/O Right input signal, becomes side signal */ + const int32_t pred_Q13[], /* I Predictors */ + int32_t fs_kHz, /* I Samples rate (kHz) */ + int32_t frame_length /* I Number of samples */ +) { + int32_t n, denom_Q16, delta0_Q13, delta1_Q13; + int32_t sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + memcpy(x1, state->sMid, 2 * sizeof(int16_t)); + memcpy(x2, state->sSide, 2 * sizeof(int16_t)); + memcpy(state->sMid, &x1[frame_length], 2 * sizeof(int16_t)); + memcpy(state->sSide, &x2[frame_length], 2 * sizeof(int16_t)); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[0]; + pred1_Q13 = state->pred_prev_Q13[1]; + denom_Q16 = silk_DIV32_16((int32_t)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz); + delta0_Q13 = silk_RSHIFT_ROUND(silk_SMULBB(pred_Q13[0] - state->pred_prev_Q13[0], denom_Q16), 16); + delta1_Q13 = silk_RSHIFT_ROUND(silk_SMULBB(pred_Q13[1] - state->pred_prev_Q13[1], denom_Q16), 16); + for (n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT(silk_ADD_LSHIFT(x1[n] + x1[n + 2], x1[n + 1], 1), 9); /* Q11 */ + sum = silk_SMLAWB(silk_LSHIFT((int32_t)x2[n + 1], 8), sum, pred0_Q13); /* Q8 */ + sum = silk_SMLAWB(sum, silk_LSHIFT((int32_t)x1[n + 1], 11), pred1_Q13); /* Q8 */ + x2[n + 1] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(sum, 8)); + } + pred0_Q13 = pred_Q13[0]; + pred1_Q13 = pred_Q13[1]; + for (n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++) { + sum = silk_LSHIFT(silk_ADD_LSHIFT(x1[n] + x1[n + 2], x1[n + 1], 1), 9); /* Q11 */ + sum = silk_SMLAWB(silk_LSHIFT((int32_t)x2[n + 1], 8), sum, pred0_Q13); /* Q8 */ + sum = silk_SMLAWB(sum, silk_LSHIFT((int32_t)x1[n + 1], 11), pred1_Q13); /* Q8 */ + x2[n + 1] = (int16_t)silk_SAT16(silk_RSHIFT_ROUND(sum, 8)); + } + state->pred_prev_Q13[0] = pred_Q13[0]; + state->pred_prev_Q13[1] = pred_Q13[1]; + + /* Convert to left/right signals */ + for (n = 0; n < frame_length; n++) { + sum = x1[n + 1] + (int32_t)x2[n + 1]; + diff = x1[n + 1] - (int32_t)x2[n + 1]; + x1[n + 1] = (int16_t)silk_SAT16(sum); + x2[n + 1] = (int16_t)silk_SAT16(diff); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Initialization of the Silk VAD */ +int32_t SilkDecoder::silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state_t* psSilk_VAD /* I/O Pointer to Silk VAD state */ +) { + int32_t b, ret = 0; + + /* reset state memory */ + memset(psSilk_VAD, 0, sizeof(silk_VAD_state_t)); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for (b = 0; b < VAD_N_BANDS; b++) { psSilk_VAD->NoiseLevelBias[b] = silk_max_32(silk_DIV32_16(VAD_NOISE_LEVELS_BIAS, b + 1), 1); } + + /* Initialize state */ + for (b = 0; b < VAD_N_BANDS; b++) { + psSilk_VAD->NL[b] = silk_MUL(100, psSilk_VAD->NoiseLevelBias[b]); + psSilk_VAD->inv_NL[b] = silk_DIV32(silk_int32_MAX, psSilk_VAD->NL[b]); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for (b = 0; b < VAD_N_BANDS; b++) { psSilk_VAD->NrgRatioSmth_Q8[b] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ } + + return (ret); +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::setChannelsAPI(uint8_t nChannelsAPI) { + m_silk_DecControlStruct->nChannelsAPI = nChannelsAPI; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::setChannelsInternal(uint8_t nChannelsInternal) { + m_silk_DecControlStruct->nChannelsInternal = nChannelsInternal; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::setAPIsampleRate(uint32_t API_sampleRate) { + m_silk_DecControlStruct->API_sampleRate = API_sampleRate; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void SilkDecoder::combine_pulses(int32_t* out, const int32_t* in, const int32_t len) { + int32_t k; + for (k = 0; k < len; k++) { out[k] = in[2 * k] + in[2 * k + 1]; } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Invert int32 value and return result as int32 in a given Q-domain */ +int32_t SilkDecoder::silk_INVERSE32_varQ(const int32_t b32, const int32_t Qres) { + int32_t b_headrm, lshift; + int32_t b32_inv, b32_nrm, err_Q32, result; + + assert(b32 != 0); + assert(Qres > 0); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32(silk_abs(b32)) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16(silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16)); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT(((int32_t)1 << 29) - silk_SMULWB(b32_nrm, b32_inv), 3); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if (lshift <= 0) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if (lshift < 32) { + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Divide two int32 values and return result as int32 in a given Q-domain */ +int32_t SilkDecoder::silk_DIV32_varQ(const int32_t a32, const int32_t b32, const int32_t Qres) { + int32_t a_headrm, b_headrm, lshift; + int32_t b32_inv, a32_nrm, b32_nrm, result; + + assert(b32 != 0); + assert(Qres >= 0); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32(silk_abs(a32)) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32(silk_abs(b32)) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16(silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16)); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw(silk_SMMUL(b32_nrm, result), 3)); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if (lshift < 0) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if (lshift < 32) { + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Approximation of square root, Accuracy: < +/- 10% for output values > 15, < +/- 2.5% for output values > 120 */ +int32_t SilkDecoder::silk_SQRT_APPROX(int32_t x) { + int32_t y, lz, frac_Q7; + if (x <= 0) { return 0; } + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if (lz & 1) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + y >>= silk_RSHIFT(lz, 1); /* get scaling right */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); /* increment using fractional part of input */ + return y; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* get number of leading zeros and fractional part (the bits right after the leading one */ +void SilkDecoder::silk_CLZ_FRAC(int32_t in, int32_t* lz, int32_t* frac_Q7) { + int32_t lzeros = silk_CLZ32(in); + + *lz = lzeros; + *frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and compile it into a 'ror' instruction if available. No need for inline ASM! */ +int32_t SilkDecoder::silk_ROR32(int32_t a32, int32_t rot) { + uint32_t x = (uint32_t)a32; + uint32_t r = (uint32_t)rot; + uint32_t m = (uint32_t)-rot; + if (rot == 0) { + return a32; + } else if (rot < 0) { + return (int32_t)((x << m) | (x >> (32 - m))); + } else { + return (int32_t)((x << (32 - r)) | (x >> r)); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* count leading zeros of int32_t64 */ +int32_t SilkDecoder::silk_CLZ64(int64_t in) { + int32_t in_upper; + + in_upper = (int32_t)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32((int32_t)in); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32(in_upper); + } +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* silk_min() versions with typecast in the function call */ +int32_t SilkDecoder::silk_min_int(int32_t a, int32_t b) { + return (((a) < (b)) ? (a) : (b)); +} +int16_t SilkDecoder::silk_min_16(int16_t a, int16_t b) { + return (((a) < (b)) ? (a) : (b)); +} +int32_t SilkDecoder::silk_min_32(int32_t a, int32_t b) { + return (((a) < (b)) ? (a) : (b)); +} +int64_t SilkDecoder::silk_min_64(int64_t a, int64_t b) { + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +int32_t SilkDecoder::silk_max_int(int32_t a, int32_t b) { + return (((a) > (b)) ? (a) : (b)); +} +int16_t SilkDecoder::silk_max_16(int16_t a, int16_t b) { + return (((a) > (b)) ? (a) : (b)); +} +int32_t SilkDecoder::silk_max_32(int32_t a, int32_t b) { + return (((a) > (b)) ? (a) : (b)); +} +int64_t SilkDecoder::silk_max_64(int64_t a, int64_t b) { + return (((a) > (b)) ? (a) : (b)); +} + +int32_t SilkDecoder::silk_CLZ16(int16_t in16) { + return 32 - EC_ILOGs(in16 << 16 | 0x8000); +} +int32_t SilkDecoder::silk_CLZ32(int32_t in32) { + return in32 ? 32 - EC_ILOGs(in32) : 32; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t SilkDecoder::silk_noise_shape_quantizer_short_prediction_c(const int32_t* buf32, const int16_t* coef16, int32_t order) { + int32_t out; + assert(order == 10 || order == 16); + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, buf32[0], coef16[0]); + out = silk_SMLAWB(out, buf32[-1], coef16[1]); + out = silk_SMLAWB(out, buf32[-2], coef16[2]); + out = silk_SMLAWB(out, buf32[-3], coef16[3]); + out = silk_SMLAWB(out, buf32[-4], coef16[4]); + out = silk_SMLAWB(out, buf32[-5], coef16[5]); + out = silk_SMLAWB(out, buf32[-6], coef16[6]); + out = silk_SMLAWB(out, buf32[-7], coef16[7]); + out = silk_SMLAWB(out, buf32[-8], coef16[8]); + out = silk_SMLAWB(out, buf32[-9], coef16[9]); + + if (order == 16) { + out = silk_SMLAWB(out, buf32[-10], coef16[10]); + out = silk_SMLAWB(out, buf32[-11], coef16[11]); + out = silk_SMLAWB(out, buf32[-12], coef16[12]); + out = silk_SMLAWB(out, buf32[-13], coef16[13]); + out = silk_SMLAWB(out, buf32[-14], coef16[14]); + out = silk_SMLAWB(out, buf32[-15], coef16[15]); + } + return out; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t SilkDecoder::silk_NSQ_noise_shape_feedback_loop_c(const int32_t* data0, int32_t* data1, const int16_t* coef, int32_t order) { + int32_t out; + int32_t tmp1, tmp2; + int32_t j; + + tmp2 = data0[0]; + tmp1 = data1[0]; + data1[0] = tmp2; + + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, tmp2, coef[0]); + + for (j = 2; j < order; j += 2) { + tmp2 = data1[j - 1]; + data1[j - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[j - 1]); + tmp1 = data1[j + 0]; + data1[j + 0] = tmp2; + out = silk_SMLAWB(out, tmp2, coef[j]); + } + data1[order - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[order - 1]); + /* Q11 -> Q12 */ + out = silk_LSHIFT32(out, 1); + return out; +} \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/silk.h b/libraries/ESP32-audioI2S/src/opus_decoder/silk.h new file mode 100644 index 0000000..4ec8872 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/silk.h @@ -0,0 +1,312 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#pragma once +#include +#include "../psram_unique_ptr.hpp" +#include "opus_decoder.h" +#include "silk_defines.h" +#include "silk_tables.h" +#include "silk_structs.h" +#include "range_decoder.h" + +extern const int16_t silk_LSFCosTab_FIX_Q12[LSF_COS_TAB_SZ_FIX + 1]; +extern const int16_t silk_stereo_pred_quant_Q13[STEREO_QUANT_TAB_SIZE]; +extern const uint8_t silk_stereo_pred_joint_iCDF[25]; +extern const uint8_t silk_stereo_only_code_mid_iCDF[2]; +extern const uint8_t silk_LBRR_flags_2_iCDF[3]; +extern const uint8_t silk_LBRR_flags_3_iCDF[7]; +extern const uint8_t* const silk_LBRR_flags_iCDF_ptr[2]; +extern const uint8_t silk_lsb_iCDF[2]; +extern const uint8_t silk_LTPscale_iCDF[3]; +extern const uint8_t silk_type_offset_VAD_iCDF[4]; +extern const uint8_t silk_type_offset_no_VAD_iCDF[2]; +extern const uint8_t silk_NLSF_interpolation_factor_iCDF[5]; +extern const int16_t silk_Quantization_Offsets_Q10[2][2]; +extern const int16_t silk_LTPScales_table_Q14[3]; +extern const uint8_t silk_uniform3_iCDF[3]; +extern const uint8_t silk_uniform4_iCDF[4]; +extern const uint8_t silk_uniform5_iCDF[5]; +extern const uint8_t silk_uniform6_iCDF[6]; +extern const uint8_t silk_uniform8_iCDF[8]; +extern const uint8_t silk_NLSF_EXT_iCDF[7]; +extern const int32_t silk_Transition_LP_B_Q28[TRANSITION_INT_NUM][TRANSITION_NB]; +extern const int32_t silk_Transition_LP_A_Q28[TRANSITION_INT_NUM][TRANSITION_NA]; +extern const uint8_t silk_max_pulses_table[4]; +extern const uint8_t silk_pulses_per_block_iCDF[10][18]; +extern const uint8_t silk_rate_levels_iCDF[2][9]; +extern const uint8_t silk_rate_levels_BITS_Q5[2][9]; +extern const uint8_t silk_shell_code_table0[152]; +extern const uint8_t silk_shell_code_table1[152]; +extern const uint8_t silk_shell_code_table2[152]; +extern const uint8_t silk_shell_code_table3[152]; +extern const uint8_t silk_shell_code_table_offsets[17]; +extern const uint8_t silk_sign_iCDF[42]; +extern const uint8_t silk_NLSF_CB1_NB_MB_Q8[320]; +extern const int16_t silk_NLSF_CB1_Wght_Q9[320]; +extern const uint8_t silk_NLSF_CB1_iCDF_NB_MB[64]; +extern const uint8_t silk_NLSF_CB2_SELECT_NB_MB[160]; +extern const uint8_t silk_NLSF_CB2_iCDF_NB_MB[72]; +extern const uint8_t silk_NLSF_CB2_BITS_NB_MB_Q5[72]; +extern const uint8_t silk_NLSF_PRED_NB_MB_Q8[18]; +extern const int16_t silk_NLSF_DELTA_MIN_NB_MB_Q15[11]; +extern const uint8_t silk_gain_iCDF[3][N_LEVELS_QGAIN / 8]; +extern const uint8_t silk_delta_gain_iCDF[MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1]; +extern const uint8_t silk_pitch_lag_iCDF[2 * (PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS)]; +extern const uint8_t silk_pitch_delta_iCDF[21]; +extern const uint8_t silk_pitch_contour_iCDF[34]; +extern const uint8_t silk_pitch_contour_NB_iCDF[11]; +extern const uint8_t silk_pitch_contour_10_ms_iCDF[12]; +extern const uint8_t silk_pitch_contour_10_ms_NB_iCDF[3]; +extern const uint8_t silk_LTP_per_index_iCDF[3]; +extern const uint8_t silk_LTP_gain_iCDF_0[8]; +extern const uint8_t silk_LTP_gain_iCDF_1[16]; +extern const uint8_t silk_LTP_gain_iCDF_2[32]; +extern const uint8_t silk_LTP_gain_BITS_Q5_0[8]; +extern const uint8_t silk_LTP_gain_BITS_Q5_1[16]; +extern const uint8_t silk_LTP_gain_BITS_Q5_2[32]; +extern const uint8_t* const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS]; +extern const uint8_t* const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS]; +extern const int8_t silk_LTP_gain_vq_0[8][5]; +extern const int8_t silk_LTP_gain_vq_1[16][5]; +extern const int8_t silk_LTP_gain_vq_2[32][5]; +extern const uint8_t silk_NLSF_CB1_WB_Q8[512]; +extern const int16_t silk_NLSF_CB1_WB_Wght_Q9[512]; +extern const uint8_t silk_NLSF_CB1_iCDF_WB[64]; +extern const uint8_t silk_NLSF_CB2_SELECT_WB[256]; +extern const uint8_t silk_NLSF_CB2_iCDF_WB[72]; +extern const uint8_t silk_NLSF_CB2_BITS_WB_Q5[72]; +extern const uint8_t silk_NLSF_PRED_WB_Q8[30]; +extern const int16_t silk_NLSF_DELTA_MIN_WB_Q15[17]; +extern const int8_t silk_CB_lags_stage2_10_ms[PE_MAX_NB_SUBFR >> 1][PE_NB_CBKS_STAGE2_10MS]; +extern const int8_t silk_CB_lags_stage3_10_ms[PE_MAX_NB_SUBFR >> 1][PE_NB_CBKS_STAGE3_10MS]; +extern const int8_t silk_CB_lags_stage3_10_ms[PE_MAX_NB_SUBFR >> 1][PE_NB_CBKS_STAGE3_10MS]; +extern const int8_t silk_Lag_range_stage3_10_ms[PE_MAX_NB_SUBFR >> 1][2]; +extern const int8_t silk_CB_lags_stage2[PE_MAX_NB_SUBFR][PE_NB_CBKS_STAGE2_EXT]; +extern const int8_t silk_CB_lags_stage3[PE_MAX_NB_SUBFR][PE_NB_CBKS_STAGE3_MAX]; +extern const int8_t silk_Lag_range_stage3[SILK_PE_MAX_COMPLEX + 1][PE_MAX_NB_SUBFR][2]; +extern const int8_t delay_matrix_enc[5][3]; +extern const int8_t delay_matrix_dec[3][5]; +extern const int16_t silk_Resampler_3_4_COEFS[2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2]; +extern const int16_t silk_Resampler_2_3_COEFS[2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2]; +extern const int16_t silk_Resampler_1_2_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR1 / 2]; +extern const int16_t silk_Resampler_1_3_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]; +extern const int16_t silk_Resampler_1_4_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]; +extern const int16_t silk_Resampler_1_6_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2]; +extern const int16_t silk_Resampler_2_3_COEFS_LQ[2 + 2 * 2]; +extern const int16_t silk_resampler_frac_FIR_12[12][RESAMPLER_ORDER_FIR_12 / 2]; +extern const int16_t HARM_ATT_Q15[NB_ATT]; +extern const int16_t PLC_RAND_ATTENUATE_V_Q15[NB_ATT]; +extern const int16_t PLC_RAND_ATTENUATE_UV_Q15[NB_ATT]; +extern const int16_t silk_resampler_down2_0; +extern const int16_t silk_resampler_down2_1; +extern const int16_t silk_resampler_up2_hq_0[3]; +extern const int16_t silk_resampler_up2_hq_1[3]; +extern const int32_t sigm_LUT_slope_Q10[6]; +extern const int32_t sigm_LUT_pos_Q15[6]; +extern const int32_t sigm_LUT_neg_Q15[6]; +extern const int8_t silk_nb_cbk_searchs_stage3[SILK_PE_MAX_COMPLEX + 1]; + + +class SilkDecoder{ +public: + SilkDecoder(RangeDecoder& rangeDecoder) : rd(rangeDecoder) {} + ~SilkDecoder() {reset();} + bool init(); + void clear(); + void reset(); + int32_t silk_InitDecoder(); + void setChannelsAPI(uint8_t nChannelsAPI); + void setChannelsInternal(uint8_t nChannelsInternal); + void setAPIsampleRate(uint32_t API_sampleRate); + void silk_setRawParams(uint8_t channels, uint8_t API_channels, uint8_t payloadSize_ms, uint32_t internalSampleRate, uint32_t API_samleRate); + int32_t silk_Decode(int32_t lostFlag, int32_t newPacketFlag, int16_t *samplesOut, int32_t *nSamplesOut); + +private: + RangeDecoder& rd; // Referenz auf RangeDecoder + + ps_ptr m_resampler_state; + ps_ptr m_channel_state; + ps_ptr m_silk_decoder; + ps_ptr m_silk_decoder_control; + ps_ptr m_silk_DecControlStruct; + + uint8_t m_channelsInternal = 0; + uint8_t m_payloadSize_ms = 0; + uint8_t m_API_channels = 0; + uint32_t m_silk_internalSampleRate = 0; + uint32_t m_API_sampleRate = 0; + uint32_t m_prevPitchLag = 0; + + /* Coefficients for 2-band filter bank based on first-order allpass filters */ + int16_t A_fb1_20 = 5394 << 1; + int16_t A_fb1_21 = -24290; /* (int16_t)(20623 << 1) */ + + const silk_NLSF_CB_struct_t silk_NLSF_CB_WB = { + 32, + 16, + SILK_FIX_CONST(0.15, 16), + SILK_FIX_CONST(1.0 / 0.15, 6), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_WB_Wght_Q9, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, + }; + + const int8_t* const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = {(int8_t*)&silk_LTP_gain_vq_0[0][0], (int8_t*)&silk_LTP_gain_vq_1[0][0], (int8_t*)&silk_LTP_gain_vq_2[0][0]}; + + /* Maximum frequency-dependent response of the pitch taps above, + computed as max(abs(freqz(taps))) */ + const uint8_t silk_LTP_gain_vq_0_gain[8] = {46, 2, 90, 87, 93, 91, 82, 98}; + + const uint8_t silk_LTP_gain_vq_1_gain[16] = {109, 120, 118, 12, 113, 115, 117, 119, 99, 59, 87, 111, 63, 111, 112, 80}; + + const uint8_t silk_LTP_gain_vq_2_gain[32] = {126, 124, 125, 124, 129, 121, 126, 23, 132, 127, 127, 127, 126, 127, 122, 133, + 130, 134, 101, 118, 119, 145, 126, 86, 124, 120, 123, 119, 170, 173, 107, 109}; + + const uint8_t* const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = {&silk_LTP_gain_vq_0_gain[0], &silk_LTP_gain_vq_1_gain[0], &silk_LTP_gain_vq_2_gain[0]}; + + const int8_t silk_LTP_vq_sizes[NB_LTP_CBKS] = {8, 16, 32}; + + const silk_NLSF_CB_struct_t silk_NLSF_CB_NB_MB = { + 32, + 10, + SILK_FIX_CONST(0.18, 16), + SILK_FIX_CONST(1.0 / 0.18, 6), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_Wght_Q9, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, + }; +//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + void silk_ana_filt_bank_1(const int16_t *in, int32_t *S, int16_t *outL, int16_t *outH, const int32_t N); + void silk_biquad_alt_stride1(const int16_t *in, const int32_t *B_Q28, const int32_t *A_Q28, int32_t *S,int16_t *out, const int32_t len); + void silk_biquad_alt_stride2_c(const int16_t *in, const int32_t *B_Q28, const int32_t *A_Q28, int32_t *S, int16_t *out, const int32_t len); + void silk_bwexpander_32(int32_t *ar, const int32_t d, int32_t chirp_Q16); + void silk_bwexpander(int16_t *ar, const int32_t d, int32_t chirp_Q16); + void silk_stereo_decode_pred(int32_t pred_Q13[]); + void silk_stereo_decode_mid_only(int32_t *decode_only_mid); + void silk_PLC_Reset(uint8_t n); + void silk_PLC(uint8_t n, int16_t frame[], int32_t lost); + void silk_PLC_glue_frames(uint8_t, int16_t frame[], int32_t length); + void silk_LP_interpolate_filter_taps(int32_t B_Q28[TRANSITION_NB], int32_t A_Q28[TRANSITION_NA], const int32_t ind, const int32_t fac_Q16); + void silk_LP_variable_cutoff(silk_LP_state_t *psLP, int16_t *frame, const int32_t frame_length); + void silk_NLSF_unpack(int16_t ec_ix[], uint8_t pred_Q8[], const silk_NLSF_CB_struct_t *psNLSF_CB, const int32_t CB1_index); + void silk_NLSF_decode(int16_t *pNLSF_Q15, int8_t *NLSFIndices, const silk_NLSF_CB_struct_t *psNLSF_CB); + int32_t silk_decoder_set_fs(uint8_t n, int32_t fs_kHz, int32_t fs_API_Hz); + int32_t combine_and_check(int32_t* pulses_comb, const int32_t* pulses_in, int32_t max_pulses, int32_t len); + void silk_decode_indices(uint8_t n, int32_t FrameIndex, int32_t decode_LBRR, int32_t condCoding); + void silk_decode_parameters(uint8_t n, int32_t condCoding); + void silk_decode_core(uint8_t n, int16_t xq[], const int16_t pulses[MAX_FRAME_LENGTH]); + void silk_decode_pulses(int16_t pulses[], const int32_t signalType, const int32_t quantOffsetType, const int32_t frame_length); + int32_t silk_init_decoder(uint8_t n); + int32_t silk_NLSF_del_dec_quant(int8_t indices[], const int16_t x_Q10[], const int16_t w_Q5[], const uint8_t pred_coef_Q8[], const int16_t ec_ix[], const uint8_t ec_rates_Q5[], + const int32_t quant_step_size_Q16, const int16_t inv_quant_step_size_Q6, const int32_t mu_Q20, const int16_t order); + void silk_NLSF_VQ(int32_t err_Q26[], const int16_t in_Q15[], const uint8_t pCB_Q8[], const int16_t pWght_Q9[], const int32_t K, const int32_t LPC_order); + int32_t silk_VAD_Init(silk_VAD_state_t *psSilk_VAD); + void silk_stereo_MS_to_LR(stereo_dec_state_t *state, int16_t x1[], int16_t x2[], const int32_t pred_Q13[], int32_t fs_kHz, int32_t frame_length); + int32_t silk_stereo_find_predictor(int32_t *ratio_Q14, const int16_t x[], const int16_t y[], int32_t mid_res_amp_Q0[], int32_t length, int32_t smooth_coef_Q16); + void silk_stereo_quant_pred(int32_t pred_Q13[], int8_t ix[2][3]); + void silk_decode_signs(int16_t pulses[], int32_t length, const int32_t signalType, const int32_t quantOffsetType, const int32_t sum_pulses[MAX_NB_SHELL_BLOCKS]); + void silk_shell_decoder(int16_t *pulses0, const int32_t pulses4); + void silk_gains_quant(int8_t ind[MAX_NB_SUBFR], int32_t gain_Q16[MAX_NB_SUBFR], int8_t *prev_ind, const int32_t conditional, const int32_t nb_subfr); + void silk_gains_dequant(int32_t gain_Q16[MAX_NB_SUBFR], const int8_t ind[MAX_NB_SUBFR], int8_t *prev_ind, const int32_t conditional, const int32_t nb_subfr); + int32_t silk_gains_ID(const int8_t ind[MAX_NB_SUBFR], const int32_t nb_subfr); + void silk_interpolate(int16_t xi[MAX_LPC_ORDER], const int16_t x0[MAX_LPC_ORDER], const int16_t x1[MAX_LPC_ORDER], const int32_t ifact_Q2, const int32_t d); + void silk_quant_LTP_gains(int16_t B_Q14[MAX_NB_SUBFR * LTP_ORDER], int8_t cbk_index[MAX_NB_SUBFR], int8_t *periodicity_index, int32_t *sum_gain_dB_Q7, int32_t *pred_gain_dB_Q7, + const int32_t XX_Q17[MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER], const int32_t xX_Q17[MAX_NB_SUBFR * LTP_ORDER], const int32_t subfr_len, const int32_t nb_subfr); + void decode_split(int16_t *p_child1, int16_t *p_child2, const int32_t p, const uint8_t *shell_table); + void silk_VQ_WMat_EC_c(int8_t *ind, int32_t *res_nrg_Q15, int32_t *rate_dist_Q8, int32_t *gain_Q7, const int32_t *XX_Q17, const int32_t *xX_Q17, const int8_t *cb_Q7, const uint8_t *cb_gain_Q7, + const uint8_t *cl_Q5, const int32_t subfr_len, const int32_t max_gain_Q7, const int32_t L); + void silk_CNG_Reset(uint8_t n); + void silk_CNG(uint8_t n, int16_t frame[], int32_t length); + int32_t silk_Get_Decoder_Size(int32_t *decSizeBytes); + void silk_NLSF2A_find_poly(int32_t *out, const int32_t *cLSF, int32_t dd); + void silk_NLSF2A(int16_t *a_Q12, const int16_t *NLSF, const int32_t d); + void silk_CNG_exc(int32_t exc_Q14[], int32_t exc_buf_Q14[], int32_t length, int32_t *rand_seed); + int32_t silk_decode_frame(uint8_t n, int16_t pOut[], int32_t *pN, int32_t lostFlag, int32_t condCoding); + void silk_decode_pitch(int16_t lagIndex, int8_t contourIndex, int32_t pitch_lags[], const int32_t Fs_kHz, const int32_t nb_subfr); + int32_t silk_inner_prod_aligned_scale(const int16_t *const inVec1, const int16_t *const inVec2, const int32_t scale, const int32_t len); + int32_t silk_lin2log(const int32_t inLin); + int32_t silk_log2lin(const int32_t inLog_Q7); + void silk_LPC_analysis_filter(int16_t *out, const int16_t *in, const int16_t *B, const int32_t len, const int32_t d); + void silk_LPC_fit(int16_t *a_QOUT, int32_t *a_QIN, const int32_t QOUT, const int32_t QIN, const int32_t d); + int32_t LPC_inverse_pred_gain_QA_c(int32_t A_QA[SILK_MAX_ORDER_LPC], const int32_t order); + int32_t silk_LPC_inverse_pred_gain_c(const int16_t *A_Q12, const int32_t order); + void silk_NLSF_residual_dequant(int16_t x_Q10[], const int8_t indices[], const uint8_t pred_coef_Q8[], const int32_t quant_step_size_Q16, const int16_t order); + void silk_NLSF_stabilize(int16_t *NLSF_Q15, const int16_t *NDeltaMin_Q15, const int32_t L); + void silk_NLSF_VQ_weights_laroia(int16_t *pNLSFW_Q_OUT, const int16_t *pNLSF_Q15, const int32_t D); + void silk_PLC_update(uint8_t n); + void silk_PLC_energy(int32_t *energy1, int32_t *shift1, int32_t *energy2, int32_t *shift2, const int32_t *exc_Q14, const int32_t *prevGain_Q10, int subfr_length, int nb_subfr); + void silk_PLC_conceal(uint8_t n, int16_t frame[]); + void silk_resampler_down2(int32_t *S, int16_t *out, const int16_t *in, int32_t inLen); + void silk_resampler_private_AR2(int32_t S[], int32_t out_Q8[], const int16_t in[], const int16_t A_Q14[], int32_t len); + int16_t *silk_resampler_private_down_FIR_INTERPOL(int16_t *out, int32_t *buf, const int16_t *FIR_Coefs, int32_t FIR_Order, int32_t FIR_Fracs, int32_t max_index_Q16, int32_t index_increment_Q16); + void silk_resampler_private_down_FIR(void *SS, int16_t out[], const int16_t in[], int32_t inLen); + int16_t *silk_resampler_private_IIR_FIR_INTERPOL(int16_t *out, int16_t *buf, int32_t max_index_Q16, int32_t index_increment_Q16); + void silk_resampler_private_IIR_FIR(void *SS, int16_t out[], const int16_t in[], int32_t inLen); + void silk_resampler_private_up2_HQ(int32_t *S, int16_t *out, const int16_t *in, int32_t len); + void silk_resampler_private_up2_HQ_wrapper(void *SS, int16_t *out, const int16_t *in, int32_t len); + int32_t silk_resampler_init(uint8_t n, int32_t Fs_Hz_in, int32_t Fs_Hz_out, int32_t forEnc); + int32_t silk_resampler(uint8_t n, int16_t out[], const int16_t in[], int32_t inLen); + int32_t silk_sigm_Q15(int32_t in_Q5); + void silk_insertion_sort_increasing(int32_t *a, int32_t *idx, const int32_t L, const int32_t K); + void silk_insertion_sort_decreasing_int16(int16_t *a, int32_t *idx, const int32_t L, const int32_t K); + void silk_insertion_sort_increasing_all_values_int16(int16_t *a, const int32_t L); + void silk_sum_sqr_shift(int32_t *energy, int32_t *shift, const int16_t *x, int32_t len); + void combine_pulses(int32_t *out, const int32_t *in, const int32_t len); + int32_t silk_INVERSE32_varQ(const int32_t b32, const int32_t Qres); + int32_t silk_DIV32_varQ(const int32_t a32, const int32_t b32, const int32_t Qres); + int32_t silk_SQRT_APPROX(int32_t x); + void silk_CLZ_FRAC(int32_t in, int32_t *lz, int32_t *frac_Q7); + uint32_t silk_getPrevPitchLag(); + int32_t silk_ROR32(int32_t a32, int32_t rot); + int32_t silk_CLZ64(int64_t in); + int32_t silk_min_int(int32_t a, int32_t b); + int16_t silk_min_16(int16_t a, int16_t b); + int32_t silk_min_32(int32_t a, int32_t b); + int64_t silk_min_64(int64_t a, int64_t b); + + /* silk_min() versions with typecast in the function call */ + int32_t silk_max_int(int32_t a, int32_t b); + int16_t silk_max_16(int16_t a, int16_t b); + int32_t silk_max_32(int32_t a, int32_t b); + int64_t silk_max_64(int64_t a, int64_t b); + int32_t silk_noise_shape_quantizer_short_prediction_c(const int32_t *buf32, const int16_t *coef16, int32_t order); + int32_t silk_NSQ_noise_shape_feedback_loop_c(const int32_t *data0, int32_t *data1, const int16_t *coef, int32_t order); + int32_t silk_CLZ16(int16_t in16); + int32_t silk_CLZ32(int32_t in32); +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/silk_defines.h b/libraries/ESP32-audioI2S/src/opus_decoder/silk_defines.h new file mode 100644 index 0000000..f0b677e --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/silk_defines.h @@ -0,0 +1,336 @@ +#pragma once + + #define SILK_MAX_FRAMES_PER_PACKET 3 + /* Decoder API flags */ + #define FLAG_DECODE_NORMAL 0 + #define FLAG_PACKET_LOST 1 + #define FLAG_DECODE_LBRR 2 + #define SILK_ALLOC_NONE 1 + /* Number of binary divisions, when not in low complexity mode */ + #define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ + #define MAX_ITERATIONS_A2NLSF_FIX 16 + + /* Fixed point macros */ + #define silk_MUL(a32, b32) ((a32) * (b32)) /* (a32 * b32) output have to be 32bit int */ + #define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) /* (a32 * b32) output have to be 32bit uint */ + #define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) /* a32 + (b32 * c32) output have to be 32bit int */ + #define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) /* a32 + (b32 * c32) output have to be 32bit uint */ + #define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) /* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ + #define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) /* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ + #define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(int64_t)((int32_t)(b16) * (int32_t)(c16))) + #define silk_SMULL(a32, b32) ((int64_t)(a32) * /*(int64_t)*/(b32)) /* (a32 * b32) */ + #define silk_ADD32_ovflw(a, b) ((int32_t)((uint32_t)(a) + (uint32_t)(b))) /* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour (just standard two's complement implementation-specific behaviour) */ + #define silk_SUB32_ovflw(a, b) ((int32_t)((uint32_t)(a) - (uint32_t)(b))) /* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour (just standard two's complement implementation-specific behaviour) */ + #define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (uint32_t)(b32) * (uint32_t)(c32)) /* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ + #define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((int32_t)((int16_t)(b32))) * (int32_t)((int16_t)(c32)))) + #define silk_DIV32_16(a32, b16) ((int32_t)((a32) / (b16))) + #define silk_DIV32(a32, b32) ((int32_t)((a32) / (b32))) + #define silk_ADD16(a, b) ((a) + (b)) /* These macros enables checking for overflow in silk_API_Debug.h*/ + #define silk_ADD32(a, b) ((a) + (b)) + #define silk_ADD64(a, b) ((a) + (b)) + #define silk_SUB16(a, b) ((a) - (b)) + #define silk_SUB32(a, b) ((a) - (b)) + #define silk_SUB64(a, b) ((a) - (b)) + #define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) + #define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) + #define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + #define silk_CHECK_FIT8(a) (a) + #define silk_CHECK_FIT16(a) (a) + #define silk_CHECK_FIT32(a) (a) + #define silk_ADD_SAT16(a, b) (int16_t)silk_SAT16( silk_ADD32( (int32_t)(a), (b) ) ) + #define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + #define silk_SUB_SAT16(a, b) (int16_t)silk_SAT16( silk_SUB32( (int32_t)(a), (b) ) ) + #define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + #define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) /* Saturation for positive input values */ + #define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) /* Add with saturation for positive input values */ + #define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) + #define silk_ADD_POS_SAT32(a, b) ((((uint32_t)(a)+(uint32_t)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) + #define silk_LSHIFT8(a, shift) ((int32_t8)((uint8_t)(a)<<(shift))) /* shift >= 0, shift < 8 */ + #define silk_LSHIFT16(a, shift) ((int16_t)((uint16_t)(a)<<(shift))) /* shift >= 0, shift < 16 */ + #define silk_LSHIFT32(a, shift) ((int32_t)((uint32_t)(a)<<(shift))) /* shift >= 0, shift < 32 */ + #define silk_LSHIFT64(a, shift) ((int64_t)((uint64_t)(a)<<(shift))) /* shift >= 0, shift < 64 */ + #define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + #define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ + #define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ + #define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ + #define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ + #define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + #define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + #define silk_LSHIFT_ovflw(a, shift) ((int32_t)((uint32_t)(a) << (shift))) /* shift >= 0, allowed to overflow */ + #define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ + #define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + #define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ + #define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ + #define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ + #define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ + #define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + #define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ + #define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ + #define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + #define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) /* Requires that shift > 0 */ + #define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + #define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) /* Number of rightshift required to fit the multiplication */ + #define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + #define silk_min(a, b) (((a) < (b)) ? (a) : (b)) + #define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + #define MIN_QGAIN_DB 2 /* dB level of lowest gain quantization level */ + #define MAX_QGAIN_DB 88 /* dB level of highest gain quantization level */ + #define N_LEVELS_QGAIN 64 /* Number of gain quantization levels */ + #define MAX_DELTA_GAIN_QUANT 36 /* Max increase in gain quantization index */ + #define MIN_DELTA_GAIN_QUANT -4 /* Max decrease in gain quantization index */ + #define OFFSET_VL_Q10 32 /* Quantization offsets (multiples of 4) */ + #define OFFSET_VH_Q10 100 + #define OFFSET_UVL_Q10 100 + #define OFFSET_UVH_Q10 240 + #define QUANT_LEVEL_ADJUST_Q10 80 + #define MAX_LPC_STABILIZE_ITERATIONS 16 /* Maximum numbers of iterations used to stabilize an LPC vector */ + #define MAX_PREDICTION_POWER_GAIN 1e4f + #define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + #define MAX_LPC_ORDER 16 + #define MIN_LPC_ORDER 10 + #define LTP_ORDER 5 /* Find Pred Coef defines */ + #define NB_LTP_CBKS 3 /* LTP quantization settings */ + #define USE_HARM_SHAPING 1 /* Flag to use harmonic noise shaping */ + #define MAX_SHAPE_LPC_ORDER 24 /* Max LPC order of noise shaping filters */ + #define HARM_SHAPE_FIR_TAPS 3 + #define MAX_DEL_DEC_STATES 4 /* Maximum number of delayed decision states */ + #define LTP_BUF_LENGTH 512 + #define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + #define DECISION_DELAY 40 + #define MAX_NB_SUBFR 4 /* Maximum number of subframes */ + #define ENCODER_NUM_CHANNELS 2 /* Max number of encoder channels (1/2) */ + #define DECODER_NUM_CHANNELS 2 /* Number of decoder channels (1/2) */ + #define MAX_FRAMES_PER_PACKET 3 + #define MIN_TARGET_RATE_BPS 5000 /* Limits on bitrate */ + #define MAX_TARGET_RATE_BPS 80000 + #define LBRR_NB_MIN_RATE_BPS 12000 /* LBRR thresholds */ + #define LBRR_MB_MIN_RATE_BPS 14000 + #define LBRR_WB_MIN_RATE_BPS 16000 + #define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ + #define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ + #define DTX_ACTIVITY_THRESHOLD 0.1f + #define VAD_NO_DECISION -1 /* VAD decision */ + #define VAD_NO_ACTIVITY 0 + #define VAD_ACTIVITY 1 + #define MAX_FS_KHZ 16 /* Maximum sampling frequency */ + #define MAX_API_FS_KHZ 48 + #define TYPE_NO_VOICE_ACTIVITY 0 /* Signal types */ + #define TYPE_UNVOICED 1 + #define TYPE_VOICED 2 + #define CODE_INDEPENDENTLY 0 /* Conditional coding types */ + #define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 + #define CODE_CONDITIONALLY 2 + #define STEREO_QUANT_TAB_SIZE 16 /* Settings for stereo processing */ + #define STEREO_QUANT_SUB_STEPS 5 + #define STEREO_INTERP_LEN_MS 8 /* must be even */ + #define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + #define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ + #define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + #define LTP_MEM_LENGTH_MS 20 /* Number of samples per frame */ + #define SUB_FRAME_LENGTH_MS 5 + #define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) + #define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) + #define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + #define LA_PITCH_MS 2 /* Milliseconds of lookahead for pitch analysis */ + #define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + #define MAX_FIND_PITCH_LPC_ORDER 16 /* Order of LPC used in find pitch */ + #define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) )/* Length of LPC window used in find pitch */ + #define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) + #define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + #define LA_SHAPE_MS 5 /* Milliseconds of lookahead for noise shape analysis */ + #define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + #define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ )/* Max lenof LPCwindow in noise shape analysis */ + #define SHELL_CODEC_FRAME_LENGTH 16 /* Number of subframes for excitation entropy coding */ + #define LOG2_SHELL_CODEC_FRAME_LENGTH 4 + #define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + #define N_RATE_LEVELS 10 /* Number of rate levels, for entropy coding of excitation */ + #define SILK_MAX_PULSES 16 /* Maximum sum of pulses per shell coding frame */ + #define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + #define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER + #define VAD_N_BANDS 4 + #define VAD_INTERNAL_SUBFRAMES_LOG2 2 + #define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + #define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ + #define VAD_NOISE_LEVELS_BIAS 50 + #define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ + #define VAD_SNR_FACTOR_Q16 45000 + #define VAD_SNR_SMOOTH_COEF_Q18 4096 /* smoothing for SNR measurement */ + #define LSF_COS_TAB_SZ_FIX 128/* Sizeof piecewise linear cos approximation table for the LSFs */ + #define BWE_COEF 0.99 + #define V_PITCH_GAIN_START_MIN_Q14 11469 + #define V_PITCH_GAIN_START_MAX_Q14 15565 + #define MAX_PITCH_LAG_MS 18 + #define RAND_BUF_SIZE 128 + #define RAND_BUF_MASK ( RAND_BUF_SIZE - 1) + #define LOG2_INV_LPC_GAIN_HIGH_THRES 3 + #define LOG2_INV_LPC_GAIN_LOW_THRES 8 + #define PITCH_DRIFT_FAC_Q16 655 + #define BITRESERVOIR_DECAY_TIME_MS 500 /* Decay time for bitreservoir */ + #define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f /* Level of noise floor for whitening filter LPC analysis */ + #define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f /* Bandwidth expansion for whitening filter in pitch analysis */ + #define FIND_LPC_COND_FAC 1e-5f /* LPC analysis regularization */ + #define MAX_SUM_LOG_GAIN_DB 250.0f /* Max cumulative LTP gain */ + #define LTP_CORR_INV_MAX 0.03f /* LTP analysis defines */ + #define VARIABLE_HP_SMTH_COEF1 0.1f + #define VARIABLE_HP_SMTH_COEF2 0.015f + #define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + #define VARIABLE_HP_MIN_CUTOFF_HZ 60 /* Min and max cut-off frequency values (-3 dB points) */ + #define VARIABLE_HP_MAX_CUTOFF_HZ 100 + #define SPEECH_ACTIVITY_DTX_THRES 0.05f /* VAD threshold */ + #define LBRR_SPEECH_ACTIVITY_THRES 0.3f /* Speech Activity LBRR enable threshold */ + #define BG_SNR_DECR_dB 2.0f /* reduction in coding SNR during low speech activity */ + #define HARM_SNR_INCR_dB 2.0f /* factor for reducing quantization noise during voiced speech */ + #define SPARSE_SNR_INCR_dB 2.0f /* factor for reducing quant. noise for unvoiced sparse signals */ + #define ENERGY_VARIATION_THRESHOLD_QNT_OFFSET 0.6f + #define WARPING_MULTIPLIER 0.015f /* warping control */ + #define SHAPE_WHITE_NOISE_FRACTION 3e-5f /* fraction added to first autocorrelation value */ + #define BANDWIDTH_EXPANSION 0.94f /* noise shaping filter chirp factor */ + #define HARMONIC_SHAPING 0.3f /* harmonic noise shaping */ + #define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f /* extra harmonic noise shaping for high bitr. or noisy input */ + #define HP_NOISE_COEF 0.25f /* parameter for shaping noise towards higher frequencies */ + #define HARM_HP_NOISE_COEF 0.35f + #define INPUT_TILT 0.05f + #define HIGH_RATE_INPUT_TILT 0.1f /* for extra high-pass tilt to the input signal at high rates */ + #define LOW_FREQ_SHAPING 4.0f /* parameter for reducing noise at the very low frequencies */ + #define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + #define SUBFR_SMTH_COEF 0.4f + #define LAMBDA_OFFSET 1.2f /* param. defining the R/D tradeoff in the residual quantizer */ + #define LAMBDA_SPEECH_ACT -0.2f + #define LAMBDA_DELAYED_DECISIONS -0.05f + #define LAMBDA_INPUT_QUALITY -0.1f + #define LAMBDA_CODING_QUALITY -0.2f + #define LAMBDA_QUANT_OFFSET 0.8f + #define REDUCE_BITRATE_10_MS_BPS 2200 /* Compensation in bitrate calculations for 10 ms modes */ + #define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 /* Maximum time before allowing a bandwidth transition */ + #define silk_int64_MAX ((int64_t)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ + #define silk_int64_MIN ((int64_t)0x8000000000000000LL) /* -2^63 */ + #define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ + #define silk_int32_MIN ((int32_t)0x80000000) /* -2^31 = -2147483648 */ + #define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ + #define silk_int16_MIN ((int16_t)0x8000) /* -2^15 = -32768 */ + #define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ + #define silk_int8_MIN ((int8_t)0x80) /* -2^7 = -128 */ + #define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + #define silk_TRUE 1 + #define silk_FALSE 0 + #define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) + #define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + #define SILK_FIX_CONST(C, Q) ((int32_t)((C) * ((int64_t)1 << (Q)) + 0.5L)) /* Macro to convert floating-point constants to fixed-point */ + #define TIC(TAG_NAME) /* define macros as empty strings */ + #define TOC(TAG_NAME) + #define silk_TimerSave(FILE_NAME) + #define NLSF_W_Q 2 /* NLSF quantizer */ + #define NLSF_VQ_MAX_VECTORS 32 + #define NLSF_QUANT_MAX_AMPLITUDE 4 + #define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 + #define NLSF_QUANT_LEVEL_ADJ 0.1 + #define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 + #define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + #define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ + #define TRANSITION_NB 3 /* Hardcoded in tables */ + #define TRANSITION_NA 2 /* Hardcoded in tables */ + #define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ + #define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) + #define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + #define BWE_AFTER_LOSS_Q16 63570 /* BWE factors to apply after packet loss */ + #define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ + #define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ + #define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + #define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + #define PE_MAX_NB_SUBFR 4 + #define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + #define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + #define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) + #define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) + #define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) + #define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + #define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + #define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ + #define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) + #define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + #define PE_D_SRCH_LENGTH 24 + #define PE_NB_STAGE3_LAGS 5 + #define PE_NB_CBKS_STAGE2 3 + #define PE_NB_CBKS_STAGE2_EXT 11 + #define PE_NB_CBKS_STAGE3_MAX 34 + #define PE_NB_CBKS_STAGE3_MID 24 + #define PE_NB_CBKS_STAGE3_MIN 16 + #define PE_NB_CBKS_STAGE3_10MS 12 + #define PE_NB_CBKS_STAGE2_10MS 3 + #define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ + #define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ + #define PE_FLATCONTOUR_BIAS 0.05f + #define SILK_PE_MIN_COMPLEX 0 + #define SILK_PE_MID_COMPLEX 1 + #define SILK_PE_MAX_COMPLEX 2 + #define USE_CELT_FIR 0 + #define MAX_LOOPS 20 + #define NB_ATT 2 + #define ORDER_FIR 4 + #define RESAMPLER_DOWN_ORDER_FIR0 18 + #define RESAMPLER_DOWN_ORDER_FIR1 24 + #define RESAMPLER_DOWN_ORDER_FIR2 36 + #define RESAMPLER_ORDER_FIR_12 8 + #define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */ + #define SILK_RESAMPLER_MAX_FIR_ORDER 36 + #define SILK_RESAMPLER_MAX_IIR_ORDER 6 + #define A_LIMIT SILK_FIX_CONST( 0.99975, 24 ) + #define MUL32_FRAC_Q(a32, b32, Q) ((int32_t)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + #define RESAMPLER_MAX_BATCH_SIZE_MS 10 /* Number of input samples to process in the inner loop */ + #define RESAMPLER_MAX_FS_KHZ 48 + #define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + #define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) /* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ + #define USE_silk_resampler_copy (0) + #define USE_silk_resampler_private_up2_HQ_wrapper (1) + #define USE_silk_resampler_private_IIR_FIR (2) + #define USE_silk_resampler_private_down_FIR (3) + #define SILK_NO_ERROR 0 + #define silk_encoder_state_Fxx silk_encoder_state_FIX + #define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX + #define silk_encode_frame_Fxx silk_encode_frame_FIX + #define silk_LIMIT(a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + #define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + #define silk_LIMIT_int silk_LIMIT + #define silk_LIMIT_16 silk_LIMIT + #define silk_LIMIT_32 silk_LIMIT + #define silk_abs(a) (((a) > 0) ? (a) : -(a)) + #define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) + #define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) + #define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + #define OFFSET ((MIN_QGAIN_DB * 128) / 6 + 16 * 128) + #define SCALE_Q16 ((65536 * (N_LEVELS_QGAIN - 1)) / (((MAX_QGAIN_DB - MIN_QGAIN_DB) * 128) / 6)) + #define INV_SCALE_Q16 ((65536 * (((MAX_QGAIN_DB - MIN_QGAIN_DB) * 128) / 6)) / (N_LEVELS_QGAIN - 1)) + #define silk_SMULWB(a32, b32) ((int32_t)(((a32) * (int64_t)((int16_t)(b32))) >> 16)) /* (a32 * (int32_t)((int16_t)(b32))) >> 16 output have to be 32bit int */ + #define silk_SMLAWB(a32, b32, c32) ((int32_t)((a32) + (((b32) * (int64_t)((int16_t)(c32))) >> 16))) /* a32 + (b32 * (int32_t)((int16_t)(c32))) >> 16 output have to be 32bit int */ + #define silk_SMULWT(a32, b32) ((int32_t)(((a32) * (int64_t)((b32) >> 16)) >> 16)) /* (a32 * (b32 >> 16)) >> 16 */ + #define silk_SMLAWT(a32, b32, c32) ((int32_t)((a32) + (((b32) * ((int64_t)(c32) >> 16)) >> 16)))/* a32 + (b32 * (c32 >> 16)) >> 16 */ + #define silk_SMULBB(a32, b32) ((int32_t)((int16_t)(a32)) * (int32_t)((int16_t)(b32))) /* (int32_t)((int16_t)(a3))) * (int32_t)((int16_t)(b32)) output have to be 32bit int */ + #define silk_SMLABB(a32, b32, c32) ((a32) + ((int32_t)((int16_t)(b32))) * (int32_t)((int16_t)(c32))) /* a32 + (int32_t)((int16_t)(b32)) * (int32_t)((int16_t)(c32)) output have to be 32bit int */ + #define silk_SMULBT(a32, b32) ((int32_t)((int16_t)(a32)) * ((b32) >> 16)) /* (int32_t)((int16_t)(a32)) * (b32 >> 16) */ + #define silk_SMLABT(a32, b32, c32) ((a32) + ((int32_t)((int16_t)(b32))) * ((c32) >> 16)) /* a32 + (int32_t)((int16_t)(b32)) * (c32 >> 16) */ + #define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((int64_t)(b32) * (int64_t)(c32)))) /* a64 + (b32 * c32) */ + #define silk_SMULWW(a32, b32) ((int32_t)(((int64_t)(a32) * (b32)) >> 16)) /* (a32 * b32) >> 16 */ + #define silk_SMLAWW(a32, b32, c32) ((int32_t)((a32) + (((int64_t)(b32) * (c32)) >> 16))) /* a32 + ((b32 * c32) >> 16) */ + #define silk_ADD_SAT32(a, b) ((((uint32_t)(a) + (uint32_t)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + #define silk_SUB_SAT32(a, b) ((((uint32_t)(a)-(uint32_t)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + #define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) + #define EC_CLZ(_x) (__builtin_clz(_x)) + #define EC_ILOGs(_x) (EC_CLZ0-EC_CLZ(_x)) + #define matrix_ptr(Matrix_base_adr, row, column, N) (*((Matrix_base_adr) + ((row) * (N) + (column)))) /* Row based */ + #define matrix_adr(Matrix_base_adr, row, column, N) ((Matrix_base_adr) + ((row) * (N) + (column))) + #define silk_VQ_WMat_EC(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L) (silk_VQ_WMat_EC_c(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L)) + #define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order) (silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + #define silk_SMMUL(a32, b32) (int32_t) silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + #define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D) (silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D)) + #define silk_inner_prod16_aligned_64(inVec1, inVec2, len) (silk_inner_prod16_aligned_64_c(inVec1, inVec2, len)) + #define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len) (silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len)) + #define silk_LPC_inverse_pred_gain(A_Q12, order) (silk_LPC_inverse_pred_gain_c(A_Q12, order)) + #define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + #define RAND_MULTIPLIER 196314165 + #define RAND_INCREMENT 907633515 + #define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER))) + #define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order) (silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order)) diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/silk_structs.h b/libraries/ESP32-audioI2S/src/opus_decoder/silk_structs.h new file mode 100644 index 0000000..0f1ab7d --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/silk_structs.h @@ -0,0 +1,191 @@ +#pragma once + +#include "Arduino.h" +#include "silk_defines.h" + +typedef struct { + int8_t GainsIndices[MAX_NB_SUBFR]; + int8_t LTPIndex[MAX_NB_SUBFR]; + int8_t NLSFIndices[MAX_LPC_ORDER + 1]; + int16_t lagIndex; + int8_t contourIndex; + int8_t signalType; + int8_t quantOffsetType; + int8_t NLSFInterpCoef_Q2; + int8_t PERIndex; + int8_t LTP_scaleIndex; + int8_t Seed; +} sideInfoIndices_t; + +typedef struct { + int32_t AnaState[2]; /* Analysis filterbank state: 0-8 kHz */ + int32_t AnaState1[2]; /* Analysis filterbank state: 0-4 kHz */ + int32_t AnaState2[2]; /* Analysis filterbank state: 0-2 kHz */ + int32_t XnrgSubfr[VAD_N_BANDS]; /* Subframe energies */ + int32_t NrgRatioSmth_Q8[VAD_N_BANDS]; /* Smoothed energy level in each band */ + int16_t HPstate; /* State of differentiator in the lowest band */ + int32_t NL[VAD_N_BANDS]; /* Noise energy level in each band */ + int32_t inv_NL[VAD_N_BANDS]; /* Inverse noise energy level in each band */ + int32_t NoiseLevelBias[VAD_N_BANDS]; /* Noise level estimator bias/offset */ + int32_t counter; /* Frame counter used in the initial phase */ +} silk_VAD_state_t; + +typedef struct { /* Variable cut-off low-pass filter state */ + int32_t In_LP_State[2]; /* Low pass filter state */ + int32_t transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + int32_t mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ + int32_t saved_fs_kHz; /* If non-zero, holds the last sampling rate before a bandwidth switching reset. */ +} silk_LP_state_t; + +typedef struct { /* Structure containing NLSF codebook */ + const int16_t nVectors; + const int16_t order; + const int16_t quantStepSize_Q16; + const int16_t invQuantStepSize_Q6; + const uint8_t* CB1_NLSF_Q8; + const int16_t* CB1_Wght_Q9; + const uint8_t* CB1_iCDF; + const uint8_t* pred_Q8; + const uint8_t* ec_sel; + const uint8_t* ec_iCDF; + const uint8_t* ec_Rates_Q5; + const int16_t* deltaMin_Q15; +} silk_NLSF_CB_struct_t; + +typedef struct _silk_resampler_state_struct { + int32_t sIIR[SILK_RESAMPLER_MAX_IIR_ORDER]; /* this must be the first element of this struct */ + union { + int32_t i32[SILK_RESAMPLER_MAX_FIR_ORDER]; + int16_t i16[SILK_RESAMPLER_MAX_FIR_ORDER]; + } sFIR; + int16_t delayBuf[48]; + int32_t resampler_function; + int32_t batchSize; + int32_t invRatio_Q16; + int32_t FIR_Order; + int32_t FIR_Fracs; + int32_t Fs_in_kHz; + int32_t Fs_out_kHz; + int32_t inputDelay; + const int16_t* Coefs; +} silk_resampler_state_struct_t; + +typedef struct { + int16_t pred_prev_Q13[2]; + int16_t sMid[2]; + int16_t sSide[2]; +} stereo_dec_state_t; + +/* Struct for Packet Loss Concealment */ +typedef struct { + int32_t pitchL_Q8; /* Pitch lag to use for voiced concealment */ + int16_t LTPCoef_Q14[LTP_ORDER]; /* LTP coeficients to use for voiced concealment */ + int16_t prevLPC_Q12[MAX_LPC_ORDER]; + int32_t last_frame_lost; /* Was previous frame lost */ + int32_t rand_seed; /* Seed for unvoiced signal generation */ + int16_t randScale_Q14; /* Scaling of unvoiced random signal */ + int32_t conc_energy; + int32_t conc_energy_shift; + int16_t prevLTP_scale_Q14; + int32_t prevGain_Q16[2]; + int32_t fs_kHz; + int32_t nb_subfr; + int32_t subfr_length; +} silk_PLC_struct_t; + +/* Struct for CNG */ +typedef struct { + int32_t CNG_exc_buf_Q14[MAX_FRAME_LENGTH]; + int16_t CNG_smth_NLSF_Q15[MAX_LPC_ORDER]; + int32_t CNG_synth_state[MAX_LPC_ORDER]; + int32_t CNG_smth_Gain_Q16; + int32_t rand_seed; + int32_t fs_kHz; +} silk_CNG_struct_t; + +typedef struct { + int32_t prev_gain_Q16; + int32_t exc_Q14[MAX_FRAME_LENGTH]; + int32_t sLPC_Q14_buf[MAX_LPC_ORDER]; + int16_t outBuf[MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH]; /* Buffer for output signal */ + int32_t lagPrev; /* Previous Lag */ + int8_t LastGainIndex; /* Previous gain index */ + int32_t fs_kHz; /* Sampling frequency in kHz */ + int32_t fs_API_hz; /* API sample frequency (Hz) */ + int32_t nb_subfr; /* Number of 5 ms subframes in a frame */ + int32_t frame_length; /* Frame length (samples) */ + int32_t subfr_length; /* Subframe length (samples) */ + int32_t ltp_mem_length; /* Length of LTP memory */ + int32_t LPC_order; /* LPC order */ + int16_t prevNLSF_Q15[MAX_LPC_ORDER]; /* Used to interpolate LSFs */ + int32_t first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const uint8_t* pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const uint8_t* pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + /* For buffering payload in case of more frames per packet */ + int32_t nFramesDecoded; + int32_t nFramesPerPacket; + /* Specifically for entropy coding */ + int32_t ec_prevSignalType; + int16_t ec_prevLagIndex; + int32_t VAD_flags[MAX_FRAMES_PER_PACKET]; + int32_t LBRR_flag; + int32_t LBRR_flags[MAX_FRAMES_PER_PACKET]; + const silk_NLSF_CB_struct_t* psNLSF_CB; /* Pointer to NLSF codebook */ + sideInfoIndices_t indices; /* Quantization indices */ + silk_CNG_struct_t sCNG; /* CNG state */ + int32_t lossCnt; /* Stuff used for PLC */ + int32_t prevSignalType; + silk_PLC_struct_t sPLC; +} silk_decoder_state_t; + +typedef struct { + int32_t pitchL[MAX_NB_SUBFR]; /* Prediction and coding parameters */ + int32_t Gains_Q16[MAX_NB_SUBFR]; + int16_t PredCoef_Q12[2][MAX_LPC_ORDER]; /* Holds interpolated and final coefficients, 4-byte aligned */ + int16_t LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR]; + int32_t LTP_scale_Q14; +} silk_decoder_control_t; + +/* Decoder Super Struct */ +typedef struct { + stereo_dec_state_t sStereo; + int32_t nChannelsAPI; + int32_t nChannelsInternal; + int32_t prev_decode_only_middle; +} silk_decoder_t; + +typedef struct { + int32_t sLPC_Q14[MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH]; + int32_t RandState[DECISION_DELAY]; + int32_t Q_Q10[DECISION_DELAY]; + int32_t Xq_Q14[DECISION_DELAY]; + int32_t Pred_Q15[DECISION_DELAY]; + int32_t Shape_Q14[DECISION_DELAY]; + int32_t sAR2_Q14[MAX_SHAPE_LPC_ORDER]; + int32_t LF_AR_Q14; + int32_t Diff_Q14; + int32_t Seed; + int32_t SeedInit; + int32_t RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + int32_t Q_Q10; + int32_t RD_Q10; + int32_t xq_Q14; + int32_t LF_AR_Q14; + int32_t Diff_Q14; + int32_t sLTP_shp_Q14; + int32_t LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[2]; + +typedef struct { + int32_t nChannelsAPI; /* I: Number of channels; 1/2 */ + int32_t nChannelsInternal; /* I: Number of channels; 1/2 */ + int32_t API_sampleRate; /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + int32_t internalSampleRate; /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + int32_t payloadSize_ms; /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + int32_t prevPitchLag; /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ +} silk_DecControlStruct_t; diff --git a/libraries/ESP32-audioI2S/src/opus_decoder/silk_tables.h b/libraries/ESP32-audioI2S/src/opus_decoder/silk_tables.h new file mode 100644 index 0000000..c72588f --- /dev/null +++ b/libraries/ESP32-audioI2S/src/opus_decoder/silk_tables.h @@ -0,0 +1,360 @@ +#pragma once +#include "silk.h" +#include "silk_defines.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +static const int16_t silk_LSFCosTab_FIX_Q12[LSF_COS_TAB_SZ_FIX + 1] = { + 8192, 8190, 8182, 8170, 8152, 8130, 8104, 8072, 8034, 7994, 7946, 7896, 7840, 7778, 7714, 7644, 7568, 7490, 7406, 7318, 7226, 7128, 7026, 6922, 6812, 6698, + 6580, 6458, 6332, 6204, 6070, 5934, 5792, 5648, 5502, 5352, 5198, 5040, 4880, 4718, 4552, 4382, 4212, 4038, 3862, 3684, 3502, 3320, 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, 1598, 1400, 1202, 1002, 802, 602, 402, 202, 0, -202, -402, -602, -802, -1002, -1202, -1400, -1598, -1794, -1990, -2186, -2378, -2570, + -2760, -2948, -3136, -3320, -3502, -3684, -3862, -4038, -4212, -4382, -4552, -4718, -4880, -5040, -5198, -5352, -5502, -5648, -5792, -5934, -6070, -6204, -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, -7226, -7318, -7406, -7490, -7568, -7644, -7714, -7778, -7840, -7896, -7946, -7994, -8034, -8072, -8104, -8130, -8152, -8170, -8182, -8190, -8192}; + +/* Tables for stereo predictor coding */ +static const int16_t silk_stereo_pred_quant_Q13[STEREO_QUANT_TAB_SIZE] = {-13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732}; +static const uint8_t silk_stereo_pred_joint_iCDF[25] = {249, 247, 246, 245, 244, 234, 210, 202, 201, 200, 197, 174, 82, 59, 56, 55, 54, 46, 22, 12, 11, 10, 9, 7, 0}; +static const uint8_t silk_stereo_only_code_mid_iCDF[2] = {64, 0}; + +/* Tables for LBRR flags */ +static const uint8_t silk_LBRR_flags_2_iCDF[3] = {203, 150, 0}; +static const uint8_t silk_LBRR_flags_3_iCDF[7] = {215, 195, 166, 125, 110, 82, 0}; +static const uint8_t* const silk_LBRR_flags_iCDF_ptr[2] = {silk_LBRR_flags_2_iCDF, silk_LBRR_flags_3_iCDF}; + +/* Table for LSB coding */ +static const uint8_t silk_lsb_iCDF[2] = {120, 0}; + +/* Tables for LTPScale */ +static const uint8_t silk_LTPscale_iCDF[3] = {128, 64, 0}; + +/* Tables for signal type and offset coding */ +static const uint8_t silk_type_offset_VAD_iCDF[4] = {232, 158, 10, 0}; +static const uint8_t silk_type_offset_no_VAD_iCDF[2] = {230, 0}; + +/* Tables for NLSF interpolation factor */ +static const uint8_t silk_NLSF_interpolation_factor_iCDF[5] = {243, 221, 192, 181, 0}; + +/* Quantization offsets */ +static const int16_t silk_Quantization_Offsets_Q10[2][2] = {{OFFSET_UVL_Q10, OFFSET_UVH_Q10}, {OFFSET_VL_Q10, OFFSET_VH_Q10}}; + +/* Table for LTPScale */ +static const int16_t silk_LTPScales_table_Q14[3] = {15565, 12288, 8192}; + +/* Uniform entropy tables */ +static const uint8_t silk_uniform3_iCDF[3] = {171, 85, 0}; +static const uint8_t silk_uniform4_iCDF[4] = {192, 128, 64, 0}; +static const uint8_t silk_uniform5_iCDF[5] = {205, 154, 102, 51, 0}; +static const uint8_t silk_uniform6_iCDF[6] = {213, 171, 128, 85, 43, 0}; +static const uint8_t silk_uniform8_iCDF[8] = {224, 192, 160, 128, 96, 64, 32, 0}; + +static const uint8_t silk_NLSF_EXT_iCDF[7] = {100, 40, 16, 7, 3, 1, 0}; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +static const int32_t silk_Transition_LP_B_Q28[TRANSITION_INT_NUM][TRANSITION_NB] = {{250767114, 501534038, 250767114}, + {209867381, 419732057, 209867381}, + {170987846, 341967853, 170987846}, + {131531482, 263046905, 131531482}, + {89306658, 178584282, 89306658}}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +static const int32_t silk_Transition_LP_A_Q28[TRANSITION_INT_NUM][TRANSITION_NA] = {{506393414, 239854379}, + {411067935, 169683996}, + {306733530, 116694253}, + {185807084, 77959395}, + {35497197, 57401098}}; + +static const uint8_t silk_max_pulses_table[4] = {8, 10, 12, 16}; + +static const uint8_t silk_pulses_per_block_iCDF[10][18] = {{125, 51, 26, 18, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + {198, 105, 45, 22, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + {213, 162, 116, 83, 59, 43, 32, 24, 18, 15, 12, 9, 7, 6, 5, 3, 2, 0}, + {239, 187, 116, 59, 28, 16, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + {250, 229, 188, 135, 86, 51, 30, 19, 13, 10, 8, 6, 5, 4, 3, 2, 1, 0}, + {249, 235, 213, 185, 156, 128, 103, 83, 66, 53, 42, 33, 26, 21, 17, 13, 10, 0}, + {254, 249, 235, 206, 164, 118, 77, 46, 27, 16, 10, 7, 5, 4, 3, 2, 1, 0}, + {255, 253, 249, 239, 220, 191, 156, 119, 85, 57, 37, 23, 15, 10, 6, 4, 2, 0}, + {255, 253, 251, 246, 237, 223, 203, 179, 152, 124, 98, 75, 55, 40, 29, 21, 15, 0}, + {255, 254, 253, 247, 220, 162, 106, 67, 42, 28, 18, 12, 9, 6, 4, 3, 2, 0}}; + +static const uint8_t silk_rate_levels_iCDF[2][9] = {{241, 190, 178, 132, 87, 74, 41, 14, 0}, {223, 193, 157, 140, 106, 57, 39, 18, 0}}; + +static const uint8_t silk_rate_levels_BITS_Q5[2][9] = {{131, 74, 141, 79, 80, 138, 95, 104, 134}, {95, 99, 91, 125, 93, 76, 123, 115, 123}}; + +static const uint8_t silk_shell_code_table0[152] = { + 128, 0, 214, 42, 0, 235, 128, 21, 0, 244, 184, 72, 11, 0, 248, 214, 128, 42, 7, 0, 248, 225, 170, 80, 25, 5, 0, 251, 236, 198, 126, 54, 18, 3, 0, 250, 238, 211, + 159, 82, 35, 15, 5, 0, 250, 231, 203, 168, 128, 88, 53, 25, 6, 0, 252, 238, 216, 185, 148, 108, 71, 40, 18, 4, 0, 253, 243, 225, 199, 166, 128, 90, 57, 31, 13, 3, + 0, 254, 246, 233, 212, 183, 147, 109, 73, 44, 23, 10, 2, 0, 255, 250, 240, 223, 198, 166, 128, 90, 58, 33, 16, 6, 1, 0, 255, 251, 244, 231, 210, 181, 146, 110, 75, 46, + 25, 12, 5, 1, 0, 255, 253, 248, 238, 221, 196, 164, 128, 92, 60, 35, 18, 8, 3, 1, 0, 255, 253, 249, 242, 229, 208, 180, 146, 110, 76, 48, 27, 14, 7, 3, 1, 0}; + +static const uint8_t silk_shell_code_table1[152] = { + 129, 0, 207, 50, 0, 236, 129, 20, 0, 245, 185, 72, 10, 0, 249, 213, 129, 42, 6, 0, 250, 226, 169, 87, 27, 4, 0, 251, 233, 194, 130, 62, 20, 4, 0, 250, 236, 207, + 160, 99, 47, 17, 3, 0, 255, 240, 217, 182, 131, 81, 41, 11, 1, 0, 255, 254, 233, 201, 159, 107, 61, 20, 2, 1, 0, 255, 249, 233, 206, 170, 128, 86, 50, 23, 7, 1, + 0, 255, 250, 238, 217, 186, 148, 108, 70, 39, 18, 6, 1, 0, 255, 252, 243, 226, 200, 166, 128, 90, 56, 30, 13, 4, 1, 0, 255, 252, 245, 231, 209, 180, 146, 110, 76, 47, + 25, 11, 4, 1, 0, 255, 253, 248, 237, 219, 194, 163, 128, 93, 62, 37, 19, 8, 3, 1, 0, 255, 254, 250, 241, 226, 205, 177, 145, 111, 79, 51, 30, 15, 6, 2, 1, 0}; + +static const uint8_t silk_shell_code_table2[152] = { + 129, 0, 203, 54, 0, 234, 129, 23, 0, 245, 184, 73, 10, 0, 250, 215, 129, 41, 5, 0, 252, 232, 173, 86, 24, 3, 0, 253, 240, 200, 129, 56, 15, 2, 0, 253, 244, 217, + 164, 94, 38, 10, 1, 0, 253, 245, 226, 189, 132, 71, 27, 7, 1, 0, 253, 246, 231, 203, 159, 105, 56, 23, 6, 1, 0, 255, 248, 235, 213, 179, 133, 85, 47, 19, 5, 1, + 0, 255, 254, 243, 221, 194, 159, 117, 70, 37, 12, 2, 1, 0, 255, 254, 248, 234, 208, 171, 128, 85, 48, 22, 8, 2, 1, 0, 255, 254, 250, 240, 220, 189, 149, 107, 67, 36, + 16, 6, 2, 1, 0, 255, 254, 251, 243, 227, 201, 166, 128, 90, 55, 29, 13, 5, 2, 1, 0, 255, 254, 252, 246, 234, 213, 183, 147, 109, 73, 43, 22, 10, 4, 2, 1, 0}; + +static const uint8_t silk_shell_code_table3[152] = { + 130, 0, 200, 58, 0, 231, 130, 26, 0, 244, 184, 76, 12, 0, 249, 214, 130, 43, 6, 0, 252, 232, 173, 87, 24, 3, 0, 253, 241, 203, 131, 56, 14, 2, 0, 254, 246, 221, + 167, 94, 35, 8, 1, 0, 254, 249, 232, 193, 130, 65, 23, 5, 1, 0, 255, 251, 239, 211, 162, 99, 45, 15, 4, 1, 0, 255, 251, 243, 223, 186, 131, 74, 33, 11, 3, 1, + 0, 255, 252, 245, 230, 202, 158, 105, 57, 24, 8, 2, 1, 0, 255, 253, 247, 235, 214, 179, 132, 84, 44, 19, 7, 2, 1, 0, 255, 254, 250, 240, 223, 196, 159, 112, 69, 36, + 15, 6, 2, 1, 0, 255, 254, 253, 245, 231, 209, 176, 136, 93, 55, 27, 11, 3, 2, 1, 0, 255, 254, 253, 252, 239, 221, 194, 158, 117, 76, 42, 18, 4, 3, 2, 1, 0}; + +static const uint8_t silk_shell_code_table_offsets[17] = {0, 0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 65, 77, 90, 104, 119, 135}; + +static const uint8_t silk_sign_iCDF[42] = {254, 49, 67, 77, 82, 93, 99, 198, 11, 18, 24, 31, 36, 45, 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, 255, 94, 104, 109, 112, 115, 118, 248, 53, 69, 80, 88, 95, 102}; + +static const uint8_t silk_NLSF_CB1_NB_MB_Q8[320] = { + 12, 35, 60, 83, 108, 132, 157, 180, 206, 228, 15, 32, 55, 77, 101, 125, 151, 175, 201, 225, 19, 42, 66, 89, 114, 137, 162, 184, 209, 230, 12, 25, 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, 205, 225, 13, 22, 53, 80, 106, 130, 156, 180, 205, 228, 15, 25, 44, 64, 90, 115, 142, 168, 196, 222, 19, 24, 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, 203, 227, 21, 29, 45, 65, 106, 124, 150, 171, 196, 224, 30, 49, 75, 97, 121, 142, 165, 186, 209, 229, 19, 25, 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, 194, 217, 25, 33, 56, 70, 91, 113, 143, 165, 196, 223, 21, 34, 51, 72, 97, 117, 145, 171, 196, 222, 20, 29, 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, 196, 222, 24, 33, 51, 77, 116, 134, 158, 180, 200, 224, 21, 28, 70, 87, 106, 124, 149, 170, 194, 217, 26, 33, 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, 210, 225, 20, 26, 72, 99, 113, 131, 154, 176, 200, 219, 34, 43, 61, 78, 93, 114, 155, 177, 205, 229, 23, 29, 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, 200, 231, 21, 29, 49, 63, 85, 111, 142, 163, 193, 222, 27, 48, 77, 103, 133, 158, 179, 196, 215, 232, 29, 47, 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, 207, 225, 29, 53, 87, 112, 136, 154, 170, 188, 208, 227, 24, 30, 52, 84, 131, 150, 166, 186, 203, 229, 37, 48, 64, 84, 104, 118, 156, 177, 201, 230}; + +static const int16_t silk_NLSF_CB1_Wght_Q9[320] = { + 2897, 2314, 2314, 2314, 2287, 2287, 2314, 2300, 2327, 2287, 2888, 2580, 2394, 2367, 2314, 2274, 2274, 2274, 2274, 2194, 2487, 2340, 2340, 2314, 2314, 2314, 2340, 2340, 2367, 2354, 3216, 2766, + 2340, 2340, 2314, 2274, 2221, 2207, 2261, 2194, 2460, 2474, 2367, 2394, 2394, 2394, 2394, 2367, 2407, 2314, 3479, 3056, 2127, 2207, 2274, 2274, 2274, 2287, 2314, 2261, 3282, 3141, 2580, 2394, + 2247, 2221, 2207, 2194, 2194, 2114, 4096, 3845, 2221, 2620, 2620, 2407, 2314, 2394, 2367, 2074, 3178, 3244, 2367, 2221, 2553, 2434, 2340, 2314, 2167, 2221, 3338, 3488, 2726, 2194, 2261, 2460, + 2354, 2367, 2207, 2101, 2354, 2420, 2327, 2367, 2394, 2420, 2420, 2420, 2460, 2367, 3779, 3629, 2434, 2527, 2367, 2274, 2274, 2300, 2207, 2048, 3254, 3225, 2713, 2846, 2447, 2327, 2300, 2300, + 2274, 2127, 3263, 3300, 2753, 2806, 2447, 2261, 2261, 2247, 2127, 2101, 2873, 2981, 2633, 2367, 2407, 2354, 2194, 2247, 2247, 2114, 3225, 3197, 2633, 2580, 2274, 2181, 2247, 2221, 2221, 2141, + 3178, 3310, 2740, 2407, 2274, 2274, 2274, 2287, 2194, 2114, 3141, 3272, 2460, 2061, 2287, 2500, 2367, 2487, 2434, 2181, 3507, 3282, 2314, 2700, 2647, 2474, 2367, 2394, 2340, 2127, 3423, 3535, + 3038, 3056, 2300, 1950, 2221, 2274, 2274, 2274, 3404, 3366, 2087, 2687, 2873, 2354, 2420, 2274, 2474, 2540, 3760, 3488, 1950, 2660, 2897, 2527, 2394, 2367, 2460, 2261, 3028, 3272, 2740, 2888, + 2740, 2154, 2127, 2287, 2234, 2247, 3695, 3657, 2025, 1969, 2660, 2700, 2580, 2500, 2327, 2367, 3207, 3413, 2354, 2074, 2888, 2888, 2340, 2487, 2247, 2167, 3338, 3366, 2846, 2780, 2327, 2154, + 2274, 2287, 2114, 2061, 2327, 2300, 2181, 2167, 2181, 2367, 2633, 2700, 2700, 2553, 2407, 2434, 2221, 2261, 2221, 2221, 2340, 2420, 2607, 2700, 3038, 3244, 2806, 2888, 2474, 2074, 2300, 2314, + 2354, 2380, 2221, 2154, 2127, 2287, 2500, 2793, 2793, 2620, 2580, 2367, 3676, 3713, 2234, 1838, 2181, 2753, 2726, 2673, 2513, 2207, 2793, 3160, 2726, 2553, 2846, 2513, 2181, 2394, 2221, 2181}; + +static const uint8_t silk_NLSF_CB1_iCDF_NB_MB[64] = {212, 178, 148, 129, 108, 96, 85, 82, 79, 77, 61, 59, 57, 56, 51, 49, 48, 45, 42, 41, 40, 38, 36, 34, 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, 190, 176, 175, 161, 149, 136, 125, 114, 102, 91, 81, 71, 60, 52, 43, 35, 28, 20, 19, 18, 12, 11, 5, 0}; + +static const uint8_t silk_NLSF_CB2_SELECT_NB_MB[160] = {16, 0, 0, 0, 0, 99, 66, 36, 36, 34, 36, 34, 34, 34, 34, 83, 69, 36, 52, 34, 116, 102, 70, 68, 68, 176, 102, + 68, 68, 34, 65, 85, 68, 84, 36, 116, 141, 152, 139, 170, 132, 187, 184, 216, 137, 132, 249, 168, 185, 139, 104, 102, 100, 68, + 68, 178, 218, 185, 185, 170, 244, 216, 187, 187, 170, 244, 187, 187, 219, 138, 103, 155, 184, 185, 137, 116, 183, 155, 152, 136, 132, + 217, 184, 184, 170, 164, 217, 171, 155, 139, 244, 169, 184, 185, 170, 164, 216, 223, 218, 138, 214, 143, 188, 218, 168, 244, 141, 136, + 155, 170, 168, 138, 220, 219, 139, 164, 219, 202, 216, 137, 168, 186, 246, 185, 139, 116, 185, 219, 185, 138, 100, 100, 134, 100, 102, + 34, 68, 68, 100, 68, 168, 203, 221, 218, 168, 167, 154, 136, 104, 70, 164, 246, 171, 137, 139, 137, 155, 218, 219, 139}; + +static const uint8_t silk_NLSF_CB2_iCDF_NB_MB[72] = {255, 254, 253, 238, 14, 3, 2, 1, 0, 255, 254, 252, 218, 35, 3, 2, 1, 0, 255, 254, 250, 208, 59, 4, 2, 1, 0, 255, 254, 246, 194, 71, 10, 2, 1, 0, + 255, 252, 236, 183, 82, 8, 2, 1, 0, 255, 252, 235, 180, 90, 17, 2, 1, 0, 255, 248, 224, 171, 97, 30, 4, 1, 0, 255, 254, 236, 173, 95, 37, 7, 1, 0}; + +static const uint8_t silk_NLSF_CB2_BITS_NB_MB_Q5[72] = {255, 255, 255, 131, 6, 145, 255, 255, 255, 255, 255, 236, 93, 15, 96, 255, 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, 66, 162, 255, 255, 255, 210, 126, 73, 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, 110, 73, 57, 62, 104, 210, 255, 255, 251, 123, 65, 55, 68, 100, 171, 255}; + +static const uint8_t silk_NLSF_PRED_NB_MB_Q8[18] = {179, 138, 140, 148, 151, 149, 153, 151, 163, 116, 67, 82, 59, 92, 72, 100, 89, 92}; + +static const int16_t silk_NLSF_DELTA_MIN_NB_MB_Q15[11] = {250, 3, 6, 3, 3, 3, 4, 3, 3, 3, 461}; + +static const uint8_t silk_gain_iCDF[3][N_LEVELS_QGAIN / 8] = {{224, 112, 44, 15, 3, 2, 1, 0}, {254, 237, 192, 132, 70, 23, 4, 0}, {255, 252, 226, 155, 61, 11, 2, 0}}; + +static const uint8_t silk_delta_gain_iCDF[MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1] = {250, 245, 234, 203, 71, 50, 42, 38, 35, 33, 31, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + +static const uint8_t silk_pitch_lag_iCDF[2 * (PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS)] = {253, 250, 244, 233, 212, 182, 150, 131, 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + +static const uint8_t silk_pitch_delta_iCDF[21] = {210, 208, 206, 203, 199, 193, 183, 168, 142, 104, 74, 52, 37, 27, 20, 14, 10, 6, 4, 2, 0}; + +static const uint8_t silk_pitch_contour_iCDF[34] = {223, 201, 183, 167, 152, 138, 124, 111, 98, 88, 79, 70, 62, 56, 50, 44, 39, 35, 31, 27, 24, 21, 18, 16, 14, 12, 10, 8, 6, 4, 3, 2, 1, 0}; + +static const uint8_t silk_pitch_contour_NB_iCDF[11] = {188, 176, 155, 138, 119, 97, 67, 43, 26, 10, 0}; + +static const uint8_t silk_pitch_contour_10_ms_iCDF[12] = {165, 119, 80, 61, 47, 35, 27, 20, 14, 9, 4, 0}; + +static const uint8_t silk_pitch_contour_10_ms_NB_iCDF[3] = {113, 63, 0}; + +static const uint8_t silk_LTP_per_index_iCDF[3] = {179, 99, 0}; + +static const uint8_t silk_LTP_gain_iCDF_0[8] = {71, 56, 43, 30, 21, 12, 6, 0}; + +static const uint8_t silk_LTP_gain_iCDF_1[16] = {199, 165, 144, 124, 109, 96, 84, 71, 61, 51, 42, 32, 23, 15, 8, 0}; + +static const uint8_t silk_LTP_gain_iCDF_2[32] = {241, 225, 211, 199, 187, 175, 164, 153, 142, 132, 123, 114, 105, 96, 88, 80, 72, 64, 57, 50, 44, 38, 33, 29, 24, 20, 16, 12, 9, 5, 2, 0}; + +static const uint8_t silk_LTP_gain_BITS_Q5_0[8] = {15, 131, 138, 138, 155, 155, 173, 173}; + +static const uint8_t silk_LTP_gain_BITS_Q5_1[16] = {69, 93, 115, 118, 131, 138, 141, 138, 150, 150, 155, 150, 155, 160, 166, 160}; + +static const uint8_t silk_LTP_gain_BITS_Q5_2[32] = {131, 128, 134, 141, 141, 141, 145, 145, 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, 182, 192, 192, 192, 205, 192, 205, 224}; + +static const uint8_t* const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = {silk_LTP_gain_iCDF_0, silk_LTP_gain_iCDF_1, silk_LTP_gain_iCDF_2}; + +static const uint8_t* const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = {silk_LTP_gain_BITS_Q5_0, silk_LTP_gain_BITS_Q5_1, silk_LTP_gain_BITS_Q5_2}; + +static const int8_t silk_LTP_gain_vq_0[8][5] = {{4, 6, 24, 7, 5}, {0, 0, 2, 0, 0}, {12, 28, 41, 13, -4}, {-9, 15, 42, 25, 14}, + {1, -2, 62, 41, -9}, {-10, 37, 65, -4, 3}, {-6, 4, 66, 7, -8}, {16, 14, 38, -3, 33}}; + +static const int8_t silk_LTP_gain_vq_1[16][5] = {{13, 22, 39, 23, 12}, {-1, 36, 64, 27, -6}, {-7, 10, 55, 43, 17}, {1, 1, 8, 1, 1}, {6, -11, 74, 53, -9}, {-12, 55, 76, -12, 8}, + {-3, 3, 93, 27, -4}, {26, 39, 59, 3, -8}, {2, 0, 77, 11, 9}, {-8, 22, 44, -6, 7}, {40, 9, 26, 3, 9}, {-7, 20, 101, -7, 4}, + {3, -8, 42, 26, 0}, {-15, 33, 68, 2, 23}, {-2, 55, 46, -2, 15}, {3, -1, 21, 16, 41}}; + +static const int8_t silk_LTP_gain_vq_2[32][5] = { + {-6, 27, 61, 39, 5}, {-11, 42, 88, 4, 1}, {-2, 60, 65, 6, -4}, {-1, -5, 73, 56, 1}, {-9, 19, 94, 29, -9}, {0, 12, 99, 6, 4}, {8, -19, 102, 46, -13}, {3, 2, 13, 3, 2}, + {9, -21, 84, 72, -18}, {-11, 46, 104, -22, 8}, {18, 38, 48, 23, 0}, {-16, 70, 83, -21, 11}, {5, -11, 117, 22, -8}, {-6, 23, 117, -12, 3}, {3, -8, 95, 28, 4}, {-10, 15, 77, 60, -15}, + {-1, 4, 124, 2, -4}, {3, 38, 84, 24, -25}, {2, 13, 42, 13, 31}, {21, -4, 56, 46, -1}, {-1, 35, 79, -13, 19}, {-7, 65, 88, -9, -14}, {20, 4, 81, 49, -29}, {20, 0, 75, 3, -17}, + {5, -9, 44, 92, -8}, {1, -3, 22, 69, 31}, {-6, 95, 41, -12, 5}, {39, 67, 16, -4, 1}, {0, -6, 120, 55, -36}, {-13, 44, 122, 4, -24}, {81, 5, 11, 3, 7}, {2, 0, 9, 10, 88}}; + +static const uint8_t silk_NLSF_CB1_WB_Q8[512] = { + 7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208, 223, 239, 13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171, 187, 203, 220, 236, 15, 21, 34, 51, 61, + 78, 92, 106, 126, 136, 152, 167, 185, 205, 225, 240, 10, 21, 36, 50, 63, 79, 95, 110, 126, 141, 157, 173, 189, 205, 221, 237, 17, 20, 37, 51, 59, 78, 89, 107, 123, 134, + 150, 164, 184, 205, 224, 240, 10, 15, 32, 51, 67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236, 8, 21, 37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, + 218, 12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203, 219, 236, 16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171, 186, 204, 220, 237, 11, 28, 43, 58, + 74, 89, 105, 120, 135, 150, 165, 180, 196, 211, 226, 241, 6, 16, 33, 46, 60, 75, 92, 107, 123, 137, 156, 169, 185, 199, 214, 225, 11, 19, 30, 44, 57, 74, 89, 105, 121, + 135, 152, 169, 186, 202, 218, 234, 12, 19, 29, 46, 57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233, 17, 23, 35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, + 222, 237, 14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206, 221, 240, 9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171, 189, 205, 222, 237, 16, 19, 36, + 48, 57, 76, 87, 105, 118, 132, 150, 167, 185, 202, 218, 236, 12, 17, 29, 54, 71, 81, 94, 104, 126, 136, 149, 164, 182, 201, 221, 237, 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, 8, 14, 30, 45, 62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239, 17, 30, 49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, + 204, 220, 235, 14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189, 205, 222, 238, 12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154, 171, 187, 204, 221, 236, 13, 17, + 31, 43, 53, 70, 83, 103, 114, 131, 149, 167, 185, 203, 220, 237, 17, 22, 35, 42, 58, 78, 93, 110, 125, 139, 155, 170, 188, 206, 224, 240, 8, 15, 34, 50, 67, 83, 99, + 115, 131, 146, 162, 178, 193, 209, 224, 239, 13, 16, 41, 66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241, 17, 25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, + 175, 191, 212, 231, 19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200, 213, 227, 242, 18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163, 177, 192, 207, 223, 239, 16, + 29, 47, 61, 76, 90, 106, 119, 133, 147, 161, 176, 193, 209, 224, 240, 15, 21, 35, 50, 61, 73, 86, 97, 110, 119, 129, 141, 175, 198, 218, 237}; + +static const int16_t silk_NLSF_CB1_WB_Wght_Q9[512] = { + 3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2963, 2963, 2925, 2846, 3216, 3085, 2972, 3056, 3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846, 2846, 2726, + 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846, 3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, 3516, 3197, 3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888, 2888, 2888, 2888, 2753, + 5054, 5054, 2934, 3573, 3385, 3056, 3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888, 4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019, 2925, 2925, 2925, 2925, 2888, 2726, + 3620, 3019, 2972, 3056, 3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981, 3310, 2991, 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094, 3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, + 5081, 5174, 4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888, 2846, 2793, 2846, 2700, 3122, 2888, 2963, 2925, 2925, 2925, 2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963, + 4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873, 2916, 3019, 2972, 3010, 3197, 2873, 3760, 3760, 3244, 3103, 2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888, 2888, 2660, + 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963, 2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, 3845, 4080, 3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846, 2647, 2647, 2846, 2806, + 5147, 4894, 3225, 3845, 3441, 3169, 2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753, 4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740, 2793, 2740, 2793, 2846, 2888, 2806, + 5081, 5054, 3047, 3545, 3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846, 2793, 2620, 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075, 3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, + 3056, 2916, 2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169, 3056, 3010, 2963, 2846, 4375, 3882, 2925, 2888, 2846, 2888, 2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846, + 2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056, 3010, 2972, 2972, 2972, 2925, 2740, 4229, 4149, 3310, 3347, 2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846, 2846, 2793, + 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888, 2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, 4615, 4575, 3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687, 2687, 2740, 2793, 2700, + 4149, 4269, 3789, 3657, 2726, 2780, 2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888, 4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925, 2888, 2925, 2925, 2925, 2963, 2888, + 5174, 4921, 2261, 3432, 3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487, 2753, 2925, 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207, 2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, + 2981, 3010, 2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150, 3150, 3103, 3010, 3010, 2944, 2873, 2687, 2726, 2780, 3010, 3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846, + 3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056, 3010, 2888, 2846, 2925, 2925, 2888, 3920, 3967, 3010, 3197, 3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460, 2580, 2607}; + +static const uint8_t silk_NLSF_CB1_iCDF_WB[64] = {225, 204, 201, 184, 183, 175, 158, 154, 153, 135, 119, 115, 113, 110, 109, 99, 98, 95, 79, 68, 52, 50, 48, 45, 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, 167, 166, 163, 151, 138, 124, 110, 104, 90, 78, 76, 70, 69, 57, 45, 34, 24, 21, 11, 6, 5, 4, 3, 0}; + +static const uint8_t silk_NLSF_CB2_SELECT_WB[256] = { + 0, 0, 0, 0, 0, 0, 0, 1, 100, 102, 102, 68, 68, 36, 34, 96, 164, 107, 158, 185, 180, 185, 139, 102, 64, 66, 36, 34, 34, 0, 1, 32, 208, 139, 141, 191, 152, + 185, 155, 104, 96, 171, 104, 166, 102, 102, 102, 132, 1, 0, 0, 0, 0, 16, 16, 0, 80, 109, 78, 107, 185, 139, 103, 101, 208, 212, 141, 139, 173, 153, 123, 103, 36, 0, + 0, 0, 0, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 32, 68, 135, 123, 119, 119, 103, 69, 98, 68, 103, 120, 118, 118, 102, 71, 98, 134, 136, 157, 184, 182, 153, 139, + 134, 208, 168, 248, 75, 189, 143, 121, 107, 32, 49, 34, 34, 34, 0, 17, 2, 210, 235, 139, 123, 185, 137, 105, 134, 98, 135, 104, 182, 100, 183, 171, 134, 100, 70, 68, 70, + 66, 66, 34, 131, 64, 166, 102, 68, 36, 2, 1, 0, 134, 166, 102, 68, 34, 34, 66, 132, 212, 246, 158, 139, 107, 107, 87, 102, 100, 219, 125, 122, 137, 118, 103, 132, 114, + 135, 137, 105, 171, 106, 50, 34, 164, 214, 141, 143, 185, 151, 121, 103, 192, 34, 0, 0, 0, 0, 0, 1, 208, 109, 74, 187, 134, 249, 159, 137, 102, 110, 154, 118, 87, 101, + 119, 101, 0, 2, 0, 36, 36, 66, 68, 35, 96, 164, 102, 100, 36, 0, 2, 33, 167, 138, 174, 102, 100, 84, 2, 2, 100, 107, 120, 119, 36, 197, 24, 0}; + +static const uint8_t silk_NLSF_CB2_iCDF_WB[72] = {255, 254, 253, 244, 12, 3, 2, 1, 0, 255, 254, 252, 224, 38, 3, 2, 1, 0, 255, 254, 251, 209, 57, 4, 2, 1, 0, 255, 254, 244, 195, 69, 4, 2, 1, 0, + 255, 251, 232, 184, 84, 7, 2, 1, 0, 255, 254, 240, 186, 86, 14, 2, 1, 0, 255, 254, 239, 178, 91, 30, 5, 1, 0, 255, 248, 227, 177, 100, 19, 2, 1, 0}; + +static const uint8_t silk_NLSF_CB2_BITS_WB_Q5[72] = {255, 255, 255, 156, 4, 154, 255, 255, 255, 255, 255, 227, 102, 15, 92, 255, 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, 63, 214, 255, 255, 255, 190, 121, 77, 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, 131, 66, 50, 66, 107, 194, 255, 255, 166, 116, 76, 55, 53, 125, 255, 255}; + +static const uint8_t silk_NLSF_PRED_WB_Q8[30] = {175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198, 192, 182, 68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142, 160, 142, 155}; + +static const int16_t silk_NLSF_DELTA_MIN_WB_Q15[17] = {100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347}; + +static const int8_t silk_CB_lags_stage2_10_ms[PE_MAX_NB_SUBFR >> 1][PE_NB_CBKS_STAGE2_10MS] = {{0, 1, 0}, {0, 0, 1}}; + +static const int8_t silk_CB_lags_stage3_10_ms[PE_MAX_NB_SUBFR >> 1][PE_NB_CBKS_STAGE3_10MS] = {{0, 0, 1, -1, 1, -1, 2, -2, 2, -2, 3, -3}, {0, 1, 0, 1, -1, 2, -1, 2, -2, 3, -2, 3}}; + +static const int8_t silk_Lag_range_stage3_10_ms[PE_MAX_NB_SUBFR >> 1][2] = {{-3, 7}, {-2, 7}}; + +static const int8_t silk_CB_lags_stage2[PE_MAX_NB_SUBFR][PE_NB_CBKS_STAGE2_EXT] = {{0, 2, -1, -1, -1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0, -1, 2, 1, 0, 1, 1, 0, 0, -1, -1}}; + +static const int8_t silk_CB_lags_stage3[PE_MAX_NB_SUBFR][PE_NB_CBKS_STAGE3_MAX] = { + {0, 0, 1, -1, 0, 1, -1, 0, -1, 1, -2, 2, -2, -2, 2, -3, 2, 3, -3, -4, 3, -4, 4, 4, -5, 5, -6, -5, 6, -7, 6, 5, 8, -9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 1, -1, 0, 1, -1, -1, 1, -1, 2, 1, -1, 2, -2, -2, 2, -2, 2, 2, 3, -3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, -1, 1, 0, 0, 2, 1, -1, 2, -1, -1, 2, -1, 2, 2, -1, 3, -2, -2, -2, 3}, + {0, 1, 0, 0, 1, 0, 1, -1, 2, -1, 2, -1, 2, 3, -2, 3, -2, -2, 4, 4, -3, 5, -3, -4, 6, -4, 6, 5, -5, 8, -6, -5, -7, 9}}; + +static const int8_t silk_Lag_range_stage3[SILK_PE_MAX_COMPLEX + 1][PE_MAX_NB_SUBFR][2] = { + /* Lags to search for low number of stage3 cbks */ + {{-5, 8}, {-1, 6}, {-1, 6}, {-4, 10}}, + /* Lags to search for middle number of stage3 cbks */ + {{-6, 10}, {-2, 6}, {-1, 6}, {-5, 10}}, + /* Lags to search for max number of stage3 cbks */ + {{-9, 12}, {-3, 7}, {-2, 7}, {-7, 13}}}; + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const int8_t delay_matrix_enc[5][3] = { + /* in \ out 8 12 16 */ + /* 8 */ {6, 0, 3}, + /* 12 */ {0, 7, 3}, + /* 16 */ {0, 1, 10}, + /* 24 */ {0, 2, 6}, + /* 48 */ {18, 10, 12}}; + +static const int8_t delay_matrix_dec[3][5] = { + /* in \ out 8 12 16 24 48 */ + /* 8 */ {4, 0, 2, 0, 0}, + /* 12 */ {0, 9, 4, 7, 4}, + /* 16 */ {0, 3, 12, 7, 7}}; + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +static const int16_t silk_Resampler_3_4_COEFS[2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2] = { + -20694, -13867, -49, 64, 17, -157, 353, -496, 163, 11047, 22205, -39, 6, 91, -170, 186, 23, -896, 6336, 19928, -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +static const int16_t silk_Resampler_2_3_COEFS[2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2] = { + -14457, -14019, 64, 128, -122, 36, 310, -768, 584, 9267, 17733, 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +static const int16_t silk_Resampler_1_2_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR1 / 2] = { + 616, -14323, -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +static const int16_t silk_Resampler_1_3_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2] = { + 16102, -15162, -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +static const int16_t silk_Resampler_1_4_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2] = { + 22500, -15099, 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +static const int16_t silk_Resampler_1_6_COEFS[2 + RESAMPLER_DOWN_ORDER_FIR2 / 2] = { + 27540, -15257, 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +static const int16_t silk_Resampler_2_3_COEFS_LQ[2 + 2 * 2] = { + -2797, -6507, 4697, 10739, 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +static const int16_t silk_resampler_frac_FIR_12[12][RESAMPLER_ORDER_FIR_12 / 2] = { + {189, -600, 617, 30567}, {117, -159, -1070, 29704}, {52, 221, -2392, 28276}, {-4, 529, -3350, 26341}, {-48, 758, -3956, 23973}, {-80, 905, -4235, 21254}, + {-99, 972, -4222, 18278}, {-107, 967, -3957, 15143}, {-103, 896, -3487, 11950}, {-91, 773, -2865, 8798}, {-71, 611, -2143, 5784}, {-46, 425, -1375, 2996}, +}; + +static const int16_t HARM_ATT_Q15[NB_ATT] = {32440, 31130}; /* 0.99, 0.95 */ +static const int16_t PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = {31130, 26214}; /* 0.95, 0.8 */ +static const int16_t PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = {32440, 29491}; /* 0.99, 0.9 */ + +/* Tables for 2x downsampler */ +static const int16_t silk_resampler_down2_0 = 9872; +static const int16_t silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const int16_t silk_resampler_up2_hq_0[3] = {1746, 14986, 39083 - 65536}; +static const int16_t silk_resampler_up2_hq_1[3] = {6854, 25769, 55542 - 65536}; + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const int32_t sigm_LUT_slope_Q10[6] = {237, 153, 73, 30, 12, 7}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const int32_t sigm_LUT_pos_Q15[6] = {16384, 23955, 28861, 31213, 32178, 32548}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const int32_t sigm_LUT_neg_Q15[6] = {16384, 8812, 3906, 1554, 589, 219}; + +static const int8_t silk_nb_cbk_searchs_stage3[SILK_PE_MAX_COMPLEX + 1] = {PE_NB_CBKS_STAGE3_MIN, PE_NB_CBKS_STAGE3_MID, PE_NB_CBKS_STAGE3_MAX}; diff --git a/libraries/ESP32-audioI2S/src/psram_unique_ptr.hpp b/libraries/ESP32-audioI2S/src/psram_unique_ptr.hpp new file mode 100644 index 0000000..26a3e18 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/psram_unique_ptr.hpp @@ -0,0 +1,3442 @@ +#pragma once + +#include "Arduino.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef PS_PTR_CLASS + #define PS_PTR_CLASS 1 + +/** Auxiliary functions for using Unique Pointers in ESP32 PSRAM **/ + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// PSRAM Deleter (ps_malloc → free) +// Deleter for PSRAM + +// single objekt (int -> PSRAM) +// auto pint = ps_make_unique(123); +// Serial.printf("Wert: %d\n", *pint); + +// single objekt (std::string -> PSRAM) +// auto pstr = ps_make_unique("Hallo PSRAM"); +// Serial.printf("String: %s\n", pstr->c_str()); + +// array (char-Buffer) +// auto buf = ps_make_unique(256); +// std::strcpy(buf.get(), "Text im PSRAM"); + +// array (int-Buffer) +// auto iarr = ps_make_unique(64); +// iarr[0] = 42 + +struct PsramDeleter { + void operator()(void* ptr) const noexcept { + if (ptr) { + free(ptr); // PSRAM freigeben + } + } +}; + +// create individual object in PSRAM +template std::unique_ptr ps_make_unique(Args&&... args) { + // rohen Speicher im PSRAM holen + void* raw = ps_malloc(sizeof(T)); + if (!raw) { throw std::bad_alloc(); } + + // Objekt mit placement-new konstruieren + T* obj = new (raw) T(std::forward(args)...); + + // unique_ptr mit eigenem Deleter zurückgeben + return std::unique_ptr(obj); +} + +// create an array of objects in PSRAM +template std::unique_ptr ps_make_unique(size_t count) { + T* raw = static_cast(ps_malloc(sizeof(T) * count)); + if (!raw) { + printf("OOM: ps_malloc failed (%zu bytes)\n", sizeof(T) * count); + return std::unique_ptr(nullptr); // kein throw + } + return std::unique_ptr(raw); +} + +// Auxiliary function: Comparison of two strings case inensitive, only up to n characters +inline int strncasecmp_local(const char* s1, const char* s2, std::size_t n) { + for (std::size_t i = 0; i < n; ++i) { + unsigned char c1 = static_cast(s1[i]); + unsigned char c2 = static_cast(s2[i]); + if (tolower(c1) != tolower(c2)) return tolower(c1) - tolower(c2); + if (c1 == '\0') break; + } + return 0; +} + +template + +class ps_ptr { + private: + std::unique_ptr mem; + size_t allocated_size = 0; + char* name = nullptr; // member for object name + static inline T dummy{}; // For invalid accesses + size_t length_ = 0; // actual number of characters + public: + // Auxiliary function for setting the name + void set_name(const char* new_name) { + if (name) { + free(name); + name = nullptr; + } + if (new_name) { + std::size_t len = std::strlen(new_name) + 1; + if (psramFound()) { + name = static_cast(ps_malloc(len)); + } else { + name = static_cast(malloc(len)); + } + if (name) { + std::memcpy(name, new_name, len); + } else { + printf("OOM: failed to allocate %zu bytes for name %s\n", len, new_name); + } + } + } + + ps_ptr() = default; // default constructor + + ~ps_ptr() { // destructor + if (mem) { + // log_w("Destructor called for %s: Freeing %zu bytes at %p", name ? name : "unnamed", allocated_size * sizeof(T), mem.get()); + } else { + // log_w("Destructor called for %s: No memory to free.", name ? name : "unnamed"); + } + if (name) { + free(name); + name = nullptr; + } + } + + explicit operator bool() const { + return mem.get() != nullptr; // Or just 'return (bool) mem;'if unique_ptr :: operator bool () is used + } + + // constructor for C-strings (only active if t == char) + ps_ptr(const char* src) { + if constexpr (std::is_same_v) { + assign(src); + } else { + static_assert(!std::is_same_v, "This constructor is only available for ps_ptr"); + } + } + + ps_ptr(const char* src, size_t len) { + if (src && len > 0) { + allocated_size = len + 1; + mem = ps_make_unique(allocated_size); // sauber! + if (mem.get() && allocated_size > len) { // additional bounds check + std::memcpy(mem.get(), src, len); + // suppress warning: We know that allocated_size = len + 1 and therefore index [len] is valid + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" + mem.get()[len] = '\0'; + #pragma GCC diagnostic pop + } else { + allocated_size = 0; // Reset if allocation fails + } + } + } + + ps_ptr(ps_ptr&& other) noexcept { // move-constructor + mem = std::move(other.mem); + allocated_size = other.allocated_size; + name = other.name; + other.allocated_size = 0; + other.name = nullptr; + } + + // copy constructor (only for Char sensible, deep copy) + ps_ptr(const ps_ptr& other) { + if constexpr (std::is_same_v) { + assign(other.get()); + } else { + // Für Nicht-Char-Typen: Kopieren verboten (wie vorher) + static_assert(!std::is_same_v, "Copy constructor disabled for this type"); + } + } + + // 🆕 alloc constructor, e.g. ps_ptrbuff(1024) + explicit ps_ptr(size_t n) { alloc(n); } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A L L O C 📌📌📌 + + // ps_ptr test; + // test.alloc(100"); + // if(test.valid()) { + // printf("Größe: %u\n", test.size()); + // test.clear(); // memset "0" + // } + + bool alloc(std::size_t size, const char* alloc_name = nullptr, bool usePSRAM = true) { + size = (size + 15) & ~15; // Align to 16 bytes + if (psramFound() && usePSRAM) { // Check at the runtime whether PSRAM is available + mem.reset(static_cast(ps_malloc(size))); // <--- Important! + } else { + mem.reset(static_cast(malloc(size))); // <--- Important! + } + allocated_size = size; + if (alloc_name) { set_name(alloc_name); } + if (!mem) { + printf("OOM: failed to allocate %zu bytes for %s\n", size, name ? name : "unnamed"); + return false; + } + return true; + } + + bool alloc(const char* alloc_name = nullptr) { // alloc for single objects/structures + reset(); // Freigabe des zuvor gehaltenen Speichers + void* raw_mem = nullptr; + if (psramFound()) { // Check at the runtime whether PSRAM is available + raw_mem = ps_malloc(sizeof(T)); // allocated im PSRAM + } else { + raw_mem = malloc(sizeof(T)); // allocated im RAM + } + if (alloc_name) { set_name(alloc_name); } + if (raw_mem) { + mem.reset(new (raw_mem) T()); // placed new: constructor of T is called up in PSRAM + allocated_size = sizeof(T); + } else { + printf("OOM: failed to allocate %zu bytes for %s\n", sizeof(T), name ? name : "unnamed"); + allocated_size = 0; // make sure that allocated_size is 0 if allocation fails + return false; + } + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A L L O C 📌📌📌 + /** + * @brief Allocates and zeroes out memory for an array of elements. + * Chooses between PSRAM (if available) and DRAM. + * @param num_elements The number of elements to allocate space for. + */ + bool calloc(std::size_t num_elements, const char* alloc_name = nullptr, bool usePSRAM = true) { + size_t total_size = num_elements * sizeof(T); + total_size = (total_size + 15) & ~15; // Align to 16 bytes, consistent with your alloc() + + reset(); // Release of the previously held memory + if (alloc_name) { set_name(alloc_name); } + void* raw_mem = nullptr; + + if (psramFound() && usePSRAM) { // Check at the runtime whether PSRAM is available + raw_mem = ps_malloc(total_size); + } else { + raw_mem = malloc(total_size); + } + + if (raw_mem) { + // Initialize memory with zeros how Calloc () does it + memset(raw_mem, 0, total_size); + + // Connect the allocated memory to the Unique_PTR + mem.reset(static_cast(raw_mem)); + allocated_size = total_size; + } else { + // Error treatment for storage allocation + printf("OOM: failed to calloc %zu bytes for %s\n", total_size, name ? name : "unnamed"); + allocated_size = 0; // Sicherstellen, dass allocated_size 0 ist, wenn Allokation fehlschlägt + return false; + } + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A L L O C _ A R R A Y 📌📌📌 + + bool alloc_array(std::size_t count, const char* alloc_name = nullptr) { + if (alloc_name) { set_name(alloc_name); } + bool res = alloc(sizeof(T) * count); + // clear(); + return res; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A L L O C _ A R R A Y 📌📌📌 + + bool calloc_array(std::size_t count, const char* alloc_name = nullptr) { + if (alloc_name) { set_name(alloc_name); } + + // rohen Speicher holen + bool res = alloc(sizeof(T) * count); + if (!res) { return false; } + + // alle Elemente sauber value-initialisieren + for (std::size_t i = 0; i < count; i++) { + // placement-new mit {} ruft den Default-Konstruktor / value-init auf + new (&(get()[i])) T{}; + } + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 Z E R O _ M E M 📌📌📌 + /** + * @brief Sets the allocated memory block to all zeroes. + * Only operates if memory is currently allocated. + */ + void zero_mem() { + if (mem) { // Check whether memory is assigned (use the new operator bool ()) + // Use allocated_aize to zero the actual size of the assigned block. + // This is important because alloc() can also be called up with a specific size. + memset(mem.get(), 0, allocated_size); + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E A L L O C 📌📌📌 + + // test.realloc(200); + // printf("new size: %i\n", test.size()); + // printf("%s\n", test.get()); + + void realloc(size_t new_size) { + void* new_mem = nullptr; + if (psramFound()) { // Check at the runtime whether PSRAM is available + new_mem = ps_malloc(new_size); + } else { + new_mem = malloc(new_size); + } + if (!new_mem) { + printf("OOM: failed to realloc %zu bytes for %s\n", new_size, name ? name : "unnamed"); + return; + } + + if (mem && allocated_size > 0) { std::memcpy(new_mem, mem.get(), std::min(allocated_size, new_size)); } + + mem.reset(static_cast(new_mem)); + allocated_size = new_size; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A S S I G N 📌📌📌 + + // ps_ptr my_str1; + // my_str1.assign("Hallo", "my_str1"); // ps_strdup() + // printf("%s\n", my_str1.get()); + // my_str1.get()[3] = 'x'; + // printf("%s\n", my_str1.get()); + + void assign(const char* src) { + if constexpr (std::is_same_v) { + if (!src) { + reset(); + return; + } + std::size_t len = std::strlen(src) + 1; + alloc(len); + if (mem) { std::memcpy(mem.get(), src, len); } + } else { + static_assert(std::is_same_v, "assign(const char*) is only valid for ps_ptr"); + } + } + + // ps_ptr my_str2; + // my_str2.assign("Hallo", 5, "my_str1"); // ps_strndup() + // printf("%s\n", my_str2.get()); + + // Only for T T = char: similar to strndup (max. n chars) + void assign(const char* src, std::size_t max_len) { + static_assert(std::is_same_v, "assign(const char*, size_t) is only valid for ps_ptr"); + if (!src) { + reset(); + return; + } + std::size_t actual_len = strnlen(src, max_len); + std::size_t total = actual_len + 1; + alloc(total); + if (mem) { + std::memcpy(mem.get(), src, actual_len); + static_cast(mem.get())[actual_len] = '\0'; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C O P Y _ F R O M 📌📌📌 + // Counted Count elements from the external pointer to the PSRAM, similar to memcpy + + // Strings + // const char* msg = "Hallo"; + // ps_ptr text; + // text.copy_from(msg, strlen(msg) + 1, "text"); + + // Integer-Array + // int32_t values[] = {10, 20, 30}; + // ps_ptr data; + // data.copy_from(values, 3, "data"); + + // Float-Array + // float samples[] = {0.1f, 0.2f, 0.3f}; + // ps_ptr buf; + // buf.copy_from(samples, 3, "buffer"); + // printf("%f\n", buf.get()[2]); + // buf.get()[2] = 4.5; + // printf("%f\n", buf.get()[2]); + + void copy_from(const T* src, std::size_t count) { + std::size_t bytes = (count + 1) * sizeof(T); // +1 For zero terminator + alloc(bytes); + if (mem && src) { + std::memcpy(mem.get(), src, count * sizeof(T)); + mem.get()[count] = '\0'; // Zero + } + } + + size_t copy_from(const T* src) { // for strings + if (src == nullptr) { + log_e("arg. is null"); + return 0; + } + std::size_t count = std::strlen(src) + 1; + std::size_t bytes = count * sizeof(T); + alloc(bytes); + if (mem && src) { std::memcpy(mem.get(), src, bytes); } + return bytes; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C O P Y _ F R O M _ U T F 1 6 📌📌📌 + // copies all characters up to the terminator "\0\0" and converted into UTF-8 + // source: 0x00, 0x4C, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x20, 0x00, 0x4C, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x47, 0x00, + // 0x69, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x00 + // is UTF-16LE and will converted to: "Little London Girl" + // UTF-16LE and UTF-16BE is often found in ID3 header + + #include + #include + #include + #include + + // convert UTF-16 to UTF-8 and stop at zero terminator + size_t copy_from_utf16(const uint8_t* src, bool is_big_endian = false) { + if (!src) { + log_e("arg. is null"); + return 0; + } + std::vector out; + size_t i = 0; + + // BOM-Handling + if (src[i] == 0xFF && src[i + 1] == 0xFE) { + is_big_endian = false; // UTF-16LE + i += 2; + } else if (src[i] == 0xFE && src[i + 1] == 0xFF) { + is_big_endian = true; // UTF-16BE + i += 2; + } + + while (true) { + // Prüfe, ob genug Bytes für ein UTF-16-Zeichen vorhanden sind + if (i + 1 >= std::numeric_limits::max() || (src[i] == 0x00 && src[i + 1] == 0x00)) { + break; // Nullterminator oder Ende des Puffers + } + + uint16_t ch; + if (is_big_endian) { + ch = (src[i] << 8) | src[i + 1]; + } else { + ch = (src[i + 1] << 8) | src[i]; + } + i += 2; + + uint32_t codepoint = ch; + + // Prüfe auf Surrogatenpaare + if (ch >= 0xD800 && ch <= 0xDBFF) { // High surrogate + if ((i + 1 >= std::numeric_limits::max()) || (src[i] == 0x00 && src[i + 1] == 0x00)) { + log_e("Invalid surrogate pair: missing low surrogate"); + break; + } + uint16_t ch2; + if (is_big_endian) { + ch2 = (src[i] << 8) | src[i + 1]; + } else { + ch2 = (src[i + 1] << 8) | src[i]; + } + if (ch2 < 0xDC00 || ch2 > 0xDFFF) { + log_e("Invalid surrogate pair: invalid low surrogate"); + break; + } + i += 2; + codepoint = 0x10000 + ((ch - 0xD800) << 10) + (ch2 - 0xDC00); + } else if (ch >= 0xDC00 && ch <= 0xDFFF) { + log_e("Invalid surrogate pair: unexpected low surrogate"); + break; + } + + // UTF-16 → UTF-8 + if (codepoint < 0x80) { + out.push_back(static_cast(codepoint)); + } else if (codepoint < 0x800) { + out.push_back(0xC0 | (codepoint >> 6)); + out.push_back(0x80 | (codepoint & 0x3F)); + } else if (codepoint < 0x10000) { + out.push_back(0xE0 | (codepoint >> 12)); + out.push_back(0x80 | ((codepoint >> 6) & 0x3F)); + out.push_back(0x80 | (codepoint & 0x3F)); + } else if (codepoint < 0x110000) { + out.push_back(0xF0 | (codepoint >> 18)); + out.push_back(0x80 | ((codepoint >> 12) & 0x3F)); + out.push_back(0x80 | ((codepoint >> 6) & 0x3F)); + out.push_back(0x80 | (codepoint & 0x3F)); + } else { + log_e("Invalid codepoint"); + break; + } + } + + // Nullterminator hinzufügen + out.push_back('\0'); + + // Speicher allozieren und kopieren + std::size_t bytes = out.size(); + alloc(bytes); + std::memcpy(mem.get(), out.data(), bytes); + return i; + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C O P Y _ F R O M _ I S O _ 8 8 5 9 - 1 📌📌📌 + // convert ISO 8859-1 to UTF-8 and stop at zero terminator + // 0x48 0x65 0x6C 0x6C 0x6F 0x20 0xC3 0xA4 0x62 0x63 0x00 -> "Hello äbc" + + size_t copy_from_iso8859_1(const uint8_t* src) { + if (!src) { + log_e("arg. is null"); + return 0; + } + std::vector out; + size_t i = 0; + + while (true) { + uint8_t ch = src[i]; + if (ch == 0x00) { + break; // 'Nullterminator' + } + + // ISO-8859-1 → UTF-8 + if (ch < 0x80) { + out.push_back(static_cast(ch)); // Ascii area remains unchanged + } else { + // chars from 0x80 to 0xff are coded as 2-byte sequences in UTF-8 + out.push_back(0xC0 | (ch >> 6)); + out.push_back(0x80 | (ch & 0x3F)); + } + i++; + } + + // add zero terminator + out.push_back('\0'); + + // allocate and copy memory + std::size_t bytes = out.size(); + alloc(bytes); + std::memcpy(mem.get(), out.data(), bytes); + return i; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 U R L D E C O D E 📌📌📌 + // Decodes the current string in-place from URL encoding. + // Example: + // ps_ptr url = "%D0%B8%D1%81%D0%BF%D1%8B%D1%82%D0%B0%D0%BD%D0%B8%D0%B5.mp3"; + // url.urldecode(); // → "испытание.mp3" + // url = "Born%20On%20The%20B.mp3"; url.urldecode(); // → "Born On The B.mp3" + // url = "A+Test.mp3"; url.urldecode(); // → "A Test.mp3" + + void urldecode() { + static_assert(std::is_same_v, "urldecode() is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("urldecode: No valid string data"); + return; + } + + char* str = get(); + uint16_t p1 = 0, p2 = 0; + char a, b; + + while (str[p1]) { + if ((str[p1] == '%') && ((a = str[p1 + 1]) && (b = str[p1 + 2])) && (isxdigit(a) && isxdigit(b))) { + + // Normalize lowercase to uppercase + if (a >= 'a') a -= ('a' - 'A'); + if (b >= 'a') b -= ('a' - 'A'); + + // Convert hex digits to numeric + a = (a >= 'A') ? (a - 'A' + 10) : (a - '0'); + b = (b >= 'A') ? (b - 'A' + 10) : (b - '0'); + + str[p2++] = (a << 4) | b; + p1 += 3; + } else if (str[p1] == '+') { + str[p2++] = ' '; + p1++; + } else { + str[p2++] = str[p1++]; + } + } + str[p2] = '\0'; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C L O N E _ F R O M 📌📌📌 + + // ps_ptr source; + // source.assign("Hello World"); + // ps_ptr copy; + // copy.clone_from(source); + // printf("%s\n", copy.get()); // → Hello World + + void clone_from(const ps_ptr& other) { + if (!other.valid() || other.size() == 0) { + reset(); + return; + } + + if constexpr (std::is_same_v) { + assign(other.get()); + return; + } + + std::size_t sz = other.size(); + alloc(sz); + if (mem && sz > 0) { std::memcpy(mem.get(), other.get(), sz); } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S W A P 📌📌📌 + // A.swap(B); + void swap(ps_ptr& other) noexcept { + std::swap(this->mem, other.mem); + std::swap(this->allocated_size, other.allocated_size); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S W A P W I T H R A W P O I N T E R 📌📌📌 + void swap_with_pointer(T*& raw_ptr) noexcept { + T* temp = get(); + mem.release(); // Gib Besitz auf, ohne zu löschen + mem = std::unique_ptr(raw_ptr); // Übernehme neuen Zeiger + raw_ptr = temp; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A P P E N D 📌📌📌 + + // ps_ptr text1; // like Strcat with automatic new allocation + // text1.assign("Hallo", "text"); + // text1.append(", Welt!"); + // printf("%s\n", text1.get()); // → "Hallo, Welt!" + + template + requires std::is_same_v + void append(const char* suffix) { + if (!suffix || !*suffix) return; + + std::size_t old_len = mem ? std::strlen(static_cast(mem.get())) : 0; + std::size_t add_len = std::strlen(suffix); + std::size_t new_len = old_len + add_len + 1; // +1 für null-Terminator + + // Alten Speicher übernehmen + char* old_data = static_cast(mem.release()); + + if (psramFound()) { // Check at the runtime whether PSRAM is available + mem.reset(static_cast(ps_malloc(new_len))); // <--- Important! + } else { + mem.reset(static_cast(malloc(new_len))); + } + if (!mem) { + printf("OOM: append() failed for %zu bytes\n", new_len); + return; + } + + // Copy existing content + if (old_data) { + std::memcpy(mem.get(), old_data, old_len); + free(old_data); + } + + // Append suffix + std::memcpy(static_cast(mem.get()) + old_len, suffix, add_len + 1); + allocated_size = new_len; + static_cast(mem.get())[old_len + add_len] = '\0'; + } + + // ps_ptr text1; // like Strcat with automatic new allocation + // text1.assign("Hallo", "text"); + // text1.append(", Welt!", 4); + // printf("%s\n", text1.get()); // → "Hallo, We" + + template + requires std::is_same_v + void append(const char* suffix, std::size_t len) { + if (!suffix || len == 0) return; + + std::size_t old_len = mem ? std::strlen(static_cast(mem.get())) : 0; + std::size_t new_len = old_len + len + 1; // +1 für null-Terminator + + char* old_data = static_cast(mem.release()); + + if (psramFound()) { // Check at the runtime whether PSRAM is available + mem.reset(static_cast(ps_malloc(new_len))); + } else { + mem.reset(static_cast(malloc(new_len))); + } + if (!mem) { + printf("OOM: append(len) failed for %zu bytes\n", new_len); + return; + } + + if (old_data) { + std::memcpy(mem.get(), old_data, old_len); + free(old_data); + } + + std::memcpy(static_cast(mem.get()) + old_len, suffix, len); + static_cast(mem.get())[old_len + len] = '\0'; + } + + // example: ps_ptr a="Hello "; ps_ptr b="World"; a.append(b); + template + requires std::is_same_v + void append(const ps_ptr& other) { + const char* suffix = other.get(); + if (!suffix || !*suffix) return; // append nothing if empty + + size_t add_len = std::strlen(suffix); + size_t old_len = mem ? std::strlen(static_cast(mem.get())) : 0; + size_t new_len = old_len + add_len + 1; + + char* old_data = static_cast(mem.release()); + + if (psramFound()) { + mem.reset(static_cast(ps_malloc(new_len))); + } else { + mem.reset(static_cast(malloc(new_len))); + } + + if (!mem) { + printf("OOM: append(ps_ptr) failed for %zu bytes\n", new_len); + if (old_data) free(old_data); + return; + } + + if (old_data) { + std::memcpy(mem.get(), old_data, old_len); + free(old_data); + } + + std::memcpy(mem.get() + old_len, suffix, add_len + 1); + allocated_size = new_len; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 P U S H _ B A C K 📌📌📌 + // append individual characters + // ps_ptrs; s = "abc"; s.push_back('1); -> abc1 + + void push_back(char c) { + if (length + 1 >= capacity()) { + // Wenn zu klein, Kapazität verdoppeln (wie std::string) + size_t new_cap = (capacity() == 0) ? 16 : capacity() * 2; + reserve(new_cap); + } + + mem.get()[length++] = c; + mem.get()[length] = '\0'; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 L E N G T H 📌📌📌 + size_t length() const { return length_; } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A P A C I T Y 📌📌📌 + size_t capacity() const { return allocated_size ? allocated_size - 1 : 0; } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E S E R V E 📌📌📌 + void reserve(size_t new_cap) { + if (new_cap + 1 <= allocated_size) return; // genug Platz vorhanden + + char* old_data = mem.release(); + size_t old_len = length(); + + size_t new_size = new_cap + 1; // +1 für '\0' + if (psramFound()) + mem.reset(static_cast(ps_malloc(new_size))); + else + mem.reset(static_cast(malloc(new_size))); + + if (!mem) { + printf("OOM: reserve(%zu) failed\n", new_size); + if (old_data) free(old_data); + return; + } + + if (old_data) { + if (old_len > 0) + std::memcpy(mem.get(), old_data, old_len + 1); + else + mem.get()[0] = '\0'; + free(old_data); + } else { + mem.get()[0] = '\0'; + } + + allocated_size = new_size; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S T A R T S _ W I T H 📌📌📌 + + // ps_ptr s; + // s.assign("https://example.com/file.mp3"); + // + // if (s.starts_with("https://")) { + // printf("https-link recognized\n"); + // } + + // Only for T = Char: Check whether the string begins with the given prefix + template + requires std::is_same_v + bool starts_with(const char* prefix) const { + if (!mem || !prefix) return false; + + const char* str = static_cast(mem.get()); + std::string_view sv(str); // C++17, sicherer als strlen + return sv.starts_with(prefix); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 E N D S _ W I T H 📌📌📌 + + // ps_ptr s; + // s.assign("https://example.com/file.mp3"); + + // if (s.ends_with(".mp3")) { + // printf("mp3-file recognized\n"); + // } + + // Only for T = Char: Check whether the string ends with the given suffix + template + requires std::is_same_v + bool ends_with(const char* prefix) const { + if (!mem || !prefix) return false; + + const char* str = static_cast(mem.get()); + std::string_view sv(str); // C++17, sicherer als strlen + return sv.ends_with(prefix); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S T A R T S _ W I T H _ I C A S E 📌📌📌 + + // ps_ptr url; + // url.assign("https://example.com/TRACK.MP3"); + // + // if (url.starts_with_icase("HTtp")) { + // printf("http recognized (case-insensitive)\n"); + // } + + // case non-sensitive: starts with Prefix? + template + requires std::is_same_v + bool starts_with_icase(const char* prefix) const { + if (!mem || !prefix) return false; + + const char* str = static_cast(mem.get()); + std::size_t prefix_len = std::strlen(prefix); + std::size_t str_len = std::strlen(str); + if (prefix_len > str_len) return false; + + return strncasecmp_local(str, prefix, prefix_len) == 0; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 E N D S _ W I T H _ I C A S E 📌📌📌 + + // ps_ptr url; + // url.assign("https://example.com/TRACK.MP3"); + // + // if (url.ends_with_icase(".mp3")) { + // printf("MP3 recognized (case-insensitive)\n"); + // } + + // case non-sensitive: ends with suffix? + template + requires std::is_same_v + bool ends_with_icase(const char* suffix) const { + if (!mem || !suffix) return false; + + const char* str = static_cast(mem.get()); + std::size_t suffix_len = std::strlen(suffix); + std::size_t str_len = std::strlen(str); + if (suffix_len > str_len) return false; + + return strncasecmp_local(str + str_len - suffix_len, suffix, suffix_len) == 0; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 E Q U A L S 📌📌📌 + // my_ps_ptr t1, t2; + // t1.assign("Hallo"); + // t2.assign("Hallo"); + // + // if (t1.equals(t2)) { + // 👍 is equal + // } + bool equals(const ps_ptr& other) const { + if (!this->valid() || !other.valid()) return false; + if (!this->get() || !other.get()) return false; + return strcmp(this->get(), other.get()) == 0; + } + + bool equals(const char* other) const { + if (!this->valid()) return false; + const char* myStr = this->get(); + if (!myStr || !other) return false; + return strcmp(myStr, other) == 0; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A S S I G N F 📌📌📌 + + // ps_ptr message; + // message.assignf("Code {}, Modul {}", 404, "Network"); + // printf("%s\n", message.get()); // → Error: Code 404, Modul Network + // e.g. {}, {:02}, {:04X}, {:.2f}, {:20}, {:-20} + // assignf("v={:02} hex={:04X} pi={:.2f}", 7, 0xAF, 3.14159); --> v=07 hex=00AF pi=3.14 + // bool --> true or false + + template + requires std::is_same_v + void assignf(const char* fmt, Args&&... args) { + + if (!fmt) return; + + constexpr size_t arg_count = sizeof...(Args); + + size_t placeholder_count = count_placeholders(fmt); + + if (placeholder_count != arg_count) { + printf("assignf(): \033[31m placeholder mismatch (expected %zu, got %zu), content: '%s' \033[0m\n", placeholder_count, arg_count, fmt); + return; + } + + std::string tmp; + + format_append(tmp, fmt, std::forward(args)...); + + reset(); + + alloc(tmp.size() + 1); + + if (!mem) { + printf("OOM: assignf() failed for %zu bytes\n", tmp.size() + 1); + return; + } + + memcpy(mem.get(), tmp.c_str(), tmp.size() + 1); + + allocated_size = tmp.size(); + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A P P E N D F 📌📌📌 + + // ps_ptr message; + // message.assign("Error: "); + // message.appendf("Code {}, Modul {}", 404, "Network"); + // printf("%s\n", message.get()); // → Error: Code 404, Modul Network + + // only activate if T = char + + template + requires std::is_same_v + void appendf(const char* fmt, Args&&... args) { + if (!fmt) return; + + constexpr size_t arg_count = sizeof...(Args); + + size_t placeholder_count = count_placeholders(fmt); + + if (placeholder_count != arg_count) { + printf("appendf(): \033[31m placeholder mismatch (expected %zu, got %zu), content: '%s' \033[0m\n", placeholder_count, arg_count, fmt); + return; + } + + std::string tmp; + format_append(tmp, fmt, std::forward(args)...); + std::size_t old_len = mem ? std::strlen(mem.get()) : 0; + std::size_t add_len = tmp.size(); + std::size_t new_len = old_len + add_len + 1; + char* old_data = static_cast(mem.release()); + reset(); + alloc(new_len); + if (!mem) { + printf("OOM: appendf1() failed for %zu bytes\n", new_len); + if (old_data) { free(old_data); } + return; + } + + // alten Text kopieren + if (old_data && old_len > 0) { + std::memcpy(mem.get(), old_data, old_len); + free(old_data); + } + + // neuen Text anhängen + std::memcpy(mem.get() + old_len, tmp.c_str(), add_len + 1); + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I N D E X _ O F 📌📌📌 + + // char + // ps_ptr text3; + // text3.assign("Hello, World!"); + // int pos = text3.index_of('l'); // → 2 + // printf("found %i\n", pos); + // int not_found = text3.index_of('x'); // → -1 + // printf("not_found %i\n", not_found); + // pos = text3.index_of('l', 5); + // printf("found %i\n", pos); + + // const char* + // ps_ptr path; + // path.assign("audio/music/song.mp3"); + // int i1 = path.index_of('s'); // → z.B. 6 + // int i2 = path.index_of("song"); // → 12 + // int i3 = path.index_of("audio"); // → 0 + // int i4 = path.index_of("test"); // → -1 + // int i5 = path.index_of("music", 7); // → -1 + + // Array + // ps_ptr numbers; + // numbers.copy_from((int[]){10, 20, 30, 40, 50}, 5); + // int idx = numbers.index_of(30); // → 2 + // printf("pos %i\n", idx); + + // General version: for any T (e.g. Int, Float, Structs) + int index_of(const T& value, std::size_t start = 0) const { + if (!mem || allocated_size < sizeof(T)) return -1; + + std::size_t count = allocated_size / sizeof(T); + if (start >= count) return -1; + + T* data = get(); + for (std::size_t i = start; i < count; ++i) { + if (data[i] == value) return static_cast(i); + } + return -1; + } + + // Specialized version: only for T = char (search for individual characters) + template + requires std::is_same_v + int index_of(char ch, std::size_t start = 0) const { + if (!mem) return -1; + + const char* str = static_cast(mem.get()); + std::size_t len = std::strlen(str); + if (start >= len) return -1; + + for (std::size_t i = start; i < len; ++i) { + if (str[i] == ch) return static_cast(i); + } + return -1; + } + // Overload for const char* (substring search) + template + requires std::is_same_v + int index_of(const char* substr, std::size_t start = 0) const { + if (!mem || !substr || !*substr) return -1; + + const char* str = static_cast(mem.get()); + std::size_t len = std::strlen(str); + if (start >= len) return -1; + + const char* found = std::strstr(str + start, substr); + if (!found) return -1; + + return static_cast(found - str); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S P E C I A L _ I N D E X _ O F 📌📌📌 + // Searches for the sequence needle within the buffer managed by ps_ptr (haystack), up to max_length bytes. + // Returns the offset of the first occurrence of needle relative to the buffer start, or -1 if not found. + // Ignores null bytes in both haystack and needle, making it suitable for binary data searches. + // Example: + // ps_ptr haystack; // Contains data, e.g., stsd atom content + // int32_t idx = haystack.index_of("mp4a", 1024); // Search for "mp4a" + // int32_t idx2 = haystack.index_of("\x00\x01\xFF", 3, 1024); // Search for byte sequence + int32_t special_index_of(const char* needle, uint32_t needle_length, uint32_t max_length) const { + static_assert(std::is_same_v, "index_of is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("index_of: No valid buffer data"); + return -1; + } + if (!needle || needle_length == 0) { + log_e("index_of: Invalid needle (null or empty)"); + return -1; + } + if (max_length < needle_length) { + log_e("index_of: max_length (%u) too short to find needle of length %u", max_length, needle_length); + return -1; + } + const char* data = get(); + for (uint32_t i = 0; i <= max_length - needle_length; ++i) { + if (std::memcmp(data + i, needle, needle_length) == 0) { + // log_i("index_of: Found needle at offset %u", i); + return static_cast(i); + } + } + log_d("index_of: Needle not found within %lu bytes", max_length); + return -1; + } + template + requires std::is_same_v + int32_t special_index_of(const char* needle, uint32_t max_length) const { + return special_index_of(needle, needle ? std::strlen(needle) : 0, max_length); + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 L A S T _ S P E C I A L _ I N D E X _ O F 📌📌📌 + // Overload for C-string needle (automatically determines needle length, excluding null terminator) + // Searches backwards for needle in the buffer. + // Returns the offset of the last occurrence or -1 if not found. + + int32_t last_special_index_of(const char* needle, uint32_t needle_length, uint32_t max_length) const { + static_assert(std::is_same_v, "last_special_index_of is only valid for ps_ptr"); + + if (!mem || !get()) { + log_e("last_special_index_of: No valid buffer data"); + return -1; + } + + if (!needle || needle_length == 0) { + log_e("last_special_index_of: Invalid needle (null or empty)"); + return -1; + } + + if (max_length < needle_length) { + log_e("last_special_index_of: max_length (%u) too short to find needle of length %u", max_length, needle_length); + return -1; + } + + const char* data = get(); + + for (int32_t i = static_cast(max_length - needle_length); i >= 0; --i) { + + if (std::memcmp(data + i, needle, needle_length) == 0) { return i; } + } + + log_d("last_special_index_of: Needle not found within %lu bytes", max_length); + return -1; + } + + // Overload for C-string needle + template + requires std::is_same_v + int32_t last_special_index_of(const char* needle, uint32_t max_length) const { + return last_special_index_of(needle, needle ? std::strlen(needle) : 0, max_length); + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I N D E X _ O F _ I C A S E 📌📌📌 + + // ps_ptr s; + // s.assign("Content-Type: audio/mp3"); + // + // int idx1 = s.index_of_icase("CONTENT"); // 0 + // int idx2 = s.index_of_icase("audio"); // 14 + // int idx3 = s.index_of_icase("MP3"); // 20 + // int idx4 = s.index_of_icase("notfound"); // -1 + + // Case-insensitive substring search + template + requires std::is_same_v + int index_of_icase(const char* substr, std::size_t start = 0) const { + if (!mem || !substr || !*substr) return -1; + + const char* str = static_cast(mem.get()); + std::size_t len_str = std::strlen(str); + std::size_t len_sub = std::strlen(substr); + if (start >= len_str || len_sub == 0 || len_sub > len_str) return -1; + + for (std::size_t i = start; i <= len_str - len_sub; ++i) { + bool match = true; + for (std::size_t j = 0; j < len_sub; ++j) { + if (std::tolower(str[i + j]) != std::tolower(substr[j])) { + match = false; + break; + } + } + if (match) return static_cast(i); + } + return -1; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 L A S T _ I N D E X _ O F 📌📌📌 + + template + requires std::is_same_v + int last_index_of(char ch, int start_pos = -1) const { + if (!mem) return -1; + + const char* str = static_cast(mem.get()); + int len = static_cast(std::strlen(str)); + + // if no start position is specified, start at the end + if (start_pos < 0 || start_pos >= len) start_pos = len - 1; + + for (int i = start_pos; i >= 0; --i) { + if (str[i] == ch) return i; + } + return -1; + } + + // ps_ptr str1; + // str1.assign("OpenAI API Test"); + // int last_i = str1.last_index_of('i'); // → -1 (no 'i', but 'I' ≠ 'i') + // int last_A = str1.last_index_of('A'); // → 5 + // printf("last_i %i\n", last_i); + // printf("last_A %i\n", last_A); + + // ps_ptr str; + // str.assign("/audiofiles/my_playlist/podcast/h.mp3"); + // int last = str.last_index_of('/'); // → 32 (the last '/') + // int prev = str.last_index_of('/', last - 1); // → 23 (the second to last '/') + + template + requires std::is_same_v + int last_index_of(const char ch, int start_pos = -1) const { + if (!mem) return -1; + + const char* str = static_cast(mem.get()); + int len = static_cast(std::strlen(str)); + + // if no start position is specified, start at the end + if (start_pos < 0 || start_pos >= len) start_pos = len - 1; + + for (int i = start_pos; i >= 0; --i) { + if (str[i] == ch) return i; + } + return -1; + } + + // ps_ptr str; + // str.assign("/audiofiles/my_playlist/podcast/h.mp3"); + // int p1 = str.last_index_of("/"); // 31 + // int p2 = str.last_index_of("podcast"); // 24 + // int p3 = str.last_index_of(".mp3"); // 33 + // int p4 = str.last_index_of("xyz"); // -1 + + // ps_ptr str; + // str.assign("abc test abc test abc"); + // int last = str.last_index_of("abc"); // 18 + // int prev = str.last_index_of("abc", last - 1); // 9 + + template + requires std::is_same_v + int last_index_of(const char* substr, int start_pos = -1) const { + if (!mem || !substr || !*substr) return -1; + + const char* str = static_cast(mem.get()); + + int len = static_cast(std::strlen(str)); + int sub_len = static_cast(std::strlen(substr)); + + if (sub_len > len) return -1; + + // Standard: am Ende beginnen + if (start_pos < 0 || start_pos > len - sub_len) { start_pos = len - sub_len; } + + for (int i = start_pos; i >= 0; --i) { + if (std::strncmp(str + i, substr, sub_len) == 0) { return i; } + } + return -1; + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I N D E X _ O F _ S U B S T R 📌📌📌 + + // source must not be null terminated + // ps_ptr buffer; + // buffer.assign("abc123ID3TAGthisisjustatest...", "mp3scan"); + // int pos1 = buffer.index_of_substr("ID3", 20); // → finds "ID3" at index 6 + // printf("ID3 found at: %d\n", pos1); + + template + requires std::is_same_v + int index_of_substr(const char* needle, std::size_t max_pos = SIZE_MAX) const { + if (!mem || !needle || !*needle) return -1; + + const char* haystack = static_cast(mem.get()); + std::size_t hay_len = std::min(std::strlen(haystack), max_pos); + std::size_t needle_len = std::strlen(needle); + + if (needle_len > hay_len) return -1; + + for (std::size_t i = 0; i <= hay_len - needle_len; ++i) { + if (std::memcmp(haystack + i, needle, needle_len) == 0) { return static_cast(i); } + } + + return -1; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S U B S T R 📌📌📌 + ps_ptr substr(size_t pos, size_t count = std::string::npos) const { + const char* src = mem.get(); + if (!src) return ps_ptr{}; + + size_t len = std::strlen(src); + if (pos >= len) return ps_ptr{}; // leer zurück + + size_t n = (count == std::string::npos || pos + count > len) ? (len - pos) : count; + + return ps_ptr(src + pos, n); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O L O W E R C A S E 📌📌📌 + + // ps_ptr a; // ascii and ISO-8859-1 only! + // a = "Hallo Welt!"; + // a.toLowerCase(); + // printf("%s\n", a.get()); // hallo welt! + + template + requires std::is_same_v + void toLowerCase() { + if (!mem) return; + + char* str = get(); + if (!str) return; + + for (; *str; ++str) { *str = static_cast(std::tolower(static_cast(*str))); } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O U P P E R C A S E 📌📌📌 + + // ps_ptr a; // ascii and ISO-8859-1 only! + // a = "Hallo Welt!"; + // a.toUpperCase(); + // printf("%s\n", a.get()); // HALLO WELT! + + template + requires std::is_same_v + void toUpperCase() { + if (!mem) return; + + char* str = get(); + if (!str) return; + + for (; *str; ++str) { *str = static_cast(std::toupper(static_cast(*str))); } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S T R L E N 📌📌📌 + + // ps_ptr text; + // text.assign("Hello"); + // text.strlen(); // --> 5 + + template + requires std::is_same_v + size_t strlen() const { + if (!valid()) return 0; + return std::strlen(get()); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 U T F 8 _ S T R L E N 📌📌📌 + + // ps_ptr colored; // ignoring ANSI + // colored.assign("\033[31mПривет\033[0m", "russian red"); + // size_t visibleLetters = colored.utf8_strlen; // --> 6 + + size_t utf8_strlen() const { + if (!get()) return 0; + + size_t count = 0; + const unsigned char* s = reinterpret_cast(get()); + + while (*s) { + // ANSI-Escape-Sequenz starts with ESC [ + if (*s == 0x1B && s[1] == '[') { + s += 2; + while (*s && !(*s >= '@' && *s <= '~')) { + ++s; // Parameter sign (numbers, semicola etc.) + } + if (*s) ++s; // Final letter z.B. 'M' + continue; + } + + // UTF-8-Count characters + if ((*s & 0x80) == 0) + s += 1; // ASCII + else if ((*s & 0xE0) == 0xC0) + s += 2; // 2 Byte + else if ((*s & 0xF0) == 0xE0) + s += 3; // 3 Byte + else if ((*s & 0xF8) == 0xF0) + s += 4; // 4 Byte + else + s += 1; // invalid ? carefully next + + ++count; + } + + return count; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I S _ U T F 8 📌📌📌 + + // ps_ptr a = "Hello"; // ASCII → valid UTF-8 + // ps_ptr b = u8"Привет"; // Russian → valid UTF-8 + // ps_ptr c = "\xC3\x28"; // invalid (bad UTF-8 sequence) + + // if (is_utf8(a)) printf("a is UTF-8\n"); + // if (is_utf8(b)) printf("b is UTF-8\n"); + // if (!is_utf8(c)) printf("c is not UTF-8\n"); + + bool is_utf8() const { + const unsigned char* s = reinterpret_cast(mem.get()); + if (!s) return false; + + while (*s) { + unsigned char c = *s++; + + // 1-byte ASCII (0xxxxxxx) + if (c < 0x80) continue; + + // 2-byte-sequence (110xxxxx 10xxxxxx) + if ((c >> 5) == 0x6) { + if ((s[0] & 0xC0) != 0x80) return false; + s += 1; + continue; + } + + // 3-byte-sequence (1110xxxx 10xxxxxx 10xxxxxx) + if ((c >> 4) == 0xE) { + if ((s[0] & 0xC0) != 0x80 || (s[1] & 0xC0) != 0x80) return false; + + unsigned int cp = ((c & 0x0F) << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F); + // Excessive coding or surrogate? + if (cp < 0x800 || (cp >= 0xD800 && cp <= 0xDFFF)) return false; + + s += 2; + continue; + } + + // 4-byte-sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx) + if ((c >> 3) == 0x1E) { + if ((s[0] & 0xC0) != 0x80 || (s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80) return false; + + unsigned int cp = ((c & 0x07) << 18) | ((s[0] & 0x3F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); + // Overlong or out of Unicode range + if (cp < 0x10000 || cp > 0x10FFFF) return false; + + s += 3; + continue; + } + + // Invalid starting byte + return false; + } + + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I S _ J S O N 📌📌📌 + + // ps_ptrjsonIn; + // jsonIn.assign("{\"status\":1,\"message\":\"Ok\",\"result\":\"Ok\",\"errorCode\":0}"); + + bool isJson() const { + if (!mem || allocated_size < 2) return false; + + const char* p = static_cast(mem.get()); + + // Skip leading whitespace + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + + // Check if it starts with '{' + if (*p != '{') return false; + + // Skip to end, ignoring trailing whitespace + const char* end = mem.get() + std::strlen(mem.get()) - 1; + while (end > p && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--; + + // Check if it ends with '}' + if (*end != '}') return false; + + // Basic JSON structure validation + bool in_string = false; + int brace_count = 0; + const char* curr = p; + + while (curr <= end) { + if (!in_string) { + if (*curr == '{') + brace_count++; + else if (*curr == '}') + brace_count--; + else if (*curr == '"') + in_string = true; + else if (*curr == ':' || *curr == ',') { + // Allow colons and commas outside strings + } else if (*curr != ' ' && *curr != '\t' && *curr != '\n' && *curr != '\r') { + // Allow digits, true, false, null, etc., but for simplicity, we just check for valid chars + if (!(*curr >= '0' && *curr <= '9') && *curr != '-' && *curr != '.' && *curr != 't' && *curr != 'f' && *curr != 'n' && *curr != '[' && *curr != ']') { + return false; // Invalid character outside string + } + } + } else { + if (*curr == '"') + in_string = false; + else if (*curr == '\\') + curr++; // Skip escaped character + } + curr++; + + if (brace_count < 0) return false; // Unmatched closing brace + } + + return brace_count == 0; // Ensure all braces are matched + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 U N I C O D E _ T O _ U T F 8 📌📌📌 + // ps_ptr jsonIn, decoded; + // jsonIn.assign("\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442"); // Привет + // decoded.unicodeToUTF8(jsonIn.get()); + // log_i("%s", decoded.get()); // shows: Привет + + void unicodeToUTF8(const char* src) { + this->clear(); + if (!src) return; + + auto encodeCodepointToUTF8 = [](uint32_t cp, char* out) -> int { + if (cp <= 0x7F) { + out[0] = cp; + return 1; + } else if (cp <= 0x7FF) { + out[0] = 0xC0 | (cp >> 6); + out[1] = 0x80 | (cp & 0x3F); + return 2; + } else if (cp <= 0xFFFF) { + out[0] = 0xE0 | (cp >> 12); + out[1] = 0x80 | ((cp >> 6) & 0x3F); + out[2] = 0x80 | (cp & 0x3F); + return 3; + } else if (cp <= 0x10FFFF) { + out[0] = 0xF0 | (cp >> 18); + out[1] = 0x80 | ((cp >> 12) & 0x3F); + out[2] = 0x80 | ((cp >> 6) & 0x3F); + out[3] = 0x80 | (cp & 0x3F); + return 4; + } + return 0; + }; + + const char* ptr = src; + char utf8[5]; + + while (*ptr) { + if (ptr[0] == '\\' && ptr[1] == 'u') { + uint32_t codepoint = 0; + if (sscanf(ptr + 2, "%4lx", &codepoint) == 1) { + int len = encodeCodepointToUTF8(codepoint, utf8); + utf8[len] = 0; + this->append(utf8); + ptr += 6; // überspringe \uXXXX + } else { + this->append(ptr, 1); + ptr++; + } + } else { + this->append(ptr, 1); + ptr++; + } + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 H T M L T O U T F 8 📌📌📌 + // ps_ptr html, utf8; + // html.assign("Hello%20World"); + // utf8.unicodeToUTF8(html.get()); + // log_i("%s", utf8.get()); // shows: Hallo World + + void htmlToUTF8(const char* src) { + this->clear(); + if (!src) return; + + struct EntityMap { + const char* name; + uint32_t codepoint; + }; + + static const EntityMap entities[] = { + {"amp", 0x0026}, // & + {"lt", 0x003C}, // < + {"gt", 0x003E}, // > + {"quot", 0x0022}, // " + {"apos", 0x0027}, // ' + {"nbsp", 0x00A0}, // non-breaking space + {"euro", 0x20AC}, // € + {"copy", 0x00A9}, // © + {"reg", 0x00AE}, // ® + {"trade", 0x2122}, // ™ + {"hellip", 0x2026}, // … + {"ndash", 0x2013}, // – + {"mdash", 0x2014}, // — + {"sect", 0x00A7}, // § + {"para", 0x00B6} // ¶ + }; + + auto encodeCodepointToUTF8 = [](uint32_t cp, char* out) -> int { + if (cp <= 0x7F) { + out[0] = (char)cp; + return 1; + } else if (cp <= 0x7FF) { + out[0] = (char)(0xC0 | (cp >> 6)); + out[1] = (char)(0x80 | (cp & 0x3F)); + return 2; + } else if (cp <= 0xFFFF) { + out[0] = (char)(0xE0 | (cp >> 12)); + out[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[2] = (char)(0x80 | (cp & 0x3F)); + return 3; + } else if (cp <= 0x10FFFF) { + out[0] = (char)(0xF0 | (cp >> 18)); + out[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + out[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[3] = (char)(0x80 | (cp & 0x3F)); + return 4; + } + return 0; + }; + + auto find_named_entity = [&](const char* p, uint32_t* cp_out, int* entity_len) -> bool { + for (size_t i = 0; i < sizeof(entities) / sizeof(entities[0]); ++i) { + const char* name = entities[i].name; + size_t len = std::strlen(name); + if (strncmp(p + 1, name, len) == 0 && p[1 + len] == ';') { + *cp_out = entities[i].codepoint; + *entity_len = (int)(len + 2); // &name; + return true; + } + } + return false; + }; + + const char* p = src; + char utf8[5]; + + while (*p) { + if (p[0] == '&') { + uint32_t cp = 0; + int ent_len = 0; + + // 1) Named entity + if (find_named_entity(p, &cp, &ent_len)) { + int n = encodeCodepointToUTF8(cp, utf8); + if (n > 0) { + utf8[n] = '\0'; + this->append(utf8); + p += ent_len; + continue; + } + } + + // 2) Numeric entity + if (p[1] == '#') { + const char* q = p + 2; + uint32_t value = 0; + + if (*q == 'x' || *q == 'X') { + // Hex 😊 + q++; + char* endptr = nullptr; + unsigned long tmp = strtoul(q, &endptr, 16); + if (endptr && *endptr == ';' && tmp <= 0x10FFFF) { + value = (uint32_t)tmp; + int n = encodeCodepointToUTF8(value, utf8); + if (n > 0) { + utf8[n] = '\0'; + this->append(utf8); + p = endptr + 1; + continue; + } + } + } else { + // Decimal Ӓ + char* endptr = nullptr; + unsigned long tmp = strtoul(q, &endptr, 10); + if (endptr && *endptr == ';' && tmp <= 0x10FFFF) { + value = (uint32_t)tmp; + int n = encodeCodepointToUTF8(value, utf8); + if (n > 0) { + utf8[n] = '\0'; + this->append(utf8); + p = endptr + 1; + continue; + } + } + } + } + + // Unbekannte Entity → nur '&' übernehmen + this->append(p, 1); + p++; + continue; + } + + // Normales Zeichen + this->append(p, 1); + p++; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 G E T 📌📌📌 + T* get() const { return static_cast(mem.get()); } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C_G E T (safe) 📌📌📌 + const char* c_get(const char* fallback = "") const { + if constexpr (std::is_same_v) { + return mem ? mem.get() : fallback; + } else { + return fallback; + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 P R I N T 📌📌📌 + // Prints the stored string to the standard output using printf. + // Only valid for ps_ptr. Uses c_get() to safely handle null cases. + template + requires std::is_same_v + void print() const { + printf("%s: %s", name ? name : "unnamed", c_get()); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 P R I N T L N 📌📌📌 + // Prints the stored string to the standard output using printf. + // Only valid for ps_ptr. Uses c_get() to safely handle null cases. + template + requires std::is_same_v + void println() const { + printf("%s: %s\n", name ? name : "unnamed", c_get()); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S E T 📌📌📌 + + // ps_ptr p; + // uint32_t* raw = (uint32_t*)malloc(100 * sizeof(uint32_t)); // create memory manually + + // for (int i = 0; i < 100; ++i) {// write data + // raw[i] = i * i; + // } + // p.set(raw, 100 * sizeof(uint32_t)); // ps_ptr takes over the pointer and remembers the size + // for (int i = 0; i < 5; ++i) {// access with ps_ptr + // printf("%u ", p[i]); + // } // later at p.reset () or automatically in the destructor `free(raw)` + void set(T* ptr, std::size_t size = 0) { + if (mem.get() != ptr) { + mem.reset(ptr); + allocated_size = size; + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A T 📌📌📌 + + // Special method for ps_ptr> + template auto at(size_t index) -> typename std::enable_if>::value, ps_ptr&>::type { + return static_cast*>(get())[index]; + } + using element_type = T; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A S 📌📌📌 + + // ps_ptr generic; + // generic.alloc(64); + // uint32_t* p = generic.as(); + + template U* as() const { return reinterpret_cast(get()); } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 I N S E R T 📌📌📌 + + // ps_ptr audioPath; + // audioPath.assign("mp3files/test.mp3", "audioPath"); + // audioPath.insert("/", 0); // result: "/mp3files/test.mp3" + // + // audioPath.insert("local/", 1); // result: "/local/mp3files/test.mp3" + + bool insert(const char* insertStr, std::size_t pos) { + if (!insertStr || !valid()) return false; + + std::size_t originalLen = std::strlen(get()); + std::size_t insertLen = std::strlen(insertStr); + + // Position outside the valid area?Then add to the end + if (pos > originalLen) pos = originalLen; + + // New total length + 1 for '\ 0' + std::size_t newLen = originalLen + insertLen + 1; + ps_ptr temp; + temp.alloc(newLen); + if (!temp.valid()) return false; + + char* dst = temp.get(); + + // Copy up to the insertion position + std::memcpy(dst, get(), pos); + // Add new content + std::memcpy(dst + pos, insertStr, insertLen); + // Copy the rest of the original + std::memcpy(dst + pos + insertLen, get() + pos, originalLen - pos + 1); // +1 für \0 + + // Take over new content + this->assign(temp.get()); + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S H R I N K _ T O _ F I T 📌📌📌 + + // Only for Char: Put the buffer on the actual length +1 (for \ 0) + template + requires std::is_same_v + void shrink_to_fit() { + if (!mem) return; + std::size_t len = std::strlen(get()); + if (len == 0) return; + ps_ptr temp; + temp.alloc(len + 1); + if (!temp.valid()) return; + std::memcpy(temp.get(), get(), len + 1); // inklusive \0 + this->assign(temp.get()); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O _ U I N T 6 4 📌📌📌 + // Retrieves the numeric value (uint64_t) from the stored string, parsing it as a number in the specified base (default: 16 for hexadecimal). + // Example: If the stored string is "0x12345678", returns 0x12345678. + // If the string is empty, null, or invalid, returns 0 and logs an error. + + // ps_ptr mediaSeqStr = "227213779"; + // uint64_t mediaSeq = mediaSeqStr.to_uint64(10); + // + // ps_ptr addr = "0x1A3B"; + // uint64_t val = addr.to_uint64(16); + + template + requires std::is_same_v + uint64_t to_uint64(int base = 10) const { + static_assert(std::is_same_v, "to_uint64 is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("to_uint64: No valid string data"); + return 0; + } + const char* str = get(); + char* end = nullptr; + uint64_t result = std::strtoull(str, &end, base); + if (end == str) { + log_e("to_uint64: Invalid numeric value in '%s' for base %d", str, base); + return 0; + } + return result; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O _ U I N T 3 2 📌📌📌 + // Retrieves the numeric value (uint32_t) from the stored string, parsing it as a number in the specified base (default: 10 for decimal). + // Example: If the stored string is "0x1A3B", returns 0x1A3B (6715) for base 16. + // If the string is empty, null, invalid, or exceeds UINT32_MAX (4294967295), returns 0 and logs an error. + // Usage: + // ps_ptr size = "227213779"; uint32_t val = size.to_uint32(10); // Returns 227213779 + // ps_ptr addr = "0x1A3B"; uint32_t val = addr.to_uint32(16); // Returns 6715 + uint32_t to_uint32(int base = 10) const { + static_assert(std::is_same_v, "to_uint32 is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("to_uint32: No valid string data"); + return 0; + } + const char* str = get(); + char* end = nullptr; + unsigned long result = std::strtoul(str, &end, base); + if (end == str) { + log_e("to_uint32: Invalid numeric value in '%s' for base %i", str, base); + return 0; + } + if (result > UINT32_MAX) { + log_e("to_uint32: Value in '%s' exceeds UINT32_MAX (%u) for base %i", str, UINT32_MAX, base); + return 0; + } + return static_cast(result); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O _ I N T 3 2 📌📌📌 + // Retrieves the numeric value (int32_t) from the stored string, parsing it as a number in the specified base (default: 10 for decimal). + // Example: + // ps_ptr temp = "-12345"; int32_t val = temp.to_int32(10); // Returns -12345 + // ps_ptr hex = "0x7FFF"; int32_t val = hex.to_int32(16); // Returns 32767 + // If the string is empty, null, invalid, or exceeds INT32 range (-2147483648 ... 2147483647), returns 0 and logs an error. + + int32_t to_int32(int base = 10) const { + static_assert(std::is_same_v, "to_int32 is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("to_int32: No valid string data"); + return 0; + } + + const char* str = get(); + char* end = nullptr; + long result = std::strtol(str, &end, base); + if (result == 0 && errno == EINVAL) { + log_e("invalid content %s", str); + return 0; + } + + if (end == str) { + log_e("to_int32: Invalid numeric value in '%s' for base %i", str, base); + return 0; + } + + if (result < INT32_MIN || result > INT32_MAX) { + log_e("to_int32: Value in '%s' exceeds INT32 range (%ld..%ld) for base %i", str, (long)INT32_MIN, (long)INT32_MAX, base); + return 0; + } + + return static_cast(result); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T O _ I N T 6 4 📌📌📌 + // Retrieves the numeric value (int64_t) from the stored string, parsing it as a number + // in the specified base (default: 10 for decimal). + // + // Examples: + // ps_ptr val1 = "9223372036854775807"; int64_t v1 = val1.to_int64(); // OK + // ps_ptr val2 = "-1234567890123"; int64_t v2 = val2.to_int64(); // OK + // ps_ptr val3 = "0x7FFFFFFFFFFFFFFF"; int64_t v3 = val3.to_int64(16); // OK + // + // If the string is empty, invalid, or exceeds INT64 range (-9223372036854775808 .. 9223372036854775807), + // returns 0 and logs an error. + + int64_t to_int64(int base = 10) const { + static_assert(std::is_same_v, "to_int64 is only valid for ps_ptr"); + if (!mem || !get()) { + log_e("to_int64: No valid string data"); + return 0; + } + + const char* str = get(); + char* end = nullptr; + long long result = std::strtoll(str, &end, base); + + if (end == str) { + log_e("to_int64: Invalid numeric value in '%s' for base %i", str, base); + return 0; + } + + if (result < INT64_MIN || result > INT64_MAX) { + log_e("to_int64: Value in '%s' exceeds INT64 range (%lld..%lld) for base %i", str, (long long)INT64_MIN, (long long)INT64_MAX, base); + return 0; + } + + return static_cast(result); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + // 📌📌📌 B I G _ E N D I A N 📌📌📌 + // Reads up to 8 bytes from a uint8_t array in big-endian order and stores the value as a hexadecimal string (e.g., "0x12345678"). + // Example: uint8_t data[] = {0x12, 0x34, 0x56, 0x78}; → stores "0x12345678" + // If size > 8, only the first 8 bytes are processed. If size = 0 or data = nullptr, stores "0x0". + template + requires std::is_same_v + void big_endian(const uint8_t* data, uint8_t size) { + static_assert(std::is_same_v, "big_endian is only valid for ps_ptr"); + if (!data || size == 0) { + log_e("big_endian: Invalid input (data is null or size is 0)"); + assign("0x0"); + return; + } + if (size > 8) { + log_e("big_endian: Size %u exceeds 8 bytes, truncating to 8", size); + size = 8; + } + uint64_t result = 0; + for (uint8_t i = 0; i < size; ++i) { result = (result << 8) | data[i]; } + char buffer[19]; // Max: "0x" + 16 chars for uint64_t + null terminator + snprintf(buffer, sizeof(buffer), "0x%llx", result); + assign(buffer); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 L I T T L E _ E N D I A N 📌📌📌 + // Reads up to 8 bytes from a uint8_t array in little-endian order and stores the value as a hexadecimal string (e.g., "0x12345678"). + // Example: uint8_t data[] = {0x78, 0x56, 0x34, 0x12}; → stores "0x12345678" + // If size > 8, only the first 8 bytes are processed. If size = 0 or data = nullptr, stores "0x0". + template + requires std::is_same_v + void little_endian(const uint8_t* data, uint8_t size) { + static_assert(std::is_same_v, "little_endian is only valid for ps_ptr"); + if (!data || size == 0) { + log_e("little_endian: Invalid input (data is null or size is 0)"); + assign("0x0"); + return; + } + if (size > 8) { + log_e("little_endian: Size %u exceeds 8 bytes, truncating to 8", size); + size = 8; + } + uint64_t result = 0; + for (int i = size - 1; i >= 0; --i) { result = (result << 8) | data[i]; } + char buffer[19]; // Max: "0x" + 16 chars for uint64_t + null terminator + snprintf(buffer, sizeof(buffer), "0x%llx", result); + assign(buffer); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E M O V E _ C H A R S 📌📌📌 + + // ps_ptr txt; + // txt.copy_from("[00:12.45]", "time"); + // txt.remove_chars("[]:."); // → 001245 + + void remove_chars(const char* chars) { + if (!valid() || !chars) return; + char* n = name; + char* dst = get(); + char* src = get(); + + while (*src) { + if (!std::strchr(chars, *src)) { *dst++ = *src; } + ++src; + } + *dst = '\0'; + name = n; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E P L A C E 📌📌📌 + + // ps_ptr path; + // path.assign("/user/temp/file.tmp"); + // path.replace("temp", "music"); + // result: "/user/music/file.tmp" + + bool replace(const char* from, const char* to) { + if (!valid() || !from || !*from || !to) return false; + + const char* src = get(); + std::size_t fromLen = std::strlen(from); + std::size_t toLen = std::strlen(to); + + if (fromLen == 0) return false; // Nichts zu ersetzen + + std::vector result; + const char* read = src; + + while (*read) { + if (std::strncmp(read, from, fromLen) == 0) { + // Match gefunden + result.insert(result.end(), to, to + toLen); + read += fromLen; + } else { + result.push_back(*read++); + } + } + + result.push_back('\0'); + + // Kopiere Ergebnis zurück + this->copy_from(result.data(), result.size() - 1); + return true; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T R I M 📌📌📌 + + // ps_ptr text3; + // text3.assign(" Hello, World! "); + // text3.trim(); // → "Hello, World!" + + template + requires std::is_same_v + void trim() { + if (!mem) return; + + char* str = static_cast(mem.get()); + std::size_t len = std::strlen(str); + if (len == 0) return; + + // trim on the left + char* start = str; + while (*start && isspace(*start)) ++start; + + // trim on the right + char* end = str + len - 1; + while (end >= start && isspace(*end)) --end; + *(end + 1) = '\0'; + + // If not at the beginning, copy everything forward + if (start != str) { + std::size_t new_len = end - start + 1; + std::memmove(str, start, new_len + 1); + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 T R U N C A T E _ A T 📌📌📌 + + // ps_ptrt; + // t.assign("Hello, World"); + // t.truncate_at(','); --> "Hello" + + // ps_ptrt; + // t.assign("Hello, World"); + // t.truncate_at('5'); --> "Hello" + + void truncate_at(char ch) { + if (!valid()) return; + char* str = get(); + char* pos = strchr(str, ch); + if (pos) *pos = '\0'; + } + + void truncate_at(std::size_t pos) { + if (!valid()) return; + if (pos >= strlen()) return; + char* str = get(); + std::size_t len = std::strlen(str); + if (pos < len) + str[pos] = '\0'; + else + log_e("truncate pos %i out of length %i", pos, len); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E M O V E _ P R E F I X 📌📌📌 + // ps_ptr t; + // t.assign("../../2093120-b/RISMI/stream01/streamPlaylist.m3u8"); + // t.remove_prefix("../../"); // Result: "2093120-b/RISMI/stream01/streamPlaylist.m3u8" + + void remove_prefix(const char* prefix) { + if (!valid() || !prefix) return; + + std::size_t prefix_len = std::strlen(prefix); + if (std::strncmp(get(), prefix, prefix_len) == 0) { + char* str = get(); + std::size_t len = std::strlen(str); + std::memmove(str, str + prefix_len, len - prefix_len + 1); // inkl. '\0' + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E M O V E _ B E F O R E 📌📌📌 + // t.assign("../../2093120-b/RISMI/stream01/streamPlaylist.m3u8"); + // t.remove_before('/'); // removed until the first '/' + // Result: "../2093120-b/RISMI/stream01/streamPlaylist.m3u8" + + void remove_before(char ch, bool includeChar = true) { + if (!valid()) return; + + char* str = get(); + char* pos = strchr(str, ch); + if (pos) { + if (!includeChar) ++pos; // wenn nicht inklusive: das Zeichen behalten + std::size_t remaining = std::strlen(pos); + std::memmove(str, pos, remaining + 1); // inkl. '\0' + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E M O V E _ B E F O R E ( B Y I N D E X ) 📌📌📌 + // t.assign("HelloWorld"); + // t.remove_before(5); // entfernt "Hello" + // t.remove_before(5, false); // entfernt nur "Hell", das Zeichen an idx bleibt + + void remove_before(int idx, bool includeIdx = true) { + if (!valid()) return; + + char* str = get(); + std::size_t len = std::strlen(str); + + if (idx < 0 || static_cast(idx) > len) return; + + char* pos = str + idx; + if (!includeIdx && idx < len) ++pos; // wenn das Zeichen nicht entfernt werden soll + + std::size_t remaining = std::strlen(pos); + std::memmove(str, pos, remaining + 1); // inkl. '\0' + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S H I F T _ L E F T 📌📌📌 + // Show the contents of the buffer around n bytes to the left and fill the rest with zeros + // Consider UTF-16 data and the size of the allocated memory + + void shift_left(int n) { + if (!mem || allocated_size == 0) { + printf("Error: No allocated memory or invalid buffer\n"); + return; + } + + if (n < 0 || static_cast(n) > allocated_size) { + printf("Error: Invalid shift amount %d, allocated_size=%zu\n", n, allocated_size); + return; + } + + // if (n % 2 != 0) { + // printf("Warning: Shift amount %d is not even, adjusting to %d for UTF-16 alignment\n", n, n + 1); + // n += 1; // make sure n is even for UTF-16 + // } + + char* str = mem.get(); + if (n == 0) return; + + // show the buffer around n bytes to the left + std::size_t remaining = allocated_size - n; + std::memmove(str, str + n, remaining); + + // fill the rest of the memory with zeros + std::memset(str + remaining, 0, n); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C O N T A I N S 📌📌📌 + + // if (t.contains("xyz")) { + // "xyz" occurs in t + // } + + bool contains(const char* substr) const { return substr && this->valid() && std::strstr(this->get(), substr); } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C O N T A I N S _ W I T H _ I C A S E 📌📌📌 + bool contains_with_icase(const char* substr) const { + if (!substr || !this->valid()) { return false; } + + const char* haystack = this->get(); + const char* needle = substr; + + // Wir kopieren den Text in temporäre lowercase-Strings + std::string haystack_lower(haystack); + std::string needle_lower(needle); + + std::transform(haystack_lower.begin(), haystack_lower.end(), haystack_lower.begin(), [](unsigned char c) { return std::tolower(c); }); + std::transform(needle_lower.begin(), needle_lower.end(), needle_lower.begin(), [](unsigned char c) { return std::tolower(c); }); + + return haystack_lower.find(needle_lower) != std::string::npos; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C L E A R 📌📌📌 + + void clear() { + if (mem && allocated_size > 0) { + std::memset(mem.get(), 0, allocated_size); + length_ = 0; + } + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 S I Z E 📌📌📌 + + size_t size() const { return allocated_size; } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 E M P T Y 📌📌📌 + + bool empty() const noexcept { return allocated_size == 0; } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 V A L I D 📌📌📌 + + bool valid() const { return mem != nullptr; } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E S E T 📌📌📌 + + void reset() { + mem.reset(); + allocated_size = 0; + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 H E X _ D U M P 📌📌📌 + // ps_ptrbuff; + // buff.calloc(10); + // buff.assign("eng\n"); + // buff.hex_dump(6); + // + // 0x65 0x6E 0x67 0x0A 0x00 0x00 + // e n g LF NUL NUL + + void hex_dump(uint16_t n = UINT16_MAX) { + if (!valid()) { + printf("hex_dump: invalid buffer\n"); + return; + } + + if (allocated_size < n) n = allocated_size; + if (n == 0) { + printf("hex_dump: no data\n"); + return; + } + + uint8_t items_per_line = 30; + + static const char* sym[32] = {"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS ", "TAB", "LF ", "VT ", "FF ", "CR ", "SO ", "SI ", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM ", "SUB", "ESC", "FS ", "GS ", "RS ", "US "}; + + const uint8_t* buff = reinterpret_cast(get()); + if (!name) + printf("dumping %u bytes:\n", n); + else + printf("%s dumping %u bytes:\n", name, n); + + for (uint16_t i = 0; i < n; i += items_per_line) { + uint16_t m = std::min(n, i + items_per_line); + uint8_t s = 0; + + // Hex view + for (uint16_t j = i; j < m; j++) { + printf("0x%02X ", buff[j]); + if (++s % 10 == 0) printf(" "); + } + printf("\n"); + + // ASCII / symbolic view + s = 0; + for (uint16_t j = i; j < m; j++) { + uint8_t c = buff[j]; + if (c >= 32) + printf("%c ", c); + else + printf("%s ", sym[c]); + if (++s % 10 == 0) printf(" "); + } + printf("\n"); + } + printf("\n"); + } + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 O P E R A T O R 📌📌📌 (within class) + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + // Copy-Assignment (only for char sensible) + ps_ptr& operator=(const ps_ptr& other) { + if (this != &other) { + if constexpr (std::is_same_v) { + assign(other.get()); + } else { + static_assert(!std::is_same_v, "Copy assignment disabled for this type"); + } + } + return *this; + } + + ps_ptr& operator=(const T* raw_ptr) { // e.g. ps_ptr h; h = "123"; + if constexpr (std::is_same_v) { + assign(raw_ptr); + } else { + static_assert(!std::is_same_v, "Assignment from const pointer disabled for this type"); + } + return *this; + } + + ps_ptr& operator=(T* raw_ptr) { + if (mem.get() != raw_ptr) { + mem.reset(raw_ptr); + allocated_size = 0; // (raw_ptr != nullptr) ? /* Calculate size here */ : 0; + } + return *this; + } + + // Move-Assignment-Operator + ps_ptr& operator=(ps_ptr&& other) noexcept { + if (this != &other) { + if (name) { + free(name); + name = nullptr; + } + mem = std::move(other.mem); + allocated_size = other.allocated_size; + name = other.name; + other.allocated_size = 0; + other.name = nullptr; + } + return *this; + } + + T* operator->() const { return get(); } + T& operator*() const { return *get(); } + + // Safe operator[] with logging + T& operator[](std::size_t index) noexcept { + if (index >= allocated_size) { + log_e("[%s:%i] ps_ptr[]: Index %zu out of bounds (size = %zu, name = %s)", __FILE__, __LINE__, index, allocated_size, name ? name : "unnamed"); + return dummy; // Access allowed, but ineffective + } + return mem[index]; + } + + const T& operator[](std::size_t index) const noexcept { + if (index >= allocated_size) { + log_e("[%s:%i] ps_ptr[]: Index %zu out of bounds (size = %zu, name = %s)", __FILE__, __LINE__, index, allocated_size, name ? name : "unnamed"); + return dummy; + } + return mem[index]; + } + + // C++20: Spaceship-Operator — Automatically creates all comparison operators + auto operator<=>(const ps_ptr& other) const noexcept { + if constexpr (std::is_same_v) { + const char* s1 = get(); + const char* s2 = other.get(); + int result = std::strcmp(s1 ? s1 : "", s2 ? s2 : ""); + return (result < 0) ? std::strong_ordering::less : (result > 0) ? std::strong_ordering::greater : std::strong_ordering::equal; + } else { + // for non-string types: Compare the pointer address + return mem.get() <=> other.mem.get(); + } + } + + // ps_ptr a = "Hallo"; a += " Welt"; + template + requires std::is_same_v + ps_ptr& operator+=(const char* rhs) { + append(rhs); + return *this; + } + + // ps_ptr a = "Hallo", b = " Welt"; a += b; + template + requires std::is_same_v + ps_ptr& operator+=(const ps_ptr& rhs) { + append(rhs); + return *this; + } + + // Iterator compatible accesses (make ps_ptr STL compatible) + T* begin() noexcept { return mem.get(); } + const T* begin() const noexcept { return mem.get(); } + + T* end() noexcept { return mem.get() + allocated_size; } + const T* end() const noexcept { return mem.get() + allocated_size; } + + const T* cbegin() const noexcept { return mem.get(); } + const T* cend() const noexcept { return mem.get() + allocated_size; } + + // 🔹 Optional: pointer arithmetic (syntactic only) + T* operator+(std::size_t offset) noexcept { return mem.get() + offset; } + const T* operator+(std::size_t offset) const noexcept { return mem.get() + offset; } + + void fill(const T& value) { std::fill(begin(), end(), value); } + + // Access as std::span – secure view of the data + std::span span() noexcept { return std::span(mem.get(), allocated_size); } + + std::span span() const noexcept { return std::span(mem.get(), allocated_size); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 F O R M A T 📌📌📌 (fmt lib within class) + // —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + template std::string to_string_any(const V& v) { + using Raw = std::remove_cv_t>; + using D = std::decay_t; + + // ps_ptr + if constexpr (std::is_same_v>) { + const char* str = v.c_get(); + return str ? std::string(str) : ""; + } + // Treat character arrays as text in the same way as string literals. + else if constexpr (std::is_array_v && std::is_same_v, char>) { + return std::string(v); + } + // BOOL + else if constexpr (std::is_same_v) { + return v ? "true" : "false"; + } + // FLOAT + else if constexpr (std::is_same_v || std::is_same_v) { + char buf[32]; + snprintf(buf, sizeof(buf), "%g", v); + return buf; + } + // INTEGER / ENUM + else if constexpr (std::is_integral_v || std::is_enum_v) { + return std::to_string(static_cast(v)); + } + // POINTER + else if constexpr (std::is_pointer_v) { + // char* + if constexpr (std::is_same_v || std::is_same_v) { + return v ? std::string(v) : ""; + } + // unsigned char* + else if constexpr (std::is_same_v || std::is_same_v) { + return v ? std::string(reinterpret_cast(v)) : ""; + } + + // generic pointer + else { + char buf[32]; + snprintf(buf, sizeof(buf), "%p", static_cast(v)); + return buf; + } + } + // fallback + else { + return v; + } + } + + void format_append(std::string& out, const char* fmt) { out += fmt; } + + template void format_append(std::string& out, const char* fmt, First&& first, Rest&&... rest) { + while (*fmt) { + + // Start eines Formatfeldes? + if (*fmt == '{') { + + // Escape {{ + if (fmt[1] == '{') { + out += '{'; + fmt += 2; + continue; + } + + // Ende suchen + const char* end = std::strchr(fmt, '}'); + + // Fehlerfall: keine schließende Klammer + if (!end) { + out += *fmt++; + continue; + } + + // Inhalt zwischen { ... } + std::string spec_str(fmt + 1, end - fmt - 1); + + format_spec fs; + + // Nur parsen wenn Inhalt existiert + // also {:02} usw. + if (!spec_str.empty()) { fs = parse_format(spec_str.c_str()); } + + // Wert formatieren + out += format_value(std::forward(first), fs); + + // Rekursiv weitermachen + format_append(out, end + 1, std::forward(rest)...); + + return; + } + + // Escape }} + if (fmt[0] == '}' && fmt[1] == '}') { + out += '}'; + fmt += 2; + continue; + } + + out += *fmt++; + } + } + + struct format_spec { + int width = 0; + int precision = -1; + char fill = ' '; + char type = 0; + bool upper = false; + bool align_right = false; + }; + + inline format_spec parse_format(const char* fmt) { + format_spec fs; + + // {:02} + if (*fmt == ':') { + ++fmt; + + // Right-aligned? + if (*fmt == '-') { + fs.align_right = true; + ++fmt; + } + + // leading zero + if (*fmt == '0') { + fs.fill = '0'; + ++fmt; + } + + // width + while (isdigit(*fmt)) { + fs.width = fs.width * 10 + (*fmt - '0'); + ++fmt; + } + + // precision + if (*fmt == '.') { + ++fmt; + fs.precision = 0; + while (isdigit(*fmt)) { + fs.precision = fs.precision * 10 + (*fmt - '0'); + ++fmt; + } + } + + // type + if (*fmt) { + fs.type = *fmt; + if (*fmt == 'X') fs.upper = true; + } + } + return fs; + } + + template std::string format_value(const V& value, const format_spec& fs) { + char buf[64]; + + // bool ist in C++ ein Integraltyp, soll hier aber als Text ausgegeben werden. + if constexpr (std::is_same_v>, bool>) { return value ? "true" : "false"; } + + // ps_ptr + if constexpr (std::is_same_v>, ps_ptr>) { + const char* str = value.c_get(); + return str ? std::string(str) : std::string(""); + } + + // CHAR - separate Behandlung vor is_integral_v + if constexpr (std::is_same_v>, char>) { + if (fs.type == 'c' || fs.type == 0) { // 'c' oder kein Specifier + buf[0] = value; + buf[1] = '\0'; + return buf; + } + } + + if constexpr (std::is_integral_v) { + // HEX + if (fs.type == 'X') { + if (fs.width > 0) { + const int safe_width = (fs.width > 30) ? 30 : fs.width; + snprintf(buf, sizeof(buf), "%0*llX", safe_width, (unsigned long long)value); + } else { + snprintf(buf, sizeof(buf), "%llX", (unsigned long long)value); + } + std::string s = buf; + apply_width(s, fs, true); + return s; + } + // HEX + if (fs.type == 'x') { + if (fs.width > 0) { + const int safe_width = (fs.width > 30) ? 30 : fs.width; + snprintf(buf, sizeof(buf), "%0*llx", safe_width, (unsigned long long)value); + } else { + snprintf(buf, sizeof(buf), "%llx", (unsigned long long)value); + } + std::string s = buf; + apply_width(s, fs, true); + return s; + } + + // Integer mit Padding + if (fs.width > 0) { + const int safe_width = (fs.width > 30) ? 30 : fs.width; + if (fs.fill == '0') { + snprintf(buf, sizeof(buf), "%0*lld", safe_width, (long long)value); + } else { + snprintf(buf, sizeof(buf), "%*lld", safe_width, (long long)value); + } + std::string s = buf; + apply_width(s, fs, true); + return s; + } + std::string s = to_string_any(value); + apply_width(s, fs, true); + return s; + } + // FLOAT + if constexpr (std::is_floating_point_v) { + if (fs.precision >= 0) { + snprintf(buf, sizeof(buf), "%.*f", fs.precision, value); + std::string s = buf; + apply_width(s, fs, true); + return s; + } + snprintf(buf, sizeof(buf), "%g", value); + std::string s = buf; + apply_width(s, fs, true); + return s; + } + + std::string s = to_string_any(value); + apply_width(s, fs, false); + return s; + } + + inline size_t count_placeholders(const char* fmt) { + size_t count = 0; + + while (*fmt) { + // escaped {{ + if (fmt[0] == '{' && fmt[1] == '{') { + fmt += 2; + continue; + } + // escaped }} + if (fmt[0] == '}' && fmt[1] == '}') { + fmt += 2; + continue; + } + + // echtes { + if (*fmt == '{') { + const char* end = std::strchr(fmt, '}'); + + if (end) { + ++count; + fmt = end + 1; + continue; + } + } + ++fmt; + } + return count; + } + + inline void apply_width(std::string& s, const format_spec& fs, bool numeric = false) { + if (fs.width <= 0) return; + + if ((int)s.size() >= fs.width) return; + size_t missing = fs.width - s.size(); + // Always fill in the numbers at the top + if (numeric) { + s.insert(s.begin(), missing, fs.fill); + return; + } + + // Strings + if (fs.align_right) { + s.insert(s.begin(), missing, fs.fill); + } else { + s.append(missing, fs.fill); + } + } +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 O P E R A T O R 📌📌📌 (witout class) +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +// ps_ptr a = "Hello "; ps_ptr b = "World"; ps_ptr c = a + b; // results in new string +template + requires std::is_same_v +ps_ptr operator+(const ps_ptr& lhs, const ps_ptr& rhs) { + ps_ptr result(lhs); + result.append(rhs); + return result; +} + +template + requires std::is_same_v +ps_ptr operator+(const ps_ptr& lhs, const char* rhs) { + ps_ptr result(lhs); + result.append(rhs); + return result; +} + +template + requires std::is_same_v +ps_ptr operator+(const char* lhs, const ps_ptr& rhs) { + ps_ptr result(lhs); + result.append(rhs); + return result; +} + +template + requires std::is_same_v +bool operator==(const ps_ptr& lhs, const ps_ptr& rhs) { + const char* a = lhs.get(); + const char* b = rhs.get(); + if (!a || !b) return a == b; // beide nullptr → true + return std::strcmp(a, b) == 0; +} + +template + requires std::is_same_v +bool operator==(const ps_ptr& lhs, const char* rhs) { + const char* a = lhs.get(); + if (!a || !rhs) return a == rhs; + return std::strcmp(a, rhs) == 0; +} + +template + requires std::is_same_v +bool operator==(const char* lhs, const ps_ptr& rhs) { + return rhs == lhs; +} + +template + requires std::is_same_v +bool operator!=(const ps_ptr& lhs, const ps_ptr& rhs) { + return !(lhs == rhs); +} + +template + requires std::is_same_v +bool operator!=(const ps_ptr& lhs, const char* rhs) { + return !(lhs == rhs); +} + +template + requires std::is_same_v +bool operator!=(const char* lhs, const ps_ptr& rhs) { + return !(lhs == rhs); +} + +template + requires std::is_same_v +bool operator<(const ps_ptr& lhs, const ps_ptr& rhs) { + const char* a = lhs.get(); + const char* b = rhs.get(); + if (!a || !b) return a < b; // nullptr kleiner als nicht-null + return std::strcmp(a, b) < 0; +} + +template + requires std::is_same_v +bool operator<(const ps_ptr& lhs, const char* rhs) { + const char* a = lhs.get(); + if (!a || !rhs) return a < rhs; + return std::strcmp(a, rhs) < 0; +} + +template + requires std::is_same_v +bool operator<(const char* lhs, const ps_ptr& rhs) { + const char* b = rhs.get(); + if (!lhs || !b) return lhs < b; + return std::strcmp(lhs, b) < 0; +} + +template + requires std::is_same_v +bool operator>(const ps_ptr& lhs, const ps_ptr& rhs) { + return rhs < lhs; +} + +template + requires std::is_same_v +bool operator>(const ps_ptr& lhs, const char* rhs) { + return rhs && (std::strcmp(lhs.get(), rhs) > 0); +} + +template + requires std::is_same_v +bool operator>(const char* lhs, const ps_ptr& rhs) { + return rhs < lhs; +} + +template + requires std::is_same_v +bool operator<=(const ps_ptr& lhs, const ps_ptr& rhs) { + return !(rhs < lhs); +} + +template + requires std::is_same_v +bool operator<=(const ps_ptr& lhs, const char* rhs) { + return !(lhs > rhs); +} + +template + requires std::is_same_v +bool operator<=(const char* lhs, const ps_ptr& rhs) { + return !(rhs < lhs); +} + +template + requires std::is_same_v +bool operator>=(const ps_ptr& lhs, const ps_ptr& rhs) { + return !(lhs < rhs); +} + +template + requires std::is_same_v +bool operator>=(const ps_ptr& lhs, const char* rhs) { + return !(lhs < rhs); +} + +template + requires std::is_same_v +bool operator>=(const char* lhs, const ps_ptr& rhs) { + return !(lhs < rhs); +} + +template + requires std::is_same_v +std::ostream& operator<<(std::ostream& os, const ps_ptr& str) { + const char* s = str.get(); + if (s) os << s; + return os; +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 S T R U C T U R E S 📌📌📌 +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +// typedef struct _hwoe{ +// bool ssl; +// ps_ptr hwoe; // host without extension +// uint16_t port; +// ps_ptrextension[100]; +// ps_ptr query_string; +// } hwoe_t; +// PS_STRUCT_FREE_MEMBERS(hwoe_t, +// ptr->hwoe.reset(); +// for(int i = 0; i< 100; i++)ptr->extension[i].reset(); +// ptr->query_string.reset(); +// ) + +// ps_struct_ptr result; +// result.alloc(); +// result->extension.copy_from(path +// ..... + +template class ps_struct_ptr { + private: + std::unique_ptr mem; + char* name = nullptr; // name member + + // Auxiliary function for setting the name + void set_name(const char* new_name) { + if (name) { + free(name); + name = nullptr; + } + if (new_name) { + std::size_t len = std::strlen(new_name) + 1; + if (psramFound()) { + name = static_cast(ps_malloc(len)); + } else { + name = static_cast(malloc(len)); + } + if (name) { + std::memcpy(name, new_name, len); + } else { + printf("OOM: failed to allocate %zu bytes for name %s\n", len, new_name); + } + } + } + + public: + ps_struct_ptr() = default; // default constructor + + explicit ps_struct_ptr(const char* name_str) { // named constructor + set_name(name_str); + } + + ~ps_struct_ptr() { // destructor + if (mem) { + log_w("Destructor called for %s: Freeing %zu bytes at %p", name ? name : "unnamed", sizeof(T), mem.get()); + } else { + log_w("Destructor called for %s: No memory to free.", name ? name : "unnamed"); + } + if (name) { + free(name); + name = nullptr; + } + } + + ps_struct_ptr(ps_struct_ptr&& other) noexcept { // Move constructor + mem = std::move(other.mem); + name = other.name; + other.name = nullptr; + } + + ps_struct_ptr& operator=(ps_struct_ptr&& other) noexcept { // Move Assignment operator + if (this != &other) { + if (name) { + free(name); + name = nullptr; + } + mem = std::move(other.mem); + name = other.name; + other.name = nullptr; + } + return *this; + } + + ps_struct_ptr(const ps_struct_ptr&) = delete; + ps_struct_ptr& operator=(const ps_struct_ptr&) = delete; + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A L L O C 📌📌📌 + void alloc(const char* name_str = nullptr) { + reset(); + if (name_str) { set_name(name_str); } + void* raw_mem = nullptr; + if (psramFound()) { + raw_mem = ps_malloc(sizeof(T)); + } else { + raw_mem = malloc(sizeof(T)); + } + if (raw_mem) { + mem.reset(new (raw_mem) T()); + } else { + printf("OOM: failed to allocate %zu bytes for %s\n", sizeof(T), name ? name : (name_str ? name_str : "unnamed")); + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A L L O C 📌📌📌 + void calloc(const char* name_str = nullptr) { + reset(); + if (name_str) { set_name(name_str); } + void* raw_mem = nullptr; + if (psramFound()) { + raw_mem = ps_calloc(1, sizeof(T)); + } else { + raw_mem = calloc(1, sizeof(T)); + } + if (raw_mem) { + mem.reset(static_cast(raw_mem)); + } else { + printf("OOM: failed to allocate %zu bytes for %s\n", sizeof(T), name ? name : (name_str ? name_str : "unnamed")); + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E S E T 📌📌📌 + void reset() { + mem.reset(); // Name is not released, remains up to the destructor + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 O P E R A T O R -> 📌📌📌 + T* operator->() { return mem.get(); } + + const T* operator->() const { return mem.get(); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 O P E R A T O R * 📌📌📌 + T& operator*() { return *mem; } + + const T& operator*() const { return *mem; } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 G E T 📌📌📌 + T* get() noexcept { return mem.get(); } + + const T* get() const noexcept { return mem.get(); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + inline void free_all_ptr_members(); // prototypes + inline void free_field(char*& field); + + void set_ptr_field(char** field, const char* text) { + if (!mem || !field) return; + if (*field) { + free(*field); + *field = nullptr; + } + if (text) { + std::size_t len = strlen(text) + 1; + char* p = nullptr; + if (psramFound()) { // Check at the runtime whether PSRAM is available + p = static_cast(ps_malloc(len)); + } else { + p = static_cast(malloc(len)); + } + if (p) { + memcpy(p, text, len); + *field = p; + } + } + } + + bool valid() const { return mem.get() != nullptr; } + std::size_t size() const { return sizeof(T); } + void clear() { reset(); } +}; + + // —————————————————————————————————————————————————————————————— + // Macro for the declaration of releasing fields for a structure + #define PS_STRUCT_FREE_MEMBERS(TYPE, ...) \ + template <> inline void ps_struct_ptr::free_all_ptr_members() { \ + auto ptr = this->get(); /* 'ptr' ist hier ein Pointer auf die Struktur TYPE */ \ + if (ptr) { /* Sicherheitsprüfung, um sicherzustellen, dass ptr gültig ist */ \ + __VA_ARGS__ \ + } \ + } + +inline void free_field(char*& field) { + if (field) { + free(field); + field = nullptr; + } +} + +// Variadic Auxiliary function +template inline void free_fields(Args&... fields) { + (free_field(fields), ...); +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// 📌📌📌 2 D A R R A Y 📌📌📌 +// +// 2D Array in PSRAM with Bounds-Check, log_e and reset() +// +// ps_array2d s_samples; // standard constructor +// s_samples.alloc(2, 1152); // mem alloc for [2][1152] +// +// int ch = 0; // exanple: channel 0 +// +// declaration of PCM1 as a pointer on the first element of the line (similar to samples [CH]) +// int32_t* pcm1; +// +// pcm1 = s_samples.get_raw_row_ptr(ch); +// +// use 'pcm1' now, as if it were an int32_t array of size 1152 +// pcm1[0] = 42; +// pcm1[1151] = 99; +// +// s_samples.reset(); +// + +template class ps_array2d { + private: + std::unique_ptr mem; + size_t rows = 0; + size_t cols = 0; + char* name = nullptr; // Neues Mitglied für den Objektnamen + + // Hilfsfunktion zum Setzen des Namens + void set_name(const char* new_name) { + if (name) { + free(name); + name = nullptr; + } + if (new_name) { + std::size_t len = std::strlen(new_name) + 1; + if (psramFound()) { + name = static_cast(ps_malloc(len)); + } else { + name = static_cast(malloc(len)); + } + if (name) { + std::memcpy(name, new_name, len); + } else { + printf("OOM: failed to allocate %zu bytes for name %s\n", len, new_name); + } + } + } + + public: + // Standardkonstruktor + ps_array2d() = default; + + // Konstruktor mit Namen + explicit ps_array2d(const char* name_str) { set_name(name_str); } + + // Destruktor + ~ps_array2d() { + if (mem) { + log_w("Destructor called for %s: Freeing %zu bytes at %p", name ? name : "unnamed", rows * cols * sizeof(T), mem.get()); + } else { + log_w("Destructor called for %s: No memory to free.", name ? name : "unnamed"); + } + if (name) { + free(name); + name = nullptr; + } + } + + // Move-Constructor + ps_array2d(ps_array2d&& other) noexcept { + mem = std::move(other.mem); + rows = other.rows; + cols = other.cols; + name = other.name; + other.rows = 0; + other.cols = 0; + other.name = nullptr; + } + + // Move-Assignment-Operator + ps_array2d& operator=(ps_array2d&& other) noexcept { + if (this != &other) { + if (name) { + free(name); + name = nullptr; + } + mem = std::move(other.mem); + rows = other.rows; + cols = other.cols; + name = other.name; + other.rows = 0; + other.cols = 0; + other.name = nullptr; + } + return *this; + } + + ps_array2d(const ps_array2d&) = delete; + ps_array2d& operator=(const ps_array2d&) = delete; + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A L L O C 📌📌📌 + void alloc(size_t r, size_t c, const char* alloc_name = nullptr, bool usePSRAM = true) { + reset(); + if (alloc_name) { set_name(alloc_name); } + rows = r; + cols = c; + size_t total_size = rows * cols * sizeof(T); + total_size = (total_size + 15) & ~15; // Align to 16 bytes + if (psramFound() && usePSRAM) { + mem.reset(static_cast(ps_malloc(total_size))); + } else { + mem.reset(static_cast(malloc(total_size))); + } + if (!mem) { + printf("OOM: failed to allocate %zu bytes for %s\n", total_size, name ? name : (alloc_name ? alloc_name : "unnamed")); + rows = 0; + cols = 0; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A L L O C 📌📌📌 + void calloc(size_t r, size_t c, const char* alloc_name = nullptr, bool usePSRAM = true) { + reset(); + if (alloc_name) { set_name(alloc_name); } + rows = r; + cols = c; + size_t total_size = rows * cols * sizeof(T); + total_size = (total_size + 15) & ~15; // Align to 16 bytes + void* raw_mem = nullptr; + if (psramFound() && usePSRAM) { + raw_mem = ps_calloc(1, total_size); + } else { + raw_mem = calloc(1, total_size); + } + if (raw_mem) { + mem.reset(static_cast(raw_mem)); + } else { + printf("OOM: failed to allocate %zu bytes for %s\n", total_size, name ? name : (alloc_name ? alloc_name : "unnamed")); + rows = 0; + cols = 0; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E S E T 📌📌📌 + void reset() { + mem.reset(); + rows = 0; + cols = 0; + // Name is not released, remains up to the destructor + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 O P E R A T O R [] 📌📌📌 + T* operator[](size_t row) { return mem.get() + row * cols; } + + const T* operator[](size_t row) const { return mem.get() + row * cols; } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 G E T 📌📌📌 + T* get() { return mem.get(); } + + const T* get() const { return mem.get(); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 V A L I D / S I Z E 📌📌📌 + bool valid() const { return mem.get() != nullptr; } + size_t get_rows() const { return rows; } + size_t get_cols() const { return cols; } +}; + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// psram_unique_ptr.hpp (Auszug mit ps_array3d) +// +// 📌📌📌 3 D A R R A Y 📌📌📌 +// +// 3D Array in PSRAM with Bounds-Check, log_e and reset() +// +// ps_array3d s_sbsample; +// s_sbsample.alloc(2, 36, 32); +// +// int ch = 0; // example of the first dimension +// int gr = 0; // example of the group index +// +// C- pointer to a 1D-Array [32] +// int32_t (*sample)[32]; +// +// // allocation using the new method get_raw_row_ptr and the appropriate reinterpret_cast +// sample = reinterpret_cast(s_sbsample.get_raw_row_ptr(ch, 18 * gr)); +// +// // use 'sample' now: +// (*sample)[0] = 10; +// +// s_sbsample.reset(); +// + +template class ps_array3d { + private: + std::unique_ptr mem; + size_t dim1 = 0; + size_t dim2 = 0; + size_t dim3 = 0; + char* name = nullptr; // Neues Mitglied für den Objektnamen + + // Hilfsfunktion zum Setzen des Namens + void set_name(const char* new_name) { + if (name) { + free(name); + name = nullptr; + } + if (new_name) { + std::size_t len = std::strlen(new_name) + 1; + if (psramFound()) { + name = static_cast(ps_malloc(len)); + } else { + name = static_cast(malloc(len)); + } + if (name) { + std::memcpy(name, new_name, len); + } else { + printf("OOM: failed to allocate %zu bytes for name %s\n", len, new_name); + } + } + } + + public: + // Standardkonstruktor + ps_array3d() = default; + + // Konstruktor mit Namen + explicit ps_array3d(const char* name_str) { set_name(name_str); } + + // Destruktor + ~ps_array3d() { + if (mem) { + log_w("Destructor called for %s: Freeing %zu bytes at %p", name ? name : "unnamed", dim1 * dim2 * dim3 * sizeof(T), mem.get()); + } else { + log_w("Destructor called for %s: No memory to free.", name ? name : "unnamed"); + } + if (name) { + free(name); + name = nullptr; + } + } + + // Move-Konstruktor + ps_array3d(ps_array3d&& other) noexcept { + mem = std::move(other.mem); + dim1 = other.dim1; + dim2 = other.dim2; + dim3 = other.dim3; + name = other.name; + other.dim1 = 0; + other.dim2 = 0; + other.dim3 = 0; + other.name = nullptr; + } + + // Move-Assignment-Operator + ps_array3d& operator=(ps_array3d&& other) noexcept { + if (this != &other) { + if (name) { + free(name); + name = nullptr; + } + mem = std::move(other.mem); + dim1 = other.dim1; + dim2 = other.dim2; + dim3 = other.dim3; + name = other.name; + other.dim1 = 0; + other.dim2 = 0; + other.dim3 = 0; + other.name = nullptr; + } + return *this; + } + + ps_array3d(const ps_array3d&) = delete; + ps_array3d& operator=(const ps_array3d&) = delete; + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 A L L O C 📌📌📌 + void alloc(size_t d1, size_t d2, size_t d3, const char* alloc_name = nullptr, bool usePSRAM = true) { + reset(); + if (alloc_name) { set_name(alloc_name); } + dim1 = d1; + dim2 = d2; + dim3 = d3; + size_t total_size = dim1 * dim2 * dim3 * sizeof(T); + total_size = (total_size + 15) & ~15; // Align to 16 bytes + if (psramFound() && usePSRAM) { + mem.reset(static_cast(ps_malloc(total_size))); + } else { + mem.reset(static_cast(malloc(total_size))); + } + if (!mem) { + printf("OOM: failed to allocate %zu bytes for %s\n", total_size, name ? name : (alloc_name ? alloc_name : "unnamed")); + dim1 = 0; + dim2 = 0; + dim3 = 0; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 C A L L O C 📌📌📌 + void calloc(size_t d1, size_t d2, size_t d3, const char* alloc_name = nullptr, bool usePSRAM = true) { + reset(); + if (alloc_name) { set_name(alloc_name); } + dim1 = d1; + dim2 = d2; + dim3 = d3; + size_t total_size = dim1 * dim2 * dim3 * sizeof(T); + total_size = (total_size + 15) & ~15; // Align to 16 bytes + void* raw_mem = nullptr; + if (psramFound() && usePSRAM) { + raw_mem = ps_calloc(1, total_size); + } else { + raw_mem = calloc(1, total_size); + } + if (raw_mem) { + mem.reset(static_cast(raw_mem)); + } else { + printf("OOM: failed to allocate %zu bytes for %s\n", total_size, name ? name : (alloc_name ? alloc_name : "unnamed")); + dim1 = 0; + dim2 = 0; + dim3 = 0; + } + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 R E S E T 📌📌📌 + void reset() { + mem.reset(); + dim1 = 0; + dim2 = 0; + dim3 = 0; + // Name wird nicht freigegeben, bleibt bis zum Destruktor erhalten + } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 O P E R A T O R [] 📌📌📌 + class Proxy { + T* ptr; + size_t cols, depth; + + public: + Proxy(T* p, size_t c, size_t d) : ptr(p), cols(c), depth(d) {} + T* operator[](size_t col) { return ptr + col * depth; } + const T* operator[](size_t col) const { return ptr + col * depth; } + }; + + Proxy operator[](size_t d1) { return Proxy(mem.get() + d1 * dim2 * dim3, dim2, dim3); } + + const Proxy operator[](size_t d1) const { return Proxy(mem.get() + d1 * dim2 * dim3, dim2, dim3); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 G E T 📌📌📌 + T* get() { return mem.get(); } + + const T* get() const { return mem.get(); } + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + // 📌📌📌 V A L I D / S I Z E 📌📌📌 + bool valid() const { return mem.get() != nullptr; } + size_t get_dim1() const { return dim1; } + size_t get_dim2() const { return dim2; } + size_t get_dim3() const { return dim3; } +}; +#endif \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/vorbis_decoder/lookup.h b/libraries/ESP32-audioI2S/src/vorbis_decoder/lookup.h new file mode 100644 index 0000000..14bc5fc --- /dev/null +++ b/libraries/ESP32-audioI2S/src/vorbis_decoder/lookup.h @@ -0,0 +1,1236 @@ + +// VORBIS DECODER lookup.h + +#include "Arduino.h" +#include "vorbis_decoder.h" + +#pragma once + +const int32_t FLOOR_fromdB_LOOKUP[256] = { + 0x000000e5, 0x000000f4, 0x00000103, 0x00000114, 0x00000126, 0x00000139, 0x0000014e, 0x00000163, 0x0000017a, + 0x00000193, 0x000001ad, 0x000001c9, 0x000001e7, 0x00000206, 0x00000228, 0x0000024c, 0x00000272, 0x0000029b, + 0x000002c6, 0x000002f4, 0x00000326, 0x0000035a, 0x00000392, 0x000003cd, 0x0000040c, 0x00000450, 0x00000497, + 0x000004e4, 0x00000535, 0x0000058c, 0x000005e8, 0x0000064a, 0x000006b3, 0x00000722, 0x00000799, 0x00000818, + 0x0000089e, 0x0000092e, 0x000009c6, 0x00000a69, 0x00000b16, 0x00000bcf, 0x00000c93, 0x00000d64, 0x00000e43, + 0x00000f30, 0x0000102d, 0x0000113a, 0x00001258, 0x0000138a, 0x000014cf, 0x00001629, 0x0000179a, 0x00001922, + 0x00001ac4, 0x00001c82, 0x00001e5c, 0x00002055, 0x0000226f, 0x000024ac, 0x0000270e, 0x00002997, 0x00002c4b, + 0x00002f2c, 0x0000323d, 0x00003581, 0x000038fb, 0x00003caf, 0x000040a0, 0x000044d3, 0x0000494c, 0x00004e10, + 0x00005323, 0x0000588a, 0x00005e4b, 0x0000646b, 0x00006af2, 0x000071e5, 0x0000794c, 0x0000812e, 0x00008993, + 0x00009283, 0x00009c09, 0x0000a62d, 0x0000b0f9, 0x0000bc79, 0x0000c8b9, 0x0000d5c4, 0x0000e3a9, 0x0000f274, + 0x00010235, 0x000112fd, 0x000124dc, 0x000137e4, 0x00014c29, 0x000161bf, 0x000178bc, 0x00019137, 0x0001ab4a, + 0x0001c70e, 0x0001e4a1, 0x0002041f, 0x000225aa, 0x00024962, 0x00026f6d, 0x000297f0, 0x0002c316, 0x0002f109, + 0x000321f9, 0x00035616, 0x00038d97, 0x0003c8b4, 0x000407a7, 0x00044ab2, 0x00049218, 0x0004de23, 0x00052f1e, + 0x0005855c, 0x0005e135, 0x00064306, 0x0006ab33, 0x00071a24, 0x0007904b, 0x00080e20, 0x00089422, 0x000922da, + 0x0009bad8, 0x000a5cb6, 0x000b091a, 0x000bc0b1, 0x000c8436, 0x000d5471, 0x000e3233, 0x000f1e5f, 0x001019e4, + 0x001125c1, 0x00124306, 0x001372d5, 0x0014b663, 0x00160ef7, 0x00177df0, 0x001904c1, 0x001aa4f9, 0x001c603d, + 0x001e384f, 0x00202f0f, 0x0022467a, 0x002480b1, 0x0026dff7, 0x002966b3, 0x002c1776, 0x002ef4fc, 0x0032022d, + 0x00354222, 0x0038b828, 0x003c67c2, 0x004054ae, 0x004482e8, 0x0048f6af, 0x004db488, 0x0052c142, 0x005821ff, + 0x005ddc33, 0x0063f5b0, 0x006a74a7, 0x00715faf, 0x0078bdce, 0x0080967f, 0x0088f1ba, 0x0091d7f9, 0x009b5247, + 0x00a56a41, 0x00b02a27, 0x00bb9ce2, 0x00c7ce12, 0x00d4ca17, 0x00e29e20, 0x00f15835, 0x0101074b, 0x0111bb4e, + 0x01238531, 0x01367704, 0x014aa402, 0x016020a7, 0x017702c3, 0x018f6190, 0x01a955cb, 0x01c4f9cf, 0x01e269a8, + 0x0201c33b, 0x0223265a, 0x0246b4ea, 0x026c9302, 0x0294e716, 0x02bfda13, 0x02ed9793, 0x031e4e09, 0x03522ee4, + 0x03896ed0, 0x03c445e2, 0x0402efd6, 0x0445ac4b, 0x048cbefc, 0x04d87013, 0x05290c67, 0x057ee5ca, 0x05da5364, + 0x063bb204, 0x06a36485, 0x0711d42b, 0x0787710e, 0x0804b299, 0x088a17ef, 0x0918287e, 0x09af747c, 0x0a50957e, + 0x0afc2f19, 0x0bb2ef7f, 0x0c759034, 0x0d44d6ca, 0x0e2195bc, 0x0f0cad0d, 0x10070b62, 0x1111aeea, 0x122da66c, + 0x135c120f, 0x149e24d9, 0x15f525b1, 0x176270e3, 0x18e7794b, 0x1a85c9ae, 0x1c3f06d1, 0x1e14f07d, 0x200963d7, + 0x221e5ccd, 0x2455f870, 0x26b2770b, 0x29363e2b, 0x2be3db5c, 0x2ebe06b6, 0x31c7a55b, 0x3503ccd4, 0x3875c5aa, + 0x3c210f44, 0x4009632b, 0x4432b8cf, 0x48a149bc, 0x4d59959e, 0x52606733, 0x57bad899, 0x5d6e593a, 0x6380b298, + 0x69f80e9a, 0x70dafda8, 0x78307d76, 0x7fffffff, +}; + +const int32_t vwin64[32] = { + 0x001f0003, 0x01168c98, 0x030333c8, 0x05dfe3a4, 0x09a49562, 0x0e45df18, 0x13b47ef2, 0x19dcf676, + 0x20a74d83, 0x27f7137c, 0x2fabb05a, 0x37a1105a, 0x3fb0ab28, 0x47b2dcd1, 0x4f807bc6, 0x56f48e70, + 0x5dedfc79, 0x64511653, 0x6a08cfff, 0x6f079328, 0x734796f4, 0x76cab7f2, 0x7999d6e8, 0x7bc3cf9f, + 0x7d5c20c1, 0x7e7961df, 0x7f33a567, 0x7fa2e1d0, 0x7fdd78a5, 0x7ff6ec6d, 0x7ffed0e9, 0x7ffffc3f, +}; + +const int32_t vwin128[64] = { + 0x0007c04d, 0x0045bb89, 0x00c18b87, 0x017ae294, 0x02714a4e, 0x03a4217a, 0x05129952, 0x06bbb24f, + 0x089e38a1, 0x0ab8c073, 0x0d09a228, 0x0f8ef6bd, 0x12469488, 0x152e0c7a, 0x1842a81c, 0x1b81686d, + 0x1ee705d9, 0x226ff15d, 0x26185705, 0x29dc21cc, 0x2db700fe, 0x31a46f08, 0x359fb9c1, 0x39a40c0c, + 0x3dac78b6, 0x41b40674, 0x45b5bcb0, 0x49acb109, 0x4d94152b, 0x516744bd, 0x5521d320, 0x58bf98a5, + 0x5c3cbef4, 0x5f95cc5d, 0x62c7add7, 0x65cfbf64, 0x68abd2ba, 0x6b5a3405, 0x6dd9acab, 0x7029840d, + 0x72497e38, 0x7439d8ac, 0x75fb4532, 0x778ee30a, 0x78f6367e, 0x7a331f1a, 0x7b47cccd, 0x7c36b416, + 0x7d028192, 0x7dae0d18, 0x7e3c4caa, 0x7eb04763, 0x7f0d08a7, 0x7f5593b7, 0x7f8cd7d5, 0x7fb5a513, + 0x7fd2a1fc, 0x7fe64212, 0x7ff2bd4c, 0x7ffa0890, 0x7ffdcf39, 0x7fff6dac, 0x7fffed01, 0x7fffffc4, +}; + +const int32_t vwin256[128] = { + 0x0001f018, 0x00117066, 0x00306e9e, 0x005ee5f1, 0x009ccf26, 0x00ea208b, 0x0146cdea, 0x01b2c87f, 0x022dfedf, + 0x02b85ced, 0x0351cbbd, 0x03fa317f, 0x04b17167, 0x05776b90, 0x064bfcdc, 0x072efedd, 0x082047b4, 0x091fa9f1, + 0x0a2cf477, 0x0b47f25d, 0x0c706ad2, 0x0da620ff, 0x0ee8d3ef, 0x10383e75, 0x11941716, 0x12fc0ff6, 0x146fd6c8, + 0x15ef14c2, 0x17796e8e, 0x190e844f, 0x1aadf196, 0x1c574d6e, 0x1e0a2a62, 0x1fc61688, 0x218a9b9c, 0x23573f12, + 0x252b823d, 0x2706e269, 0x28e8d913, 0x2ad0dc0e, 0x2cbe5dc1, 0x2eb0cd60, 0x30a79733, 0x32a224d5, 0x349fdd8b, + 0x36a02690, 0x38a2636f, 0x3aa5f65e, 0x3caa409e, 0x3eaea2df, 0x40b27da6, 0x42b531b8, 0x44b62086, 0x46b4ac99, + 0x48b03a05, 0x4aa82ed5, 0x4c9bf37d, 0x4e8af349, 0x50749ccb, 0x52586246, 0x5435ba1c, 0x560c1f31, 0x57db1152, + 0x59a21591, 0x5b60b6a3, 0x5d168535, 0x5ec31839, 0x60660d36, 0x61ff0886, 0x638db595, 0x6511c717, 0x668af734, + 0x67f907b0, 0x695bc207, 0x6ab2f787, 0x6bfe815a, 0x6d3e4090, 0x6e721e16, 0x6f9a0ab5, 0x70b5fef8, 0x71c5fb16, + 0x72ca06cd, 0x73c2313d, 0x74ae90b2, 0x758f4275, 0x76646a85, 0x772e335c, 0x77eccda0, 0x78a06fd7, 0x79495613, + 0x79e7c19c, 0x7a7bf894, 0x7b064596, 0x7b86f757, 0x7bfe6044, 0x7c6cd615, 0x7cd2b16e, 0x7d304d71, 0x7d860756, + 0x7dd43e06, 0x7e1b51ad, 0x7e5ba355, 0x7e95947e, 0x7ec986bb, 0x7ef7db4a, 0x7f20f2b9, 0x7f452c7f, 0x7f64e6a7, + 0x7f807d71, 0x7f984aff, 0x7faca700, 0x7fbde662, 0x7fcc5b04, 0x7fd85372, 0x7fe21a99, 0x7fe9f791, 0x7ff02d58, + 0x7ff4fa9e, 0x7ff89990, 0x7ffb3faa, 0x7ffd1d8b, 0x7ffe5ecc, 0x7fff29e0, 0x7fff9ff3, 0x7fffdcd2, 0x7ffff6d6, + 0x7ffffed0, 0x7ffffffc, +}; + +const int32_t vwin512[256] = { + 0x00007c06, 0x00045c32, 0x000c1c62, 0x0017bc4c, 0x00273b7a, 0x003a9955, 0x0051d51c, 0x006cede7, 0x008be2a9, + 0x00aeb22a, 0x00d55b0d, 0x00ffdbcc, 0x012e32b6, 0x01605df5, 0x01965b85, 0x01d02939, 0x020dc4ba, 0x024f2b83, + 0x02945ae6, 0x02dd5004, 0x032a07d3, 0x037a7f19, 0x03ceb26e, 0x04269e37, 0x04823eab, 0x04e18fcc, 0x05448d6d, + 0x05ab3329, 0x06157c68, 0x0683645e, 0x06f4e607, 0x0769fc25, 0x07e2a146, 0x085ecfbc, 0x08de819f, 0x0961b0cc, + 0x09e856e3, 0x0a726d46, 0x0affed1d, 0x0b90cf4c, 0x0c250c79, 0x0cbc9d0b, 0x0d577926, 0x0df598aa, 0x0e96f337, + 0x0f3b8026, 0x0fe3368f, 0x108e0d42, 0x113bfaca, 0x11ecf56b, 0x12a0f324, 0x1357e9ac, 0x1411ce70, 0x14ce9698, + 0x158e3702, 0x1650a444, 0x1715d2aa, 0x17ddb638, 0x18a842aa, 0x19756b72, 0x1a4523b9, 0x1b175e62, 0x1bec0e04, + 0x1cc324f0, 0x1d9c9532, 0x1e78508a, 0x1f564876, 0x20366e2e, 0x2118b2a2, 0x21fd0681, 0x22e35a37, 0x23cb9dee, + 0x24b5c18e, 0x25a1b4c0, 0x268f66f1, 0x277ec74e, 0x286fc4cc, 0x29624e23, 0x2a5651d7, 0x2b4bbe34, 0x2c428150, + 0x2d3a8913, 0x2e33c332, 0x2f2e1d35, 0x30298478, 0x3125e62d, 0x32232f61, 0x33214cfc, 0x34202bc2, 0x351fb85a, + 0x361fdf4f, 0x37208d10, 0x3821adf7, 0x39232e49, 0x3a24fa3c, 0x3b26fdf6, 0x3c292593, 0x3d2b5d29, 0x3e2d90c8, + 0x3f2fac7f, 0x40319c5f, 0x41334c81, 0x4234a905, 0x43359e16, 0x443617f3, 0x453602eb, 0x46354b65, 0x4733dde1, + 0x4831a6ff, 0x492e937f, 0x4a2a9045, 0x4b258a5f, 0x4c1f6f06, 0x4d182ba2, 0x4e0fadce, 0x4f05e35b, 0x4ffaba53, + 0x50ee20fd, 0x51e005e1, 0x52d057ca, 0x53bf05ca, 0x54abff3b, 0x559733c7, 0x56809365, 0x57680e62, 0x584d955d, + 0x59311952, 0x5a128b96, 0x5af1dddd, 0x5bcf023a, 0x5ca9eb27, 0x5d828b81, 0x5e58d68d, 0x5f2cbffc, 0x5ffe3be9, + 0x60cd3edf, 0x6199bdda, 0x6263ae45, 0x632b0602, 0x63efbb66, 0x64b1c53f, 0x65711ad0, 0x662db3d7, 0x66e7888d, + 0x679e91a5, 0x6852c84e, 0x69042635, 0x69b2a582, 0x6a5e40dd, 0x6b06f36c, 0x6bacb8d2, 0x6c4f8d30, 0x6cef6d26, + 0x6d8c55d4, 0x6e2644d4, 0x6ebd3840, 0x6f512ead, 0x6fe2272e, 0x7070214f, 0x70fb1d17, 0x71831b06, 0x72081c16, + 0x728a21b5, 0x73092dc8, 0x738542a6, 0x73fe631b, 0x74749261, 0x74e7d421, 0x75582c72, 0x75c59fd5, 0x76303333, + 0x7697ebdd, 0x76fccf85, 0x775ee443, 0x77be308a, 0x781abb2e, 0x78748b59, 0x78cba88e, 0x79201aa7, 0x7971e9cd, + 0x79c11e79, 0x7a0dc170, 0x7a57dbc2, 0x7a9f76c1, 0x7ae49c07, 0x7b27556b, 0x7b67ad02, 0x7ba5ad1b, 0x7be1603a, + 0x7c1ad118, 0x7c520a9e, 0x7c8717e1, 0x7cba0421, 0x7ceadac3, 0x7d19a74f, 0x7d46756e, 0x7d7150e5, 0x7d9a4592, + 0x7dc15f69, 0x7de6aa71, 0x7e0a32c0, 0x7e2c0479, 0x7e4c2bc7, 0x7e6ab4db, 0x7e87abe9, 0x7ea31d24, 0x7ebd14be, + 0x7ed59edd, 0x7eecc7a3, 0x7f029b21, 0x7f17255a, 0x7f2a723f, 0x7f3c8daa, 0x7f4d835d, 0x7f5d5f00, 0x7f6c2c1b, + 0x7f79f617, 0x7f86c83a, 0x7f92ada2, 0x7f9db146, 0x7fa7ddf3, 0x7fb13e46, 0x7fb9dcb0, 0x7fc1c36c, 0x7fc8fc83, + 0x7fcf91c7, 0x7fd58cd2, 0x7fdaf702, 0x7fdfd979, 0x7fe43d1c, 0x7fe82a8b, 0x7febaa29, 0x7feec412, 0x7ff1801c, + 0x7ff3e5d6, 0x7ff5fc86, 0x7ff7cb29, 0x7ff9586f, 0x7ffaaaba, 0x7ffbc81e, 0x7ffcb660, 0x7ffd7af3, 0x7ffe1afa, + 0x7ffe9b42, 0x7fff0047, 0x7fff4e2f, 0x7fff88c9, 0x7fffb390, 0x7fffd1a6, 0x7fffe5d7, 0x7ffff296, 0x7ffff9fd, + 0x7ffffdcd, 0x7fffff6d, 0x7fffffed, 0x7fffffff, +}; + +const int32_t vwin1024[512] = { + 0x00001f02, 0x0001170e, 0x00030724, 0x0005ef40, 0x0009cf59, 0x000ea767, 0x0014775e, 0x001b3f2e, 0x0022fec8, + 0x002bb618, 0x00356508, 0x00400b81, 0x004ba968, 0x00583ea0, 0x0065cb0a, 0x00744e84, 0x0083c8ea, 0x00943a14, + 0x00a5a1da, 0x00b80010, 0x00cb5488, 0x00df9f10, 0x00f4df76, 0x010b1584, 0x01224101, 0x013a61b2, 0x01537759, + 0x016d81b6, 0x01888087, 0x01a47385, 0x01c15a69, 0x01df34e6, 0x01fe02b1, 0x021dc377, 0x023e76e7, 0x02601ca9, + 0x0282b466, 0x02a63dc1, 0x02cab85d, 0x02f023d6, 0x03167fcb, 0x033dcbd3, 0x03660783, 0x038f3270, 0x03b94c29, + 0x03e4543a, 0x04104a2e, 0x043d2d8b, 0x046afdd5, 0x0499ba8c, 0x04c9632d, 0x04f9f734, 0x052b7615, 0x055ddf46, + 0x05913237, 0x05c56e53, 0x05fa9306, 0x06309fb6, 0x066793c5, 0x069f6e93, 0x06d82f7c, 0x0711d5d9, 0x074c60fe, + 0x0787d03d, 0x07c422e4, 0x0801583e, 0x083f6f91, 0x087e681f, 0x08be4129, 0x08fef9ea, 0x0940919a, 0x0983076d, + 0x09c65a92, 0x0a0a8a38, 0x0a4f9585, 0x0a957b9f, 0x0adc3ba7, 0x0b23d4b9, 0x0b6c45ee, 0x0bb58e5a, 0x0bffad0f, + 0x0c4aa11a, 0x0c966982, 0x0ce3054d, 0x0d30737b, 0x0d7eb308, 0x0dcdc2eb, 0x0e1da21a, 0x0e6e4f83, 0x0ebfca11, + 0x0f1210ad, 0x0f652238, 0x0fb8fd91, 0x100da192, 0x10630d11, 0x10b93ee0, 0x111035cb, 0x1167f09a, 0x11c06e13, + 0x1219acf5, 0x1273abfb, 0x12ce69db, 0x1329e54a, 0x13861cf3, 0x13e30f80, 0x1440bb97, 0x149f1fd8, 0x14fe3ade, + 0x155e0b40, 0x15be8f92, 0x161fc662, 0x1681ae38, 0x16e4459b, 0x17478b0b, 0x17ab7d03, 0x181019fb, 0x18756067, + 0x18db4eb3, 0x1941e34a, 0x19a91c92, 0x1a10f8ea, 0x1a7976af, 0x1ae29439, 0x1b4c4fda, 0x1bb6a7e2, 0x1c219a9a, + 0x1c8d2649, 0x1cf9492e, 0x1d660188, 0x1dd34d8e, 0x1e412b74, 0x1eaf996a, 0x1f1e959b, 0x1f8e1e2f, 0x1ffe3146, + 0x206ecd01, 0x20dfef78, 0x215196c2, 0x21c3c0f0, 0x22366c10, 0x22a9962a, 0x231d3d45, 0x23915f60, 0x2405fa7a, + 0x247b0c8c, 0x24f09389, 0x25668d65, 0x25dcf80c, 0x2653d167, 0x26cb175e, 0x2742c7d0, 0x27bae09e, 0x28335fa2, + 0x28ac42b3, 0x292587a5, 0x299f2c48, 0x2a192e69, 0x2a938bd1, 0x2b0e4247, 0x2b894f8d, 0x2c04b164, 0x2c806588, + 0x2cfc69b2, 0x2d78bb9a, 0x2df558f4, 0x2e723f6f, 0x2eef6cbb, 0x2f6cde83, 0x2fea9270, 0x30688627, 0x30e6b74e, + 0x31652385, 0x31e3c86b, 0x3262a39e, 0x32e1b2b8, 0x3360f352, 0x33e06303, 0x345fff5e, 0x34dfc5f8, 0x355fb462, + 0x35dfc82a, 0x365ffee0, 0x36e0560f, 0x3760cb43, 0x37e15c05, 0x386205df, 0x38e2c657, 0x39639af5, 0x39e4813e, + 0x3a6576b6, 0x3ae678e3, 0x3b678547, 0x3be89965, 0x3c69b2c1, 0x3ceacedc, 0x3d6beb37, 0x3ded0557, 0x3e6e1abb, + 0x3eef28e6, 0x3f702d5a, 0x3ff1259a, 0x40720f29, 0x40f2e789, 0x4173ac3f, 0x41f45ad0, 0x4274f0c2, 0x42f56b9a, + 0x4375c8e0, 0x43f6061d, 0x447620db, 0x44f616a5, 0x4575e509, 0x45f58994, 0x467501d6, 0x46f44b62, 0x477363cb, + 0x47f248a6, 0x4870f78e, 0x48ef6e1a, 0x496da9e8, 0x49eba897, 0x4a6967c8, 0x4ae6e521, 0x4b641e47, 0x4be110e5, + 0x4c5dbaa7, 0x4cda193f, 0x4d562a5f, 0x4dd1ebbd, 0x4e4d5b15, 0x4ec87623, 0x4f433aa9, 0x4fbda66c, 0x5037b734, + 0x50b16acf, 0x512abf0e, 0x51a3b1c5, 0x521c40ce, 0x52946a06, 0x530c2b50, 0x53838292, 0x53fa6db8, 0x5470eab3, + 0x54e6f776, 0x555c91fc, 0x55d1b844, 0x56466851, 0x56baa02f, 0x572e5deb, 0x57a19f98, 0x58146352, 0x5886a737, + 0x58f8696d, 0x5969a81c, 0x59da6177, 0x5a4a93b4, 0x5aba3d0f, 0x5b295bcb, 0x5b97ee30, 0x5c05f28d, 0x5c736738, + 0x5ce04a8d, 0x5d4c9aed, 0x5db856c1, 0x5e237c78, 0x5e8e0a89, 0x5ef7ff6f, 0x5f6159b0, 0x5fca17d4, 0x6032386e, + 0x6099ba15, 0x61009b69, 0x6166db11, 0x61cc77b9, 0x62317017, 0x6295c2e7, 0x62f96eec, 0x635c72f1, 0x63becdc8, + 0x64207e4b, 0x6481835a, 0x64e1dbde, 0x654186c8, 0x65a0830e, 0x65fecfb1, 0x665c6bb7, 0x66b95630, 0x67158e30, + 0x677112d7, 0x67cbe34b, 0x6825feb9, 0x687f6456, 0x68d81361, 0x69300b1e, 0x69874ada, 0x69ddd1ea, 0x6a339fab, + 0x6a88b382, 0x6add0cdb, 0x6b30ab2a, 0x6b838dec, 0x6bd5b4a6, 0x6c271ee2, 0x6c77cc36, 0x6cc7bc3d, 0x6d16ee9b, + 0x6d6562fb, 0x6db31911, 0x6e001099, 0x6e4c4955, 0x6e97c311, 0x6ee27d9f, 0x6f2c78d9, 0x6f75b4a2, 0x6fbe30e4, + 0x7005ed91, 0x704ceaa1, 0x70932816, 0x70d8a5f8, 0x711d6457, 0x7161634b, 0x71a4a2f3, 0x71e72375, 0x7228e500, + 0x7269e7c8, 0x72aa2c0a, 0x72e9b209, 0x73287a12, 0x73668476, 0x73a3d18f, 0x73e061bc, 0x741c3566, 0x74574cfa, + 0x7491a8ee, 0x74cb49be, 0x75042fec, 0x753c5c03, 0x7573ce92, 0x75aa882f, 0x75e08979, 0x7615d313, 0x764a65a7, + 0x767e41e5, 0x76b16884, 0x76e3da40, 0x771597dc, 0x7746a221, 0x7776f9dd, 0x77a69fe6, 0x77d59514, 0x7803da49, + 0x7831706a, 0x785e5861, 0x788a9320, 0x78b6219c, 0x78e104cf, 0x790b3dbb, 0x7934cd64, 0x795db4d5, 0x7985f51d, + 0x79ad8f50, 0x79d48486, 0x79fad5de, 0x7a208478, 0x7a45917b, 0x7a69fe12, 0x7a8dcb6c, 0x7ab0fabb, 0x7ad38d36, + 0x7af5841a, 0x7b16e0a3, 0x7b37a416, 0x7b57cfb8, 0x7b7764d4, 0x7b9664b6, 0x7bb4d0b0, 0x7bd2aa14, 0x7beff23b, + 0x7c0caa7f, 0x7c28d43c, 0x7c4470d2, 0x7c5f81a5, 0x7c7a081a, 0x7c940598, 0x7cad7b8b, 0x7cc66b5e, 0x7cded680, + 0x7cf6be64, 0x7d0e247b, 0x7d250a3c, 0x7d3b711c, 0x7d515a95, 0x7d66c822, 0x7d7bbb3c, 0x7d903563, 0x7da43814, + 0x7db7c4d0, 0x7dcadd16, 0x7ddd826a, 0x7defb64d, 0x7e017a44, 0x7e12cfd3, 0x7e23b87f, 0x7e3435cc, 0x7e444943, + 0x7e53f467, 0x7e6338c0, 0x7e7217d5, 0x7e80932b, 0x7e8eac49, 0x7e9c64b7, 0x7ea9bdf8, 0x7eb6b994, 0x7ec35910, + 0x7ecf9def, 0x7edb89b6, 0x7ee71de9, 0x7ef25c09, 0x7efd4598, 0x7f07dc16, 0x7f122103, 0x7f1c15dc, 0x7f25bc1f, + 0x7f2f1547, 0x7f3822cd, 0x7f40e62b, 0x7f4960d6, 0x7f519443, 0x7f5981e7, 0x7f612b31, 0x7f689191, 0x7f6fb674, + 0x7f769b45, 0x7f7d416c, 0x7f83aa51, 0x7f89d757, 0x7f8fc9df, 0x7f958348, 0x7f9b04ef, 0x7fa0502e, 0x7fa56659, + 0x7faa48c7, 0x7faef8c7, 0x7fb377a7, 0x7fb7c6b3, 0x7fbbe732, 0x7fbfda67, 0x7fc3a196, 0x7fc73dfa, 0x7fcab0ce, + 0x7fcdfb4a, 0x7fd11ea0, 0x7fd41c00, 0x7fd6f496, 0x7fd9a989, 0x7fdc3bff, 0x7fdead17, 0x7fe0fdee, 0x7fe32f9d, + 0x7fe54337, 0x7fe739ce, 0x7fe9146c, 0x7fead41b, 0x7fec79dd, 0x7fee06b2, 0x7fef7b94, 0x7ff0d97b, 0x7ff22158, + 0x7ff35417, 0x7ff472a3, 0x7ff57de0, 0x7ff676ac, 0x7ff75de3, 0x7ff8345a, 0x7ff8fae4, 0x7ff9b24b, 0x7ffa5b58, + 0x7ffaf6cd, 0x7ffb8568, 0x7ffc07e2, 0x7ffc7eed, 0x7ffceb38, 0x7ffd4d6d, 0x7ffda631, 0x7ffdf621, 0x7ffe3dd8, + 0x7ffe7dea, 0x7ffeb6e7, 0x7ffee959, 0x7fff15c4, 0x7fff3ca9, 0x7fff5e80, 0x7fff7bc0, 0x7fff94d6, 0x7fffaa2d, + 0x7fffbc29, 0x7fffcb29, 0x7fffd786, 0x7fffe195, 0x7fffe9a3, 0x7fffeffa, 0x7ffff4dd, 0x7ffff889, 0x7ffffb37, + 0x7ffffd1a, 0x7ffffe5d, 0x7fffff29, 0x7fffffa0, 0x7fffffdd, 0x7ffffff7, 0x7fffffff, 0x7fffffff, +}; + +const int32_t vwin2048[1024] = { + 0x000007c0, 0x000045c4, 0x0000c1ca, 0x00017bd3, 0x000273de, 0x0003a9eb, 0x00051df9, 0x0006d007, 0x0008c014, + 0x000aee1e, 0x000d5a25, 0x00100428, 0x0012ec23, 0x00161216, 0x001975fe, 0x001d17da, 0x0020f7a8, 0x00251564, + 0x0029710c, 0x002e0a9e, 0x0032e217, 0x0037f773, 0x003d4ab0, 0x0042dbca, 0x0048aabe, 0x004eb788, 0x00550224, + 0x005b8a8f, 0x006250c5, 0x006954c1, 0x0070967e, 0x007815f9, 0x007fd32c, 0x0087ce13, 0x009006a9, 0x00987ce9, + 0x00a130cc, 0x00aa224f, 0x00b3516b, 0x00bcbe1a, 0x00c66856, 0x00d0501a, 0x00da755f, 0x00e4d81f, 0x00ef7853, + 0x00fa55f4, 0x010570fc, 0x0110c963, 0x011c5f22, 0x01283232, 0x0134428c, 0x01409027, 0x014d1afb, 0x0159e302, + 0x0166e831, 0x01742a82, 0x0181a9ec, 0x018f6665, 0x019d5fe5, 0x01ab9663, 0x01ba09d6, 0x01c8ba34, 0x01d7a775, + 0x01e6d18d, 0x01f63873, 0x0205dc1e, 0x0215bc82, 0x0225d997, 0x02363350, 0x0246c9a3, 0x02579c86, 0x0268abed, + 0x0279f7cc, 0x028b801a, 0x029d44c9, 0x02af45ce, 0x02c1831d, 0x02d3fcaa, 0x02e6b269, 0x02f9a44c, 0x030cd248, + 0x03203c4f, 0x0333e255, 0x0347c44b, 0x035be225, 0x03703bd5, 0x0384d14d, 0x0399a280, 0x03aeaf5e, 0x03c3f7d9, + 0x03d97be4, 0x03ef3b6e, 0x0405366a, 0x041b6cc8, 0x0431de78, 0x04488b6c, 0x045f7393, 0x047696dd, 0x048df53b, + 0x04a58e9b, 0x04bd62ee, 0x04d57223, 0x04edbc28, 0x050640ed, 0x051f0060, 0x0537fa70, 0x05512f0a, 0x056a9e1e, + 0x05844798, 0x059e2b67, 0x05b84978, 0x05d2a1b8, 0x05ed3414, 0x06080079, 0x062306d3, 0x063e470f, 0x0659c119, + 0x067574dd, 0x06916247, 0x06ad8941, 0x06c9e9b8, 0x06e68397, 0x070356c8, 0x07206336, 0x073da8cb, 0x075b2772, + 0x0778df15, 0x0796cf9c, 0x07b4f8f3, 0x07d35b01, 0x07f1f5b1, 0x0810c8eb, 0x082fd497, 0x084f189e, 0x086e94e9, + 0x088e495e, 0x08ae35e6, 0x08ce5a68, 0x08eeb6cc, 0x090f4af8, 0x093016d3, 0x09511a44, 0x09725530, 0x0993c77f, + 0x09b57115, 0x09d751d8, 0x09f969ae, 0x0a1bb87c, 0x0a3e3e26, 0x0a60fa91, 0x0a83eda2, 0x0aa7173c, 0x0aca7743, + 0x0aee0d9b, 0x0b11da28, 0x0b35dccc, 0x0b5a156a, 0x0b7e83e5, 0x0ba3281f, 0x0bc801fa, 0x0bed1159, 0x0c12561c, + 0x0c37d025, 0x0c5d7f55, 0x0c83638d, 0x0ca97cae, 0x0ccfca97, 0x0cf64d2a, 0x0d1d0444, 0x0d43efc7, 0x0d6b0f92, + 0x0d926383, 0x0db9eb79, 0x0de1a752, 0x0e0996ee, 0x0e31ba29, 0x0e5a10e2, 0x0e829af6, 0x0eab5841, 0x0ed448a2, + 0x0efd6bf4, 0x0f26c214, 0x0f504ade, 0x0f7a062e, 0x0fa3f3df, 0x0fce13cd, 0x0ff865d2, 0x1022e9ca, 0x104d9f8e, + 0x107886f9, 0x10a39fe5, 0x10ceea2c, 0x10fa65a6, 0x1126122d, 0x1151ef9a, 0x117dfdc5, 0x11aa3c87, 0x11d6abb6, + 0x12034b2c, 0x12301ac0, 0x125d1a48, 0x128a499b, 0x12b7a891, 0x12e536ff, 0x1312f4bb, 0x1340e19c, 0x136efd75, + 0x139d481e, 0x13cbc16a, 0x13fa692f, 0x14293f40, 0x14584371, 0x14877597, 0x14b6d585, 0x14e6630d, 0x15161e04, + 0x1546063b, 0x15761b85, 0x15a65db3, 0x15d6cc99, 0x16076806, 0x16382fcd, 0x166923bf, 0x169a43ab, 0x16cb8f62, + 0x16fd06b5, 0x172ea973, 0x1760776b, 0x1792706e, 0x17c49449, 0x17f6e2cb, 0x18295bc3, 0x185bfeff, 0x188ecc4c, + 0x18c1c379, 0x18f4e452, 0x19282ea4, 0x195ba23c, 0x198f3ee6, 0x19c3046e, 0x19f6f2a1, 0x1a2b094a, 0x1a5f4833, + 0x1a93af28, 0x1ac83df3, 0x1afcf460, 0x1b31d237, 0x1b66d744, 0x1b9c034e, 0x1bd15621, 0x1c06cf84, 0x1c3c6f40, + 0x1c72351e, 0x1ca820e6, 0x1cde3260, 0x1d146953, 0x1d4ac587, 0x1d8146c3, 0x1db7eccd, 0x1deeb76c, 0x1e25a667, + 0x1e5cb982, 0x1e93f085, 0x1ecb4b33, 0x1f02c953, 0x1f3a6aaa, 0x1f722efb, 0x1faa160b, 0x1fe21f9e, 0x201a4b79, + 0x2052995d, 0x208b0910, 0x20c39a53, 0x20fc4cea, 0x21352097, 0x216e151c, 0x21a72a3a, 0x21e05fb5, 0x2219b54d, + 0x22532ac3, 0x228cbfd8, 0x22c6744d, 0x230047e2, 0x233a3a58, 0x23744b6d, 0x23ae7ae3, 0x23e8c878, 0x242333ec, + 0x245dbcfd, 0x24986369, 0x24d326f1, 0x250e0750, 0x25490446, 0x25841d90, 0x25bf52ec, 0x25faa417, 0x263610cd, + 0x267198cc, 0x26ad3bcf, 0x26e8f994, 0x2724d1d6, 0x2760c451, 0x279cd0c0, 0x27d8f6e0, 0x2815366a, 0x28518f1b, + 0x288e00ac, 0x28ca8ad8, 0x29072d5a, 0x2943e7eb, 0x2980ba45, 0x29bda422, 0x29faa53c, 0x2a37bd4a, 0x2a74ec07, + 0x2ab2312b, 0x2aef8c6f, 0x2b2cfd8b, 0x2b6a8437, 0x2ba8202c, 0x2be5d120, 0x2c2396cc, 0x2c6170e7, 0x2c9f5f29, + 0x2cdd6147, 0x2d1b76fa, 0x2d599ff7, 0x2d97dbf5, 0x2dd62aab, 0x2e148bcf, 0x2e52ff16, 0x2e918436, 0x2ed01ae5, + 0x2f0ec2d9, 0x2f4d7bc6, 0x2f8c4562, 0x2fcb1f62, 0x300a097a, 0x3049035f, 0x30880cc6, 0x30c72563, 0x31064cea, + 0x3145830f, 0x3184c786, 0x31c41a03, 0x32037a39, 0x3242e7dc, 0x3282629f, 0x32c1ea36, 0x33017e53, 0x33411ea9, + 0x3380caec, 0x33c082ce, 0x34004602, 0x34401439, 0x347fed27, 0x34bfd07e, 0x34ffbdf0, 0x353fb52e, 0x357fb5ec, + 0x35bfbfda, 0x35ffd2aa, 0x363fee0f, 0x368011b9, 0x36c03d5a, 0x370070a4, 0x3740ab48, 0x3780ecf7, 0x37c13562, + 0x3801843a, 0x3841d931, 0x388233f7, 0x38c2943d, 0x3902f9b4, 0x3943640d, 0x3983d2f8, 0x39c44626, 0x3a04bd48, + 0x3a45380e, 0x3a85b62a, 0x3ac6374a, 0x3b06bb20, 0x3b47415c, 0x3b87c9ae, 0x3bc853c7, 0x3c08df57, 0x3c496c0f, + 0x3c89f99f, 0x3cca87b6, 0x3d0b1605, 0x3d4ba43d, 0x3d8c320e, 0x3dccbf27, 0x3e0d4b3a, 0x3e4dd5f6, 0x3e8e5f0c, + 0x3ecee62b, 0x3f0f6b05, 0x3f4fed49, 0x3f906ca8, 0x3fd0e8d2, 0x40116177, 0x4051d648, 0x409246f6, 0x40d2b330, + 0x41131aa7, 0x41537d0c, 0x4193da10, 0x41d43162, 0x421482b4, 0x4254cdb7, 0x4295121b, 0x42d54f91, 0x431585ca, + 0x4355b477, 0x4395db49, 0x43d5f9f1, 0x44161021, 0x44561d8a, 0x449621dd, 0x44d61ccc, 0x45160e08, 0x4555f544, + 0x4595d230, 0x45d5a47f, 0x46156be3, 0x4655280e, 0x4694d8b2, 0x46d47d82, 0x4714162f, 0x4753a26d, 0x479321ef, + 0x47d29466, 0x4811f987, 0x48515104, 0x48909a91, 0x48cfd5e1, 0x490f02a7, 0x494e2098, 0x498d2f66, 0x49cc2ec7, + 0x4a0b1e6f, 0x4a49fe11, 0x4a88cd62, 0x4ac78c18, 0x4b0639e6, 0x4b44d683, 0x4b8361a2, 0x4bc1dafa, 0x4c004241, + 0x4c3e972c, 0x4c7cd970, 0x4cbb08c5, 0x4cf924e1, 0x4d372d7a, 0x4d752247, 0x4db30300, 0x4df0cf5a, 0x4e2e870f, + 0x4e6c29d6, 0x4ea9b766, 0x4ee72f78, 0x4f2491c4, 0x4f61de02, 0x4f9f13ec, 0x4fdc333b, 0x50193ba8, 0x50562ced, + 0x509306c3, 0x50cfc8e5, 0x510c730d, 0x514904f6, 0x51857e5a, 0x51c1def5, 0x51fe2682, 0x523a54bc, 0x52766961, + 0x52b2642c, 0x52ee44d9, 0x532a0b26, 0x5365b6d0, 0x53a14793, 0x53dcbd2f, 0x54181760, 0x545355e5, 0x548e787d, + 0x54c97ee6, 0x550468e1, 0x553f362c, 0x5579e687, 0x55b479b3, 0x55eeef70, 0x5629477f, 0x566381a1, 0x569d9d97, + 0x56d79b24, 0x57117a0a, 0x574b3a0a, 0x5784dae9, 0x57be5c69, 0x57f7be4d, 0x5831005a, 0x586a2254, 0x58a32400, + 0x58dc0522, 0x5914c57f, 0x594d64de, 0x5985e305, 0x59be3fba, 0x59f67ac3, 0x5a2e93e9, 0x5a668af2, 0x5a9e5fa6, + 0x5ad611ce, 0x5b0da133, 0x5b450d9d, 0x5b7c56d7, 0x5bb37ca9, 0x5bea7ede, 0x5c215d41, 0x5c58179d, 0x5c8eadbe, + 0x5cc51f6f, 0x5cfb6c7c, 0x5d3194b2, 0x5d6797de, 0x5d9d75cf, 0x5dd32e51, 0x5e08c132, 0x5e3e2e43, 0x5e737551, + 0x5ea8962d, 0x5edd90a7, 0x5f12648e, 0x5f4711b4, 0x5f7b97ea, 0x5faff702, 0x5fe42ece, 0x60183f20, 0x604c27cc, + 0x607fe8a6, 0x60b38180, 0x60e6f22f, 0x611a3a89, 0x614d5a62, 0x61805190, 0x61b31fe9, 0x61e5c545, 0x62184179, + 0x624a945d, 0x627cbdca, 0x62aebd98, 0x62e0939f, 0x63123fba, 0x6343c1c1, 0x6375198f, 0x63a646ff, 0x63d749ec, + 0x64082232, 0x6438cfad, 0x64695238, 0x6499a9b3, 0x64c9d5f9, 0x64f9d6ea, 0x6529ac63, 0x65595643, 0x6588d46a, + 0x65b826b8, 0x65e74d0e, 0x6616474b, 0x66451552, 0x6673b704, 0x66a22c44, 0x66d074f4, 0x66fe90f8, 0x672c8033, + 0x675a428a, 0x6787d7e1, 0x67b5401f, 0x67e27b27, 0x680f88e1, 0x683c6934, 0x68691c05, 0x6895a13e, 0x68c1f8c7, + 0x68ee2287, 0x691a1e68, 0x6945ec54, 0x69718c35, 0x699cfdf5, 0x69c8417f, 0x69f356c0, 0x6a1e3da3, 0x6a48f615, + 0x6a738002, 0x6a9ddb5a, 0x6ac80808, 0x6af205fd, 0x6b1bd526, 0x6b457575, 0x6b6ee6d8, 0x6b982940, 0x6bc13c9f, + 0x6bea20e5, 0x6c12d605, 0x6c3b5bf1, 0x6c63b29c, 0x6c8bd9fb, 0x6cb3d200, 0x6cdb9aa0, 0x6d0333d0, 0x6d2a9d86, + 0x6d51d7b7, 0x6d78e25a, 0x6d9fbd67, 0x6dc668d3, 0x6dece498, 0x6e1330ad, 0x6e394d0c, 0x6e5f39ae, 0x6e84f68d, + 0x6eaa83a2, 0x6ecfe0ea, 0x6ef50e5e, 0x6f1a0bfc, 0x6f3ed9bf, 0x6f6377a4, 0x6f87e5a8, 0x6fac23c9, 0x6fd03206, + 0x6ff4105c, 0x7017becc, 0x703b3d54, 0x705e8bf5, 0x7081aaaf, 0x70a49984, 0x70c75874, 0x70e9e783, 0x710c46b2, + 0x712e7605, 0x7150757f, 0x71724523, 0x7193e4f6, 0x71b554fd, 0x71d6953e, 0x71f7a5bd, 0x72188681, 0x72393792, + 0x7259b8f5, 0x727a0ab2, 0x729a2cd2, 0x72ba1f5d, 0x72d9e25c, 0x72f975d8, 0x7318d9db, 0x73380e6f, 0x735713a0, + 0x7375e978, 0x73949003, 0x73b3074c, 0x73d14f61, 0x73ef684f, 0x740d5222, 0x742b0ce9, 0x744898b1, 0x7465f589, + 0x74832381, 0x74a022a8, 0x74bcf30e, 0x74d994c3, 0x74f607d8, 0x75124c5f, 0x752e6268, 0x754a4a05, 0x7566034b, + 0x75818e4a, 0x759ceb16, 0x75b819c4, 0x75d31a66, 0x75eded12, 0x760891dc, 0x762308da, 0x763d5221, 0x76576dc8, + 0x76715be4, 0x768b1c8c, 0x76a4afd9, 0x76be15e0, 0x76d74ebb, 0x76f05a82, 0x7709394d, 0x7721eb35, 0x773a7054, + 0x7752c8c4, 0x776af49f, 0x7782f400, 0x779ac701, 0x77b26dbd, 0x77c9e851, 0x77e136d8, 0x77f8596f, 0x780f5032, + 0x78261b3f, 0x783cbab2, 0x78532eaa, 0x78697745, 0x787f94a0, 0x789586db, 0x78ab4e15, 0x78c0ea6d, 0x78d65c03, + 0x78eba2f7, 0x7900bf68, 0x7915b179, 0x792a7949, 0x793f16fb, 0x79538aaf, 0x7967d488, 0x797bf4a8, 0x798feb31, + 0x79a3b846, 0x79b75c0a, 0x79cad6a1, 0x79de282e, 0x79f150d5, 0x7a0450bb, 0x7a172803, 0x7a29d6d3, 0x7a3c5d50, + 0x7a4ebb9f, 0x7a60f1e6, 0x7a73004a, 0x7a84e6f2, 0x7a96a604, 0x7aa83da7, 0x7ab9ae01, 0x7acaf73a, 0x7adc1979, + 0x7aed14e6, 0x7afde9a8, 0x7b0e97e8, 0x7b1f1fcd, 0x7b2f8182, 0x7b3fbd2d, 0x7b4fd2f9, 0x7b5fc30f, 0x7b6f8d98, + 0x7b7f32bd, 0x7b8eb2a9, 0x7b9e0d85, 0x7bad437d, 0x7bbc54b9, 0x7bcb4166, 0x7bda09ae, 0x7be8adbc, 0x7bf72dbc, + 0x7c0589d8, 0x7c13c23d, 0x7c21d716, 0x7c2fc88f, 0x7c3d96d5, 0x7c4b4214, 0x7c58ca78, 0x7c66302d, 0x7c737362, + 0x7c809443, 0x7c8d92fc, 0x7c9a6fbc, 0x7ca72aaf, 0x7cb3c404, 0x7cc03be8, 0x7ccc9288, 0x7cd8c814, 0x7ce4dcb9, + 0x7cf0d0a5, 0x7cfca406, 0x7d08570c, 0x7d13e9e5, 0x7d1f5cbf, 0x7d2aafca, 0x7d35e335, 0x7d40f72e, 0x7d4bebe4, + 0x7d56c188, 0x7d617848, 0x7d6c1054, 0x7d7689db, 0x7d80e50e, 0x7d8b221b, 0x7d954133, 0x7d9f4286, 0x7da92643, + 0x7db2ec9b, 0x7dbc95bd, 0x7dc621da, 0x7dcf9123, 0x7dd8e3c6, 0x7de219f6, 0x7deb33e2, 0x7df431ba, 0x7dfd13af, + 0x7e05d9f2, 0x7e0e84b4, 0x7e171424, 0x7e1f8874, 0x7e27e1d4, 0x7e302074, 0x7e384487, 0x7e404e3c, 0x7e483dc4, + 0x7e501350, 0x7e57cf11, 0x7e5f7138, 0x7e66f9f4, 0x7e6e6979, 0x7e75bff5, 0x7e7cfd9a, 0x7e842298, 0x7e8b2f22, + 0x7e922366, 0x7e98ff97, 0x7e9fc3e4, 0x7ea6707f, 0x7ead0598, 0x7eb38360, 0x7eb9ea07, 0x7ec039bf, 0x7ec672b7, + 0x7ecc9521, 0x7ed2a12c, 0x7ed8970a, 0x7ede76ea, 0x7ee440fd, 0x7ee9f573, 0x7eef947d, 0x7ef51e4b, 0x7efa930d, + 0x7efff2f2, 0x7f053e2b, 0x7f0a74e8, 0x7f0f9758, 0x7f14a5ac, 0x7f19a013, 0x7f1e86bc, 0x7f2359d8, 0x7f281995, + 0x7f2cc623, 0x7f315fb1, 0x7f35e66e, 0x7f3a5a8a, 0x7f3ebc33, 0x7f430b98, 0x7f4748e7, 0x7f4b7450, 0x7f4f8e01, + 0x7f539629, 0x7f578cf5, 0x7f5b7293, 0x7f5f4732, 0x7f630b00, 0x7f66be2b, 0x7f6a60df, 0x7f6df34b, 0x7f71759b, + 0x7f74e7fe, 0x7f784aa0, 0x7f7b9daf, 0x7f7ee156, 0x7f8215c3, 0x7f853b22, 0x7f88519f, 0x7f8b5967, 0x7f8e52a6, + 0x7f913d87, 0x7f941a36, 0x7f96e8df, 0x7f99a9ad, 0x7f9c5ccb, 0x7f9f0265, 0x7fa19aa5, 0x7fa425b5, 0x7fa6a3c1, + 0x7fa914f3, 0x7fab7974, 0x7fadd16f, 0x7fb01d0d, 0x7fb25c78, 0x7fb48fd9, 0x7fb6b75a, 0x7fb8d323, 0x7fbae35d, + 0x7fbce831, 0x7fbee1c7, 0x7fc0d047, 0x7fc2b3d9, 0x7fc48ca5, 0x7fc65ad3, 0x7fc81e88, 0x7fc9d7ee, 0x7fcb872a, + 0x7fcd2c63, 0x7fcec7bf, 0x7fd05966, 0x7fd1e17c, 0x7fd36027, 0x7fd4d58d, 0x7fd641d3, 0x7fd7a51e, 0x7fd8ff94, + 0x7fda5157, 0x7fdb9a8e, 0x7fdcdb5b, 0x7fde13e2, 0x7fdf4448, 0x7fe06caf, 0x7fe18d3b, 0x7fe2a60e, 0x7fe3b74b, + 0x7fe4c114, 0x7fe5c38b, 0x7fe6bed2, 0x7fe7b30a, 0x7fe8a055, 0x7fe986d4, 0x7fea66a7, 0x7feb3ff0, 0x7fec12cd, + 0x7fecdf5f, 0x7feda5c5, 0x7fee6620, 0x7fef208d, 0x7fefd52c, 0x7ff0841c, 0x7ff12d7a, 0x7ff1d164, 0x7ff26ff9, + 0x7ff30955, 0x7ff39d96, 0x7ff42cd9, 0x7ff4b739, 0x7ff53cd4, 0x7ff5bdc5, 0x7ff63a28, 0x7ff6b217, 0x7ff725af, + 0x7ff7950a, 0x7ff80043, 0x7ff86773, 0x7ff8cab4, 0x7ff92a21, 0x7ff985d1, 0x7ff9dddf, 0x7ffa3262, 0x7ffa8374, + 0x7ffad12c, 0x7ffb1ba1, 0x7ffb62ec, 0x7ffba723, 0x7ffbe85c, 0x7ffc26b0, 0x7ffc6233, 0x7ffc9afb, 0x7ffcd11e, + 0x7ffd04b1, 0x7ffd35c9, 0x7ffd647b, 0x7ffd90da, 0x7ffdbafa, 0x7ffde2f0, 0x7ffe08ce, 0x7ffe2ca7, 0x7ffe4e8e, + 0x7ffe6e95, 0x7ffe8cce, 0x7ffea94a, 0x7ffec41b, 0x7ffedd52, 0x7ffef4ff, 0x7fff0b33, 0x7fff1ffd, 0x7fff336e, + 0x7fff4593, 0x7fff567d, 0x7fff663a, 0x7fff74d8, 0x7fff8265, 0x7fff8eee, 0x7fff9a81, 0x7fffa52b, 0x7fffaef8, + 0x7fffb7f5, 0x7fffc02d, 0x7fffc7ab, 0x7fffce7c, 0x7fffd4a9, 0x7fffda3e, 0x7fffdf44, 0x7fffe3c6, 0x7fffe7cc, + 0x7fffeb60, 0x7fffee8a, 0x7ffff153, 0x7ffff3c4, 0x7ffff5e3, 0x7ffff7b8, 0x7ffff94b, 0x7ffffaa1, 0x7ffffbc1, + 0x7ffffcb2, 0x7ffffd78, 0x7ffffe19, 0x7ffffe9a, 0x7ffffeff, 0x7fffff4e, 0x7fffff89, 0x7fffffb3, 0x7fffffd2, + 0x7fffffe6, 0x7ffffff3, 0x7ffffffa, 0x7ffffffe, 0x7fffffff, 0x7fffffff, 0x7fffffff, +}; + +const int32_t vwin4096[2048] = { + 0x000001f0, 0x00001171, 0x00003072, 0x00005ef5, 0x00009cf8, 0x0000ea7c, 0x00014780, 0x0001b405, 0x0002300b, + 0x0002bb91, 0x00035698, 0x0004011e, 0x0004bb25, 0x000584ac, 0x00065db3, 0x0007463a, 0x00083e41, 0x000945c7, + 0x000a5ccc, 0x000b8350, 0x000cb954, 0x000dfed7, 0x000f53d8, 0x0010b857, 0x00122c55, 0x0013afd1, 0x001542ca, + 0x0016e541, 0x00189735, 0x001a58a7, 0x001c2995, 0x001e09ff, 0x001ff9e6, 0x0021f948, 0x00240826, 0x00262680, + 0x00285454, 0x002a91a3, 0x002cde6c, 0x002f3aaf, 0x0031a66b, 0x003421a0, 0x0036ac4f, 0x00394675, 0x003bf014, + 0x003ea92a, 0x004171b7, 0x004449bb, 0x00473135, 0x004a2824, 0x004d2e8a, 0x00504463, 0x005369b2, 0x00569e74, + 0x0059e2aa, 0x005d3652, 0x0060996d, 0x00640bf9, 0x00678df7, 0x006b1f66, 0x006ec045, 0x00727093, 0x00763051, + 0x0079ff7d, 0x007dde16, 0x0081cc1d, 0x0085c991, 0x0089d671, 0x008df2bc, 0x00921e71, 0x00965991, 0x009aa41a, + 0x009efe0c, 0x00a36766, 0x00a7e028, 0x00ac6850, 0x00b0ffde, 0x00b5a6d1, 0x00ba5d28, 0x00bf22e4, 0x00c3f802, + 0x00c8dc83, 0x00cdd065, 0x00d2d3a8, 0x00d7e64a, 0x00dd084c, 0x00e239ac, 0x00e77a69, 0x00ecca83, 0x00f229f9, + 0x00f798ca, 0x00fd16f5, 0x0102a479, 0x01084155, 0x010ded89, 0x0113a913, 0x011973f3, 0x011f4e27, 0x012537af, + 0x012b308a, 0x013138b7, 0x01375035, 0x013d7702, 0x0143ad1f, 0x0149f289, 0x01504741, 0x0156ab44, 0x015d1e92, + 0x0163a12a, 0x016a330b, 0x0170d433, 0x017784a3, 0x017e4458, 0x01851351, 0x018bf18e, 0x0192df0d, 0x0199dbcd, + 0x01a0e7cd, 0x01a8030c, 0x01af2d89, 0x01b66743, 0x01bdb038, 0x01c50867, 0x01cc6fd0, 0x01d3e670, 0x01db6c47, + 0x01e30153, 0x01eaa593, 0x01f25907, 0x01fa1bac, 0x0201ed81, 0x0209ce86, 0x0211beb8, 0x0219be17, 0x0221cca2, + 0x0229ea56, 0x02321733, 0x023a5337, 0x02429e60, 0x024af8af, 0x02536220, 0x025bdab3, 0x02646267, 0x026cf93a, + 0x02759f2a, 0x027e5436, 0x0287185d, 0x028feb9d, 0x0298cdf4, 0x02a1bf62, 0x02aabfe5, 0x02b3cf7b, 0x02bcee23, + 0x02c61bdb, 0x02cf58a2, 0x02d8a475, 0x02e1ff55, 0x02eb693e, 0x02f4e230, 0x02fe6a29, 0x03080127, 0x0311a729, + 0x031b5c2d, 0x03252031, 0x032ef334, 0x0338d534, 0x0342c630, 0x034cc625, 0x0356d512, 0x0360f2f6, 0x036b1fce, + 0x03755b99, 0x037fa655, 0x038a0001, 0x0394689a, 0x039ee020, 0x03a9668f, 0x03b3fbe6, 0x03bea024, 0x03c95347, + 0x03d4154d, 0x03dee633, 0x03e9c5f9, 0x03f4b49b, 0x03ffb219, 0x040abe71, 0x0415d9a0, 0x042103a5, 0x042c3c7d, + 0x04378428, 0x0442daa2, 0x044e3fea, 0x0459b3fd, 0x046536db, 0x0470c880, 0x047c68eb, 0x0488181a, 0x0493d60b, + 0x049fa2bc, 0x04ab7e2a, 0x04b76854, 0x04c36137, 0x04cf68d1, 0x04db7f21, 0x04e7a424, 0x04f3d7d8, 0x05001a3b, + 0x050c6b4a, 0x0518cb04, 0x05253966, 0x0531b66e, 0x053e421a, 0x054adc68, 0x05578555, 0x05643cdf, 0x05710304, + 0x057dd7c1, 0x058abb15, 0x0597acfd, 0x05a4ad76, 0x05b1bc7f, 0x05beda14, 0x05cc0635, 0x05d940dd, 0x05e68a0b, + 0x05f3e1bd, 0x060147f0, 0x060ebca1, 0x061c3fcf, 0x0629d176, 0x06377194, 0x06452027, 0x0652dd2c, 0x0660a8a2, + 0x066e8284, 0x067c6ad1, 0x068a6186, 0x069866a1, 0x06a67a1e, 0x06b49bfc, 0x06c2cc38, 0x06d10acf, 0x06df57bf, + 0x06edb304, 0x06fc1c9d, 0x070a9487, 0x07191abe, 0x0727af40, 0x0736520b, 0x0745031c, 0x0753c270, 0x07629004, + 0x07716bd6, 0x078055e2, 0x078f4e26, 0x079e549f, 0x07ad694b, 0x07bc8c26, 0x07cbbd2e, 0x07dafc5f, 0x07ea49b7, + 0x07f9a533, 0x08090ed1, 0x0818868c, 0x08280c62, 0x0837a051, 0x08474255, 0x0856f26b, 0x0866b091, 0x08767cc3, + 0x088656fe, 0x08963f3f, 0x08a63584, 0x08b639c8, 0x08c64c0a, 0x08d66c45, 0x08e69a77, 0x08f6d69d, 0x090720b3, + 0x091778b7, 0x0927dea5, 0x0938527a, 0x0948d433, 0x095963cc, 0x096a0143, 0x097aac94, 0x098b65bb, 0x099c2cb6, + 0x09ad0182, 0x09bde41a, 0x09ced47d, 0x09dfd2a5, 0x09f0de90, 0x0a01f83b, 0x0a131fa3, 0x0a2454c3, 0x0a359798, + 0x0a46e820, 0x0a584656, 0x0a69b237, 0x0a7b2bc0, 0x0a8cb2ec, 0x0a9e47ba, 0x0aafea24, 0x0ac19a29, 0x0ad357c3, + 0x0ae522ef, 0x0af6fbab, 0x0b08e1f1, 0x0b1ad5c0, 0x0b2cd712, 0x0b3ee5e5, 0x0b510234, 0x0b632bfd, 0x0b75633b, + 0x0b87a7eb, 0x0b99fa08, 0x0bac5990, 0x0bbec67e, 0x0bd140cf, 0x0be3c87e, 0x0bf65d89, 0x0c08ffeb, 0x0c1bafa1, + 0x0c2e6ca6, 0x0c4136f6, 0x0c540e8f, 0x0c66f36c, 0x0c79e588, 0x0c8ce4e1, 0x0c9ff172, 0x0cb30b37, 0x0cc6322c, + 0x0cd9664d, 0x0ceca797, 0x0cfff605, 0x0d135193, 0x0d26ba3d, 0x0d3a2fff, 0x0d4db2d5, 0x0d6142ba, 0x0d74dfac, + 0x0d8889a5, 0x0d9c40a1, 0x0db0049d, 0x0dc3d593, 0x0dd7b380, 0x0deb9e60, 0x0dff962f, 0x0e139ae7, 0x0e27ac85, + 0x0e3bcb05, 0x0e4ff662, 0x0e642e98, 0x0e7873a2, 0x0e8cc57d, 0x0ea12423, 0x0eb58f91, 0x0eca07c2, 0x0ede8cb1, + 0x0ef31e5b, 0x0f07bcba, 0x0f1c67cb, 0x0f311f88, 0x0f45e3ee, 0x0f5ab4f7, 0x0f6f92a0, 0x0f847ce3, 0x0f9973bc, + 0x0fae7726, 0x0fc3871e, 0x0fd8a39d, 0x0fedcca1, 0x10030223, 0x1018441f, 0x102d9291, 0x1042ed74, 0x105854c3, + 0x106dc879, 0x10834892, 0x1098d508, 0x10ae6dd8, 0x10c412fc, 0x10d9c46f, 0x10ef822d, 0x11054c30, 0x111b2274, + 0x113104f5, 0x1146f3ac, 0x115cee95, 0x1172f5ab, 0x118908e9, 0x119f284a, 0x11b553ca, 0x11cb8b62, 0x11e1cf0f, + 0x11f81ecb, 0x120e7a90, 0x1224e25a, 0x123b5624, 0x1251d5e9, 0x126861a3, 0x127ef94e, 0x12959ce3, 0x12ac4c5f, + 0x12c307bb, 0x12d9cef2, 0x12f0a200, 0x130780df, 0x131e6b8a, 0x133561fa, 0x134c642c, 0x1363721a, 0x137a8bbe, + 0x1391b113, 0x13a8e214, 0x13c01eba, 0x13d76702, 0x13eebae5, 0x14061a5e, 0x141d8567, 0x1434fbfb, 0x144c7e14, + 0x14640bae, 0x147ba4c1, 0x14934949, 0x14aaf941, 0x14c2b4a2, 0x14da7b67, 0x14f24d8a, 0x150a2b06, 0x152213d5, + 0x153a07f1, 0x15520755, 0x156a11fb, 0x158227dd, 0x159a48f5, 0x15b2753d, 0x15caacb1, 0x15e2ef49, 0x15fb3d01, + 0x161395d2, 0x162bf9b6, 0x164468a8, 0x165ce2a1, 0x1675679c, 0x168df793, 0x16a69280, 0x16bf385c, 0x16d7e922, + 0x16f0a4cc, 0x17096b54, 0x17223cb4, 0x173b18e5, 0x1753ffe2, 0x176cf1a5, 0x1785ee27, 0x179ef562, 0x17b80750, + 0x17d123eb, 0x17ea4b2d, 0x18037d10, 0x181cb98d, 0x1836009e, 0x184f523c, 0x1868ae63, 0x1882150a, 0x189b862c, + 0x18b501c4, 0x18ce87c9, 0x18e81836, 0x1901b305, 0x191b582f, 0x193507ad, 0x194ec17a, 0x1968858f, 0x198253e5, + 0x199c2c75, 0x19b60f3a, 0x19cffc2d, 0x19e9f347, 0x1a03f482, 0x1a1dffd7, 0x1a381540, 0x1a5234b5, 0x1a6c5e31, + 0x1a8691ac, 0x1aa0cf21, 0x1abb1687, 0x1ad567da, 0x1aefc311, 0x1b0a2826, 0x1b249712, 0x1b3f0fd0, 0x1b599257, + 0x1b741ea1, 0x1b8eb4a7, 0x1ba95462, 0x1bc3fdcd, 0x1bdeb0de, 0x1bf96d91, 0x1c1433dd, 0x1c2f03bc, 0x1c49dd27, + 0x1c64c017, 0x1c7fac85, 0x1c9aa269, 0x1cb5a1be, 0x1cd0aa7c, 0x1cebbc9c, 0x1d06d816, 0x1d21fce4, 0x1d3d2aff, + 0x1d586260, 0x1d73a2fe, 0x1d8eecd4, 0x1daa3fda, 0x1dc59c09, 0x1de1015a, 0x1dfc6fc5, 0x1e17e743, 0x1e3367cd, + 0x1e4ef15b, 0x1e6a83e7, 0x1e861f6a, 0x1ea1c3da, 0x1ebd7133, 0x1ed9276b, 0x1ef4e67c, 0x1f10ae5e, 0x1f2c7f0a, + 0x1f485879, 0x1f643aa2, 0x1f80257f, 0x1f9c1908, 0x1fb81536, 0x1fd41a00, 0x1ff02761, 0x200c3d4f, 0x20285bc3, + 0x204482b7, 0x2060b221, 0x207ce9fb, 0x20992a3e, 0x20b572e0, 0x20d1c3dc, 0x20ee1d28, 0x210a7ebe, 0x2126e895, + 0x21435aa6, 0x215fd4ea, 0x217c5757, 0x2198e1e8, 0x21b57493, 0x21d20f51, 0x21eeb21b, 0x220b5ce7, 0x22280fb0, + 0x2244ca6c, 0x22618d13, 0x227e579f, 0x229b2a06, 0x22b80442, 0x22d4e649, 0x22f1d015, 0x230ec19d, 0x232bbad9, + 0x2348bbc1, 0x2365c44c, 0x2382d474, 0x239fec30, 0x23bd0b78, 0x23da3244, 0x23f7608b, 0x24149646, 0x2431d36c, + 0x244f17f5, 0x246c63da, 0x2489b711, 0x24a71193, 0x24c47358, 0x24e1dc57, 0x24ff4c88, 0x251cc3e2, 0x253a425e, + 0x2557c7f4, 0x2575549a, 0x2592e848, 0x25b082f7, 0x25ce249e, 0x25ebcd34, 0x26097cb2, 0x2627330e, 0x2644f040, + 0x2662b441, 0x26807f07, 0x269e5089, 0x26bc28c1, 0x26da07a4, 0x26f7ed2b, 0x2715d94d, 0x2733cc02, 0x2751c540, + 0x276fc500, 0x278dcb39, 0x27abd7e2, 0x27c9eaf3, 0x27e80463, 0x28062429, 0x28244a3e, 0x28427697, 0x2860a92d, + 0x287ee1f7, 0x289d20eb, 0x28bb6603, 0x28d9b134, 0x28f80275, 0x291659c0, 0x2934b709, 0x29531a49, 0x29718378, + 0x298ff28b, 0x29ae677b, 0x29cce23e, 0x29eb62cb, 0x2a09e91b, 0x2a287523, 0x2a4706dc, 0x2a659e3c, 0x2a843b39, + 0x2aa2ddcd, 0x2ac185ec, 0x2ae0338f, 0x2afee6ad, 0x2b1d9f3c, 0x2b3c5d33, 0x2b5b208b, 0x2b79e939, 0x2b98b734, + 0x2bb78a74, 0x2bd662ef, 0x2bf5409d, 0x2c142374, 0x2c330b6b, 0x2c51f87a, 0x2c70ea97, 0x2c8fe1b9, 0x2caeddd6, + 0x2ccddee7, 0x2cece4e1, 0x2d0befbb, 0x2d2aff6d, 0x2d4a13ec, 0x2d692d31, 0x2d884b32, 0x2da76de4, 0x2dc69540, + 0x2de5c13d, 0x2e04f1d0, 0x2e2426f0, 0x2e436095, 0x2e629eb4, 0x2e81e146, 0x2ea1283f, 0x2ec07398, 0x2edfc347, + 0x2eff1742, 0x2f1e6f80, 0x2f3dcbf8, 0x2f5d2ca0, 0x2f7c916f, 0x2f9bfa5c, 0x2fbb675d, 0x2fdad869, 0x2ffa4d76, + 0x3019c67b, 0x3039436f, 0x3058c448, 0x307848fc, 0x3097d183, 0x30b75dd3, 0x30d6ede2, 0x30f681a6, 0x31161917, + 0x3135b42b, 0x315552d8, 0x3174f514, 0x31949ad7, 0x31b44417, 0x31d3f0ca, 0x31f3a0e6, 0x32135462, 0x32330b35, + 0x3252c555, 0x327282b7, 0x32924354, 0x32b20720, 0x32d1ce13, 0x32f19823, 0x33116546, 0x33313573, 0x3351089f, + 0x3370dec2, 0x3390b7d1, 0x33b093c3, 0x33d0728f, 0x33f05429, 0x3410388a, 0x34301fa7, 0x34500977, 0x346ff5ef, + 0x348fe506, 0x34afd6b3, 0x34cfcaeb, 0x34efc1a5, 0x350fbad7, 0x352fb678, 0x354fb47d, 0x356fb4dd, 0x358fb78e, + 0x35afbc86, 0x35cfc3bc, 0x35efcd25, 0x360fd8b8, 0x362fe66c, 0x364ff636, 0x3670080c, 0x36901be5, 0x36b031b7, + 0x36d04978, 0x36f0631e, 0x37107ea0, 0x37309bf3, 0x3750bb0e, 0x3770dbe6, 0x3790fe73, 0x37b122aa, 0x37d14881, + 0x37f16fee, 0x381198e8, 0x3831c365, 0x3851ef5a, 0x38721cbe, 0x38924b87, 0x38b27bac, 0x38d2ad21, 0x38f2dfde, + 0x391313d8, 0x39334906, 0x39537f5d, 0x3973b6d4, 0x3993ef60, 0x39b428f9, 0x39d46393, 0x39f49f25, 0x3a14dba6, + 0x3a35190a, 0x3a555748, 0x3a759657, 0x3a95d62c, 0x3ab616be, 0x3ad65801, 0x3af699ed, 0x3b16dc78, 0x3b371f97, + 0x3b576341, 0x3b77a76c, 0x3b97ec0d, 0x3bb8311b, 0x3bd8768b, 0x3bf8bc55, 0x3c19026d, 0x3c3948ca, 0x3c598f62, + 0x3c79d62b, 0x3c9a1d1b, 0x3cba6428, 0x3cdaab48, 0x3cfaf271, 0x3d1b3999, 0x3d3b80b6, 0x3d5bc7be, 0x3d7c0ea8, + 0x3d9c5569, 0x3dbc9bf7, 0x3ddce248, 0x3dfd2852, 0x3e1d6e0c, 0x3e3db36c, 0x3e5df866, 0x3e7e3cf2, 0x3e9e8106, + 0x3ebec497, 0x3edf079b, 0x3eff4a09, 0x3f1f8bd7, 0x3f3fccfa, 0x3f600d69, 0x3f804d1a, 0x3fa08c02, 0x3fc0ca19, + 0x3fe10753, 0x400143a7, 0x40217f0a, 0x4041b974, 0x4061f2da, 0x40822b32, 0x40a26272, 0x40c29891, 0x40e2cd83, + 0x41030140, 0x412333bd, 0x414364f1, 0x416394d2, 0x4183c355, 0x41a3f070, 0x41c41c1b, 0x41e4464a, 0x42046ef4, + 0x42249610, 0x4244bb92, 0x4264df72, 0x428501a5, 0x42a52222, 0x42c540de, 0x42e55dd0, 0x430578ed, 0x4325922d, + 0x4345a985, 0x4365beeb, 0x4385d255, 0x43a5e3ba, 0x43c5f30f, 0x43e6004b, 0x44060b65, 0x44261451, 0x44461b07, + 0x44661f7c, 0x448621a7, 0x44a6217d, 0x44c61ef6, 0x44e61a07, 0x450612a6, 0x452608ca, 0x4545fc69, 0x4565ed79, + 0x4585dbf1, 0x45a5c7c6, 0x45c5b0ef, 0x45e59761, 0x46057b15, 0x46255bfe, 0x46453a15, 0x4665154f, 0x4684eda2, + 0x46a4c305, 0x46c4956e, 0x46e464d3, 0x4704312b, 0x4723fa6c, 0x4743c08d, 0x47638382, 0x47834344, 0x47a2ffc9, + 0x47c2b906, 0x47e26ef2, 0x48022183, 0x4821d0b1, 0x48417c71, 0x486124b9, 0x4880c981, 0x48a06abe, 0x48c00867, + 0x48dfa272, 0x48ff38d6, 0x491ecb8a, 0x493e5a84, 0x495de5b9, 0x497d6d22, 0x499cf0b4, 0x49bc7066, 0x49dbec2e, + 0x49fb6402, 0x4a1ad7db, 0x4a3a47ad, 0x4a59b370, 0x4a791b1a, 0x4a987ea1, 0x4ab7ddfd, 0x4ad73924, 0x4af6900c, + 0x4b15e2ad, 0x4b3530fc, 0x4b547af1, 0x4b73c082, 0x4b9301a6, 0x4bb23e53, 0x4bd17681, 0x4bf0aa25, 0x4c0fd937, + 0x4c2f03ae, 0x4c4e297f, 0x4c6d4aa3, 0x4c8c670f, 0x4cab7eba, 0x4cca919c, 0x4ce99fab, 0x4d08a8de, 0x4d27ad2c, + 0x4d46ac8b, 0x4d65a6f3, 0x4d849c5a, 0x4da38cb7, 0x4dc27802, 0x4de15e31, 0x4e003f3a, 0x4e1f1b16, 0x4e3df1ba, + 0x4e5cc31e, 0x4e7b8f3a, 0x4e9a5603, 0x4eb91771, 0x4ed7d37b, 0x4ef68a18, 0x4f153b3f, 0x4f33e6e7, 0x4f528d08, + 0x4f712d97, 0x4f8fc88e, 0x4fae5de1, 0x4fcced8a, 0x4feb777f, 0x5009fbb6, 0x50287a28, 0x5046f2cc, 0x50656598, + 0x5083d284, 0x50a23988, 0x50c09a9a, 0x50def5b1, 0x50fd4ac7, 0x511b99d0, 0x5139e2c5, 0x5158259e, 0x51766251, + 0x519498d6, 0x51b2c925, 0x51d0f334, 0x51ef16fb, 0x520d3473, 0x522b4b91, 0x52495c4e, 0x526766a2, 0x52856a83, + 0x52a367e9, 0x52c15ecd, 0x52df4f24, 0x52fd38e8, 0x531b1c10, 0x5338f892, 0x5356ce68, 0x53749d89, 0x539265eb, + 0x53b02788, 0x53cde257, 0x53eb964f, 0x54094369, 0x5426e99c, 0x544488df, 0x5462212c, 0x547fb279, 0x549d3cbe, + 0x54babff4, 0x54d83c12, 0x54f5b110, 0x55131ee7, 0x5530858d, 0x554de4fc, 0x556b3d2a, 0x55888e11, 0x55a5d7a8, + 0x55c319e7, 0x55e054c7, 0x55fd883f, 0x561ab447, 0x5637d8d8, 0x5654f5ea, 0x56720b75, 0x568f1971, 0x56ac1fd7, + 0x56c91e9e, 0x56e615c0, 0x57030534, 0x571fecf2, 0x573cccf3, 0x5759a530, 0x577675a0, 0x57933e3c, 0x57affefd, + 0x57ccb7db, 0x57e968ce, 0x580611cf, 0x5822b2d6, 0x583f4bdd, 0x585bdcdb, 0x587865c9, 0x5894e69f, 0x58b15f57, + 0x58cdcfe9, 0x58ea384e, 0x5906987d, 0x5922f071, 0x593f4022, 0x595b8788, 0x5977c69c, 0x5993fd57, 0x59b02bb2, + 0x59cc51a6, 0x59e86f2c, 0x5a04843c, 0x5a2090d0, 0x5a3c94e0, 0x5a589065, 0x5a748359, 0x5a906db4, 0x5aac4f70, + 0x5ac82884, 0x5ae3f8ec, 0x5affc09f, 0x5b1b7f97, 0x5b3735cd, 0x5b52e33a, 0x5b6e87d8, 0x5b8a239f, 0x5ba5b689, + 0x5bc1408f, 0x5bdcc1aa, 0x5bf839d5, 0x5c13a907, 0x5c2f0f3b, 0x5c4a6c6a, 0x5c65c08d, 0x5c810b9e, 0x5c9c4d97, + 0x5cb78670, 0x5cd2b623, 0x5ceddcaa, 0x5d08f9ff, 0x5d240e1b, 0x5d3f18f8, 0x5d5a1a8f, 0x5d7512da, 0x5d9001d3, + 0x5daae773, 0x5dc5c3b5, 0x5de09692, 0x5dfb6004, 0x5e162004, 0x5e30d68d, 0x5e4b8399, 0x5e662721, 0x5e80c11f, + 0x5e9b518e, 0x5eb5d867, 0x5ed055a4, 0x5eeac940, 0x5f053334, 0x5f1f937b, 0x5f39ea0f, 0x5f5436ea, 0x5f6e7a06, + 0x5f88b35d, 0x5fa2e2e9, 0x5fbd08a6, 0x5fd7248d, 0x5ff13698, 0x600b3ec2, 0x60253d05, 0x603f315b, 0x60591bc0, + 0x6072fc2d, 0x608cd29e, 0x60a69f0b, 0x60c06171, 0x60da19ca, 0x60f3c80f, 0x610d6c3d, 0x6127064d, 0x6140963a, + 0x615a1bff, 0x61739797, 0x618d08fc, 0x61a67029, 0x61bfcd1a, 0x61d91fc8, 0x61f2682f, 0x620ba64a, 0x6224da13, + 0x623e0386, 0x6257229d, 0x62703754, 0x628941a6, 0x62a2418e, 0x62bb3706, 0x62d4220a, 0x62ed0296, 0x6305d8a3, + 0x631ea42f, 0x63376533, 0x63501bab, 0x6368c793, 0x638168e5, 0x6399ff9e, 0x63b28bb8, 0x63cb0d2f, 0x63e383ff, + 0x63fbf022, 0x64145195, 0x642ca853, 0x6444f457, 0x645d359e, 0x64756c22, 0x648d97e0, 0x64a5b8d3, 0x64bdcef6, + 0x64d5da47, 0x64eddabf, 0x6505d05c, 0x651dbb19, 0x65359af2, 0x654d6fe3, 0x656539e7, 0x657cf8fb, 0x6594ad1b, + 0x65ac5643, 0x65c3f46e, 0x65db8799, 0x65f30fc0, 0x660a8ce0, 0x6621fef3, 0x663965f7, 0x6650c1e7, 0x666812c1, + 0x667f5880, 0x66969320, 0x66adc29e, 0x66c4e6f7, 0x66dc0026, 0x66f30e28, 0x670a10fa, 0x67210898, 0x6737f4ff, + 0x674ed62b, 0x6765ac19, 0x677c76c5, 0x6793362c, 0x67a9ea4b, 0x67c0931f, 0x67d730a3, 0x67edc2d6, 0x680449b3, + 0x681ac538, 0x68313562, 0x68479a2d, 0x685df396, 0x6874419b, 0x688a8438, 0x68a0bb6a, 0x68b6e72e, 0x68cd0782, + 0x68e31c63, 0x68f925cd, 0x690f23be, 0x69251633, 0x693afd29, 0x6950d89e, 0x6966a88f, 0x697c6cf8, 0x699225d9, + 0x69a7d32d, 0x69bd74f3, 0x69d30b27, 0x69e895c8, 0x69fe14d2, 0x6a138844, 0x6a28f01b, 0x6a3e4c54, 0x6a539ced, + 0x6a68e1e4, 0x6a7e1b37, 0x6a9348e3, 0x6aa86ae6, 0x6abd813d, 0x6ad28be7, 0x6ae78ae2, 0x6afc7e2b, 0x6b1165c0, + 0x6b26419f, 0x6b3b11c7, 0x6b4fd634, 0x6b648ee6, 0x6b793bda, 0x6b8ddd0e, 0x6ba27281, 0x6bb6fc31, 0x6bcb7a1b, + 0x6bdfec3e, 0x6bf45299, 0x6c08ad29, 0x6c1cfbed, 0x6c313ee4, 0x6c45760a, 0x6c59a160, 0x6c6dc0e4, 0x6c81d493, + 0x6c95dc6d, 0x6ca9d86f, 0x6cbdc899, 0x6cd1acea, 0x6ce5855f, 0x6cf951f7, 0x6d0d12b1, 0x6d20c78c, 0x6d347087, + 0x6d480da0, 0x6d5b9ed6, 0x6d6f2427, 0x6d829d94, 0x6d960b1a, 0x6da96cb9, 0x6dbcc270, 0x6dd00c3c, 0x6de34a1f, + 0x6df67c16, 0x6e09a221, 0x6e1cbc3f, 0x6e2fca6e, 0x6e42ccaf, 0x6e55c300, 0x6e68ad60, 0x6e7b8bd0, 0x6e8e5e4d, + 0x6ea124d8, 0x6eb3df70, 0x6ec68e13, 0x6ed930c3, 0x6eebc77d, 0x6efe5242, 0x6f10d111, 0x6f2343e9, 0x6f35aacb, + 0x6f4805b5, 0x6f5a54a8, 0x6f6c97a2, 0x6f7ecea4, 0x6f90f9ae, 0x6fa318be, 0x6fb52bd6, 0x6fc732f4, 0x6fd92e19, + 0x6feb1d44, 0x6ffd0076, 0x700ed7ad, 0x7020a2eb, 0x7032622f, 0x7044157a, 0x7055bcca, 0x70675821, 0x7078e77e, + 0x708a6ae2, 0x709be24c, 0x70ad4dbd, 0x70bead36, 0x70d000b5, 0x70e1483d, 0x70f283cc, 0x7103b363, 0x7114d704, + 0x7125eead, 0x7136fa60, 0x7147fa1c, 0x7158ede4, 0x7169d5b6, 0x717ab193, 0x718b817d, 0x719c4573, 0x71acfd76, + 0x71bda988, 0x71ce49a8, 0x71deddd7, 0x71ef6617, 0x71ffe267, 0x721052ca, 0x7220b73e, 0x72310fc6, 0x72415c62, + 0x72519d14, 0x7261d1db, 0x7271faba, 0x728217b1, 0x729228c0, 0x72a22dea, 0x72b22730, 0x72c21491, 0x72d1f611, + 0x72e1cbaf, 0x72f1956c, 0x7301534c, 0x7311054d, 0x7320ab72, 0x733045bc, 0x733fd42d, 0x734f56c5, 0x735ecd86, + 0x736e3872, 0x737d9789, 0x738ceacf, 0x739c3243, 0x73ab6de7, 0x73ba9dbe, 0x73c9c1c8, 0x73d8da08, 0x73e7e67f, + 0x73f6e72e, 0x7405dc17, 0x7414c53c, 0x7423a29f, 0x74327442, 0x74413a26, 0x744ff44d, 0x745ea2b9, 0x746d456c, + 0x747bdc68, 0x748a67ae, 0x7498e741, 0x74a75b23, 0x74b5c356, 0x74c41fdb, 0x74d270b6, 0x74e0b5e7, 0x74eeef71, + 0x74fd1d57, 0x750b3f9a, 0x7519563c, 0x75276140, 0x753560a8, 0x75435477, 0x75513cae, 0x755f1951, 0x756cea60, + 0x757aafdf, 0x758869d1, 0x75961837, 0x75a3bb14, 0x75b1526a, 0x75bede3c, 0x75cc5e8d, 0x75d9d35f, 0x75e73cb5, + 0x75f49a91, 0x7601ecf6, 0x760f33e6, 0x761c6f65, 0x76299f74, 0x7636c417, 0x7643dd51, 0x7650eb24, 0x765ded93, + 0x766ae4a0, 0x7677d050, 0x7684b0a4, 0x7691859f, 0x769e4f45, 0x76ab0d98, 0x76b7c09c, 0x76c46852, 0x76d104bf, + 0x76dd95e6, 0x76ea1bc9, 0x76f6966b, 0x770305d0, 0x770f69fb, 0x771bc2ef, 0x772810af, 0x7734533e, 0x77408aa0, + 0x774cb6d7, 0x7758d7e8, 0x7764edd5, 0x7770f8a2, 0x777cf852, 0x7788ece8, 0x7794d668, 0x77a0b4d5, 0x77ac8833, + 0x77b85085, 0x77c40dce, 0x77cfc013, 0x77db6756, 0x77e7039b, 0x77f294e6, 0x77fe1b3b, 0x7809969c, 0x7815070e, + 0x78206c93, 0x782bc731, 0x783716ea, 0x78425bc3, 0x784d95be, 0x7858c4e1, 0x7863e92d, 0x786f02a8, 0x787a1156, + 0x78851539, 0x78900e56, 0x789afcb1, 0x78a5e04d, 0x78b0b92f, 0x78bb875b, 0x78c64ad4, 0x78d1039e, 0x78dbb1be, + 0x78e65537, 0x78f0ee0e, 0x78fb7c46, 0x7905ffe4, 0x791078ec, 0x791ae762, 0x79254b4a, 0x792fa4a7, 0x7939f380, + 0x794437d7, 0x794e71b0, 0x7958a111, 0x7962c5fd, 0x796ce078, 0x7976f087, 0x7980f62f, 0x798af173, 0x7994e258, + 0x799ec8e2, 0x79a8a515, 0x79b276f7, 0x79bc3e8b, 0x79c5fbd6, 0x79cfaedc, 0x79d957a2, 0x79e2f62c, 0x79ec8a7f, + 0x79f6149f, 0x79ff9492, 0x7a090a5a, 0x7a1275fe, 0x7a1bd781, 0x7a252ee9, 0x7a2e7c39, 0x7a37bf77, 0x7a40f8a7, + 0x7a4a27ce, 0x7a534cf0, 0x7a5c6813, 0x7a65793b, 0x7a6e806d, 0x7a777dad, 0x7a807100, 0x7a895a6b, 0x7a9239f4, + 0x7a9b0f9e, 0x7aa3db6f, 0x7aac9d6b, 0x7ab55597, 0x7abe03f9, 0x7ac6a895, 0x7acf4370, 0x7ad7d48f, 0x7ae05bf6, + 0x7ae8d9ac, 0x7af14db5, 0x7af9b815, 0x7b0218d2, 0x7b0a6ff2, 0x7b12bd78, 0x7b1b016a, 0x7b233bce, 0x7b2b6ca7, + 0x7b3393fc, 0x7b3bb1d1, 0x7b43c62c, 0x7b4bd111, 0x7b53d286, 0x7b5bca90, 0x7b63b935, 0x7b6b9e78, 0x7b737a61, + 0x7b7b4cf3, 0x7b831634, 0x7b8ad629, 0x7b928cd8, 0x7b9a3a45, 0x7ba1de77, 0x7ba97972, 0x7bb10b3c, 0x7bb893d9, + 0x7bc01350, 0x7bc789a6, 0x7bcef6e0, 0x7bd65b03, 0x7bddb616, 0x7be5081c, 0x7bec511c, 0x7bf3911b, 0x7bfac81f, + 0x7c01f62c, 0x7c091b49, 0x7c10377b, 0x7c174ac7, 0x7c1e5532, 0x7c2556c4, 0x7c2c4f80, 0x7c333f6c, 0x7c3a268e, + 0x7c4104ec, 0x7c47da8a, 0x7c4ea76f, 0x7c556ba1, 0x7c5c2724, 0x7c62d9fe, 0x7c698435, 0x7c7025cf, 0x7c76bed0, + 0x7c7d4f40, 0x7c83d723, 0x7c8a567f, 0x7c90cd5a, 0x7c973bb9, 0x7c9da1a2, 0x7ca3ff1b, 0x7caa542a, 0x7cb0a0d3, + 0x7cb6e51e, 0x7cbd210f, 0x7cc354ac, 0x7cc97ffc, 0x7ccfa304, 0x7cd5bdc9, 0x7cdbd051, 0x7ce1daa3, 0x7ce7dcc3, + 0x7cedd6b8, 0x7cf3c888, 0x7cf9b238, 0x7cff93cf, 0x7d056d51, 0x7d0b3ec5, 0x7d110830, 0x7d16c99a, 0x7d1c8306, + 0x7d22347c, 0x7d27de00, 0x7d2d7f9a, 0x7d33194f, 0x7d38ab24, 0x7d3e351f, 0x7d43b748, 0x7d4931a2, 0x7d4ea435, + 0x7d540f06, 0x7d59721b, 0x7d5ecd7b, 0x7d64212a, 0x7d696d2f, 0x7d6eb190, 0x7d73ee53, 0x7d79237e, 0x7d7e5117, + 0x7d837723, 0x7d8895a9, 0x7d8dacae, 0x7d92bc3a, 0x7d97c451, 0x7d9cc4f9, 0x7da1be39, 0x7da6b017, 0x7dab9a99, + 0x7db07dc4, 0x7db5599e, 0x7dba2e2f, 0x7dbefb7b, 0x7dc3c189, 0x7dc8805e, 0x7dcd3802, 0x7dd1e879, 0x7dd691ca, + 0x7ddb33fb, 0x7ddfcf12, 0x7de46315, 0x7de8f00a, 0x7ded75f8, 0x7df1f4e3, 0x7df66cd3, 0x7dfaddcd, 0x7dff47d7, + 0x7e03aaf8, 0x7e080735, 0x7e0c5c95, 0x7e10ab1e, 0x7e14f2d5, 0x7e1933c1, 0x7e1d6de8, 0x7e21a150, 0x7e25cdff, + 0x7e29f3fc, 0x7e2e134c, 0x7e322bf5, 0x7e363dfd, 0x7e3a496b, 0x7e3e4e45, 0x7e424c90, 0x7e464454, 0x7e4a3595, + 0x7e4e205a, 0x7e5204aa, 0x7e55e289, 0x7e59b9ff, 0x7e5d8b12, 0x7e6155c7, 0x7e651a24, 0x7e68d831, 0x7e6c8ff2, + 0x7e70416e, 0x7e73ecac, 0x7e7791b0, 0x7e7b3082, 0x7e7ec927, 0x7e825ba6, 0x7e85e804, 0x7e896e48, 0x7e8cee77, + 0x7e906899, 0x7e93dcb2, 0x7e974aca, 0x7e9ab2e5, 0x7e9e150b, 0x7ea17141, 0x7ea4c78e, 0x7ea817f7, 0x7eab6283, + 0x7eaea737, 0x7eb1e61a, 0x7eb51f33, 0x7eb85285, 0x7ebb8019, 0x7ebea7f4, 0x7ec1ca1d, 0x7ec4e698, 0x7ec7fd6d, + 0x7ecb0ea1, 0x7ece1a3a, 0x7ed1203f, 0x7ed420b6, 0x7ed71ba4, 0x7eda110f, 0x7edd00ff, 0x7edfeb78, 0x7ee2d081, + 0x7ee5b01f, 0x7ee88a5a, 0x7eeb5f36, 0x7eee2eba, 0x7ef0f8ed, 0x7ef3bdd3, 0x7ef67d73, 0x7ef937d3, 0x7efbecf9, + 0x7efe9ceb, 0x7f0147ae, 0x7f03ed4a, 0x7f068dc4, 0x7f092922, 0x7f0bbf69, 0x7f0e50a1, 0x7f10dcce, 0x7f1363f7, + 0x7f15e622, 0x7f186355, 0x7f1adb95, 0x7f1d4ee9, 0x7f1fbd57, 0x7f2226e4, 0x7f248b96, 0x7f26eb74, 0x7f294683, + 0x7f2b9cc9, 0x7f2dee4d, 0x7f303b13, 0x7f328322, 0x7f34c680, 0x7f370533, 0x7f393f40, 0x7f3b74ad, 0x7f3da581, + 0x7f3fd1c1, 0x7f41f972, 0x7f441c9c, 0x7f463b43, 0x7f48556d, 0x7f4a6b21, 0x7f4c7c64, 0x7f4e893c, 0x7f5091ae, + 0x7f5295c1, 0x7f54957a, 0x7f5690e0, 0x7f5887f7, 0x7f5a7ac5, 0x7f5c6951, 0x7f5e53a0, 0x7f6039b8, 0x7f621b9e, + 0x7f63f958, 0x7f65d2ed, 0x7f67a861, 0x7f6979ba, 0x7f6b46ff, 0x7f6d1034, 0x7f6ed560, 0x7f709687, 0x7f7253b1, + 0x7f740ce1, 0x7f75c21f, 0x7f777370, 0x7f7920d8, 0x7f7aca5f, 0x7f7c7008, 0x7f7e11db, 0x7f7fafdd, 0x7f814a13, + 0x7f82e082, 0x7f847331, 0x7f860224, 0x7f878d62, 0x7f8914f0, 0x7f8a98d4, 0x7f8c1912, 0x7f8d95b0, 0x7f8f0eb5, + 0x7f908425, 0x7f91f605, 0x7f93645c, 0x7f94cf2f, 0x7f963683, 0x7f979a5d, 0x7f98fac4, 0x7f9a57bb, 0x7f9bb14a, + 0x7f9d0775, 0x7f9e5a41, 0x7f9fa9b4, 0x7fa0f5d3, 0x7fa23ea4, 0x7fa3842b, 0x7fa4c66f, 0x7fa60575, 0x7fa74141, + 0x7fa879d9, 0x7fa9af42, 0x7faae182, 0x7fac109e, 0x7fad3c9a, 0x7fae657d, 0x7faf8b4c, 0x7fb0ae0b, 0x7fb1cdc0, + 0x7fb2ea70, 0x7fb40420, 0x7fb51ad5, 0x7fb62e95, 0x7fb73f64, 0x7fb84d48, 0x7fb95846, 0x7fba6062, 0x7fbb65a2, + 0x7fbc680c, 0x7fbd67a3, 0x7fbe646d, 0x7fbf5e70, 0x7fc055af, 0x7fc14a31, 0x7fc23bf9, 0x7fc32b0d, 0x7fc41773, + 0x7fc5012e, 0x7fc5e844, 0x7fc6ccba, 0x7fc7ae94, 0x7fc88dd8, 0x7fc96a8a, 0x7fca44af, 0x7fcb1c4c, 0x7fcbf167, + 0x7fccc403, 0x7fcd9425, 0x7fce61d3, 0x7fcf2d11, 0x7fcff5e3, 0x7fd0bc4f, 0x7fd1805a, 0x7fd24207, 0x7fd3015c, + 0x7fd3be5d, 0x7fd47910, 0x7fd53178, 0x7fd5e79b, 0x7fd69b7c, 0x7fd74d21, 0x7fd7fc8e, 0x7fd8a9c8, 0x7fd954d4, + 0x7fd9fdb5, 0x7fdaa471, 0x7fdb490b, 0x7fdbeb89, 0x7fdc8bef, 0x7fdd2a42, 0x7fddc685, 0x7fde60be, 0x7fdef8f0, + 0x7fdf8f20, 0x7fe02353, 0x7fe0b58d, 0x7fe145d3, 0x7fe1d428, 0x7fe26091, 0x7fe2eb12, 0x7fe373b0, 0x7fe3fa6f, + 0x7fe47f53, 0x7fe50260, 0x7fe5839b, 0x7fe60308, 0x7fe680ab, 0x7fe6fc88, 0x7fe776a4, 0x7fe7ef02, 0x7fe865a7, + 0x7fe8da97, 0x7fe94dd6, 0x7fe9bf68, 0x7fea2f51, 0x7fea9d95, 0x7feb0a39, 0x7feb7540, 0x7febdeae, 0x7fec4687, + 0x7fecaccf, 0x7fed118b, 0x7fed74be, 0x7fedd66c, 0x7fee3698, 0x7fee9548, 0x7feef27e, 0x7fef4e3f, 0x7fefa88e, + 0x7ff0016f, 0x7ff058e7, 0x7ff0aef8, 0x7ff103a6, 0x7ff156f6, 0x7ff1a8eb, 0x7ff1f988, 0x7ff248d2, 0x7ff296cc, + 0x7ff2e37a, 0x7ff32edf, 0x7ff378ff, 0x7ff3c1de, 0x7ff4097e, 0x7ff44fe5, 0x7ff49515, 0x7ff4d911, 0x7ff51bde, + 0x7ff55d7f, 0x7ff59df7, 0x7ff5dd4a, 0x7ff61b7b, 0x7ff6588d, 0x7ff69485, 0x7ff6cf65, 0x7ff70930, 0x7ff741eb, + 0x7ff77998, 0x7ff7b03b, 0x7ff7e5d7, 0x7ff81a6f, 0x7ff84e06, 0x7ff880a1, 0x7ff8b241, 0x7ff8e2ea, 0x7ff912a0, + 0x7ff94165, 0x7ff96f3d, 0x7ff99c2b, 0x7ff9c831, 0x7ff9f354, 0x7ffa1d95, 0x7ffa46f9, 0x7ffa6f81, 0x7ffa9731, + 0x7ffabe0d, 0x7ffae416, 0x7ffb0951, 0x7ffb2dbf, 0x7ffb5164, 0x7ffb7442, 0x7ffb965d, 0x7ffbb7b8, 0x7ffbd854, + 0x7ffbf836, 0x7ffc175f, 0x7ffc35d3, 0x7ffc5394, 0x7ffc70a5, 0x7ffc8d09, 0x7ffca8c2, 0x7ffcc3d4, 0x7ffcde3f, + 0x7ffcf809, 0x7ffd1132, 0x7ffd29be, 0x7ffd41ae, 0x7ffd5907, 0x7ffd6fc9, 0x7ffd85f9, 0x7ffd9b97, 0x7ffdb0a7, + 0x7ffdc52b, 0x7ffdd926, 0x7ffdec99, 0x7ffdff88, 0x7ffe11f4, 0x7ffe23e0, 0x7ffe354f, 0x7ffe4642, 0x7ffe56bc, + 0x7ffe66bf, 0x7ffe764e, 0x7ffe856a, 0x7ffe9416, 0x7ffea254, 0x7ffeb026, 0x7ffebd8e, 0x7ffeca8f, 0x7ffed72a, + 0x7ffee362, 0x7ffeef38, 0x7ffefaaf, 0x7fff05c9, 0x7fff1087, 0x7fff1aec, 0x7fff24f9, 0x7fff2eb1, 0x7fff3816, + 0x7fff4128, 0x7fff49eb, 0x7fff5260, 0x7fff5a88, 0x7fff6266, 0x7fff69fc, 0x7fff714b, 0x7fff7854, 0x7fff7f1a, + 0x7fff859f, 0x7fff8be3, 0x7fff91ea, 0x7fff97b3, 0x7fff9d41, 0x7fffa296, 0x7fffa7b3, 0x7fffac99, 0x7fffb14b, + 0x7fffb5c9, 0x7fffba15, 0x7fffbe31, 0x7fffc21d, 0x7fffc5dc, 0x7fffc96f, 0x7fffccd8, 0x7fffd016, 0x7fffd32d, + 0x7fffd61c, 0x7fffd8e7, 0x7fffdb8d, 0x7fffde0f, 0x7fffe071, 0x7fffe2b1, 0x7fffe4d2, 0x7fffe6d5, 0x7fffe8bb, + 0x7fffea85, 0x7fffec34, 0x7fffedc9, 0x7fffef45, 0x7ffff0aa, 0x7ffff1f7, 0x7ffff330, 0x7ffff453, 0x7ffff562, + 0x7ffff65f, 0x7ffff749, 0x7ffff823, 0x7ffff8ec, 0x7ffff9a6, 0x7ffffa51, 0x7ffffaee, 0x7ffffb7e, 0x7ffffc02, + 0x7ffffc7a, 0x7ffffce7, 0x7ffffd4a, 0x7ffffda3, 0x7ffffdf4, 0x7ffffe3c, 0x7ffffe7c, 0x7ffffeb6, 0x7ffffee8, + 0x7fffff15, 0x7fffff3c, 0x7fffff5e, 0x7fffff7b, 0x7fffff95, 0x7fffffaa, 0x7fffffbc, 0x7fffffcb, 0x7fffffd7, + 0x7fffffe2, 0x7fffffea, 0x7ffffff0, 0x7ffffff5, 0x7ffffff9, 0x7ffffffb, 0x7ffffffd, 0x7ffffffe, 0x7fffffff, + 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, +}; + +const int32_t vwin8192[4096] = { + 0x0000007c, 0x0000045c, 0x00000c1d, 0x000017bd, 0x0000273e, 0x00003a9f, 0x000051e0, 0x00006d02, 0x00008c03, + 0x0000aee5, 0x0000d5a7, 0x00010049, 0x00012ecb, 0x0001612d, 0x00019770, 0x0001d193, 0x00020f96, 0x00025178, + 0x0002973c, 0x0002e0df, 0x00032e62, 0x00037fc5, 0x0003d509, 0x00042e2c, 0x00048b30, 0x0004ec13, 0x000550d7, + 0x0005b97a, 0x000625fe, 0x00069661, 0x00070aa4, 0x000782c8, 0x0007fecb, 0x00087eae, 0x00090271, 0x00098a14, + 0x000a1597, 0x000aa4f9, 0x000b383b, 0x000bcf5d, 0x000c6a5f, 0x000d0941, 0x000dac02, 0x000e52a3, 0x000efd23, + 0x000fab84, 0x00105dc3, 0x001113e3, 0x0011cde2, 0x00128bc0, 0x00134d7e, 0x0014131b, 0x0014dc98, 0x0015a9f4, + 0x00167b30, 0x0017504a, 0x00182945, 0x0019061e, 0x0019e6d7, 0x001acb6f, 0x001bb3e6, 0x001ca03c, 0x001d9071, + 0x001e8485, 0x001f7c79, 0x0020784b, 0x002177fc, 0x00227b8c, 0x002382fb, 0x00248e49, 0x00259d76, 0x0026b081, + 0x0027c76b, 0x0028e234, 0x002a00dc, 0x002b2361, 0x002c49c6, 0x002d7409, 0x002ea22a, 0x002fd42a, 0x00310a08, + 0x003243c5, 0x00338160, 0x0034c2d9, 0x00360830, 0x00375165, 0x00389e78, 0x0039ef6a, 0x003b4439, 0x003c9ce6, + 0x003df971, 0x003f59da, 0x0040be20, 0x00422645, 0x00439247, 0x00450226, 0x004675e3, 0x0047ed7e, 0x004968f5, + 0x004ae84b, 0x004c6b7d, 0x004df28d, 0x004f7d7a, 0x00510c44, 0x00529eeb, 0x00543570, 0x0055cfd1, 0x00576e0f, + 0x00591029, 0x005ab621, 0x005c5ff5, 0x005e0da6, 0x005fbf33, 0x0061749d, 0x00632de4, 0x0064eb06, 0x0066ac05, + 0x006870e0, 0x006a3998, 0x006c062b, 0x006dd69b, 0x006faae6, 0x0071830d, 0x00735f10, 0x00753eef, 0x007722a9, + 0x00790a3f, 0x007af5b1, 0x007ce4fe, 0x007ed826, 0x0080cf29, 0x0082ca08, 0x0084c8c2, 0x0086cb57, 0x0088d1c7, + 0x008adc11, 0x008cea37, 0x008efc37, 0x00911212, 0x00932bc7, 0x00954957, 0x00976ac2, 0x00999006, 0x009bb925, + 0x009de61e, 0x00a016f1, 0x00a24b9e, 0x00a48425, 0x00a6c086, 0x00a900c0, 0x00ab44d4, 0x00ad8cc2, 0x00afd889, + 0x00b22829, 0x00b47ba2, 0x00b6d2f5, 0x00b92e21, 0x00bb8d26, 0x00bdf004, 0x00c056ba, 0x00c2c149, 0x00c52fb1, + 0x00c7a1f1, 0x00ca180a, 0x00cc91fb, 0x00cf0fc5, 0x00d19166, 0x00d416df, 0x00d6a031, 0x00d92d5a, 0x00dbbe5b, + 0x00de5333, 0x00e0ebe3, 0x00e3886b, 0x00e628c9, 0x00e8ccff, 0x00eb750c, 0x00ee20f0, 0x00f0d0ab, 0x00f3843d, + 0x00f63ba5, 0x00f8f6e4, 0x00fbb5fa, 0x00fe78e5, 0x01013fa7, 0x01040a3f, 0x0106d8ae, 0x0109aaf2, 0x010c810c, + 0x010f5afb, 0x011238c0, 0x01151a5b, 0x0117ffcb, 0x011ae910, 0x011dd62a, 0x0120c719, 0x0123bbdd, 0x0126b476, + 0x0129b0e4, 0x012cb126, 0x012fb53c, 0x0132bd27, 0x0135c8e6, 0x0138d879, 0x013bebdf, 0x013f031a, 0x01421e28, + 0x01453d0a, 0x01485fbf, 0x014b8648, 0x014eb0a4, 0x0151ded2, 0x015510d4, 0x015846a8, 0x015b8050, 0x015ebdc9, + 0x0161ff15, 0x01654434, 0x01688d24, 0x016bd9e6, 0x016f2a7b, 0x01727ee1, 0x0175d718, 0x01793321, 0x017c92fc, + 0x017ff6a7, 0x01835e24, 0x0186c972, 0x018a3890, 0x018dab7f, 0x0191223f, 0x01949ccf, 0x01981b2f, 0x019b9d5f, + 0x019f235f, 0x01a2ad2f, 0x01a63acf, 0x01a9cc3e, 0x01ad617c, 0x01b0fa8a, 0x01b49767, 0x01b83813, 0x01bbdc8d, + 0x01bf84d6, 0x01c330ee, 0x01c6e0d4, 0x01ca9488, 0x01ce4c0b, 0x01d2075b, 0x01d5c679, 0x01d98964, 0x01dd501d, + 0x01e11aa3, 0x01e4e8f6, 0x01e8bb17, 0x01ec9104, 0x01f06abd, 0x01f44844, 0x01f82996, 0x01fc0eb5, 0x01fff7a0, + 0x0203e456, 0x0207d4d9, 0x020bc926, 0x020fc140, 0x0213bd24, 0x0217bcd4, 0x021bc04e, 0x021fc793, 0x0223d2a3, + 0x0227e17d, 0x022bf421, 0x02300a90, 0x023424c8, 0x023842ca, 0x023c6495, 0x02408a2a, 0x0244b389, 0x0248e0b0, + 0x024d11a0, 0x02514659, 0x02557eda, 0x0259bb24, 0x025dfb35, 0x02623f0f, 0x026686b1, 0x026ad21a, 0x026f214b, + 0x02737443, 0x0277cb02, 0x027c2588, 0x028083d5, 0x0284e5e9, 0x02894bc2, 0x028db562, 0x029222c8, 0x029693f4, + 0x029b08e6, 0x029f819d, 0x02a3fe19, 0x02a87e5b, 0x02ad0261, 0x02b18a2c, 0x02b615bb, 0x02baa50f, 0x02bf3827, + 0x02c3cf03, 0x02c869a3, 0x02cd0807, 0x02d1aa2d, 0x02d65017, 0x02daf9c4, 0x02dfa734, 0x02e45866, 0x02e90d5b, + 0x02edc612, 0x02f2828b, 0x02f742c6, 0x02fc06c3, 0x0300ce80, 0x030599ff, 0x030a6940, 0x030f3c40, 0x03141302, + 0x0318ed84, 0x031dcbc6, 0x0322adc8, 0x0327938a, 0x032c7d0c, 0x03316a4c, 0x03365b4d, 0x033b500c, 0x03404889, + 0x034544c6, 0x034a44c0, 0x034f4879, 0x03544ff0, 0x03595b24, 0x035e6a16, 0x03637cc5, 0x03689331, 0x036dad5a, + 0x0372cb40, 0x0377ece2, 0x037d1240, 0x03823b5a, 0x03876830, 0x038c98c1, 0x0391cd0e, 0x03970516, 0x039c40d8, + 0x03a18055, 0x03a6c38d, 0x03ac0a7f, 0x03b1552b, 0x03b6a390, 0x03bbf5af, 0x03c14b88, 0x03c6a519, 0x03cc0263, + 0x03d16366, 0x03d6c821, 0x03dc3094, 0x03e19cc0, 0x03e70ca2, 0x03ec803d, 0x03f1f78e, 0x03f77296, 0x03fcf155, + 0x040273cb, 0x0407f9f7, 0x040d83d9, 0x04131170, 0x0418a2bd, 0x041e37c0, 0x0423d077, 0x04296ce4, 0x042f0d04, + 0x0434b0da, 0x043a5863, 0x044003a0, 0x0445b290, 0x044b6534, 0x04511b8b, 0x0456d595, 0x045c9352, 0x046254c1, + 0x046819e1, 0x046de2b4, 0x0473af39, 0x04797f6e, 0x047f5355, 0x04852aec, 0x048b0635, 0x0490e52d, 0x0496c7d6, + 0x049cae2e, 0x04a29836, 0x04a885ed, 0x04ae7753, 0x04b46c68, 0x04ba652b, 0x04c0619d, 0x04c661bc, 0x04cc658a, + 0x04d26d04, 0x04d8782c, 0x04de8701, 0x04e49983, 0x04eaafb0, 0x04f0c98a, 0x04f6e710, 0x04fd0842, 0x05032d1e, + 0x050955a6, 0x050f81d8, 0x0515b1b5, 0x051be53d, 0x05221c6e, 0x05285748, 0x052e95cd, 0x0534d7fa, 0x053b1dd0, + 0x0541674e, 0x0547b475, 0x054e0544, 0x055459bb, 0x055ab1d9, 0x05610d9e, 0x05676d0a, 0x056dd01c, 0x057436d5, + 0x057aa134, 0x05810f38, 0x058780e2, 0x058df631, 0x05946f25, 0x059aebbe, 0x05a16bfa, 0x05a7efdb, 0x05ae775f, + 0x05b50287, 0x05bb9152, 0x05c223c0, 0x05c8b9d0, 0x05cf5382, 0x05d5f0d6, 0x05dc91cc, 0x05e33663, 0x05e9de9c, + 0x05f08a75, 0x05f739ee, 0x05fded07, 0x0604a3c0, 0x060b5e19, 0x06121c11, 0x0618dda8, 0x061fa2dd, 0x06266bb1, + 0x062d3822, 0x06340831, 0x063adbde, 0x0641b328, 0x06488e0e, 0x064f6c91, 0x06564eaf, 0x065d346a, 0x06641dc0, + 0x066b0ab1, 0x0671fb3d, 0x0678ef64, 0x067fe724, 0x0686e27f, 0x068de173, 0x0694e400, 0x069bea27, 0x06a2f3e6, + 0x06aa013d, 0x06b1122c, 0x06b826b3, 0x06bf3ed1, 0x06c65a86, 0x06cd79d1, 0x06d49cb3, 0x06dbc32b, 0x06e2ed38, + 0x06ea1adb, 0x06f14c13, 0x06f880df, 0x06ffb940, 0x0706f535, 0x070e34bd, 0x071577d9, 0x071cbe88, 0x072408c9, + 0x072b569d, 0x0732a802, 0x0739fcf9, 0x07415582, 0x0748b19b, 0x07501145, 0x0757747f, 0x075edb49, 0x076645a3, + 0x076db38c, 0x07752503, 0x077c9a09, 0x0784129e, 0x078b8ec0, 0x07930e70, 0x079a91ac, 0x07a21876, 0x07a9a2cc, + 0x07b130ad, 0x07b8c21b, 0x07c05714, 0x07c7ef98, 0x07cf8ba6, 0x07d72b3f, 0x07dece62, 0x07e6750e, 0x07ee1f43, + 0x07f5cd01, 0x07fd7e48, 0x08053316, 0x080ceb6d, 0x0814a74a, 0x081c66af, 0x0824299a, 0x082bf00c, 0x0833ba03, + 0x083b8780, 0x08435882, 0x084b2d09, 0x08530514, 0x085ae0a3, 0x0862bfb6, 0x086aa24c, 0x08728865, 0x087a7201, + 0x08825f1e, 0x088a4fbe, 0x089243de, 0x089a3b80, 0x08a236a2, 0x08aa3545, 0x08b23767, 0x08ba3d09, 0x08c2462a, + 0x08ca52c9, 0x08d262e7, 0x08da7682, 0x08e28d9c, 0x08eaa832, 0x08f2c645, 0x08fae7d4, 0x09030cdf, 0x090b3566, + 0x09136168, 0x091b90e5, 0x0923c3dc, 0x092bfa4d, 0x09343437, 0x093c719b, 0x0944b277, 0x094cf6cc, 0x09553e99, + 0x095d89dd, 0x0965d899, 0x096e2acb, 0x09768073, 0x097ed991, 0x09873625, 0x098f962e, 0x0997f9ac, 0x09a0609e, + 0x09a8cb04, 0x09b138dd, 0x09b9aa29, 0x09c21ee8, 0x09ca9719, 0x09d312bc, 0x09db91d0, 0x09e41456, 0x09ec9a4b, + 0x09f523b1, 0x09fdb087, 0x0a0640cc, 0x0a0ed47f, 0x0a176ba2, 0x0a200632, 0x0a28a42f, 0x0a31459a, 0x0a39ea72, + 0x0a4292b5, 0x0a4b3e65, 0x0a53ed80, 0x0a5ca006, 0x0a6555f7, 0x0a6e0f51, 0x0a76cc16, 0x0a7f8c44, 0x0a884fda, + 0x0a9116d9, 0x0a99e140, 0x0aa2af0e, 0x0aab8043, 0x0ab454df, 0x0abd2ce1, 0x0ac60849, 0x0acee716, 0x0ad7c948, + 0x0ae0aedf, 0x0ae997d9, 0x0af28437, 0x0afb73f7, 0x0b04671b, 0x0b0d5da0, 0x0b165788, 0x0b1f54d0, 0x0b285579, + 0x0b315983, 0x0b3a60ec, 0x0b436bb5, 0x0b4c79dd, 0x0b558b63, 0x0b5ea048, 0x0b67b88a, 0x0b70d429, 0x0b79f324, + 0x0b83157c, 0x0b8c3b30, 0x0b95643f, 0x0b9e90a8, 0x0ba7c06c, 0x0bb0f38a, 0x0bba2a01, 0x0bc363d1, 0x0bcca0f9, + 0x0bd5e17a, 0x0bdf2552, 0x0be86c81, 0x0bf1b706, 0x0bfb04e2, 0x0c045613, 0x0c0daa99, 0x0c170274, 0x0c205da3, + 0x0c29bc25, 0x0c331dfb, 0x0c3c8323, 0x0c45eb9e, 0x0c4f576a, 0x0c58c688, 0x0c6238f6, 0x0c6baeb5, 0x0c7527c3, + 0x0c7ea421, 0x0c8823cd, 0x0c91a6c8, 0x0c9b2d10, 0x0ca4b6a6, 0x0cae4389, 0x0cb7d3b8, 0x0cc16732, 0x0ccafdf8, + 0x0cd49809, 0x0cde3564, 0x0ce7d609, 0x0cf179f7, 0x0cfb212e, 0x0d04cbad, 0x0d0e7974, 0x0d182a83, 0x0d21ded8, + 0x0d2b9673, 0x0d355154, 0x0d3f0f7b, 0x0d48d0e6, 0x0d529595, 0x0d5c5d88, 0x0d6628be, 0x0d6ff737, 0x0d79c8f2, + 0x0d839dee, 0x0d8d762c, 0x0d9751aa, 0x0da13068, 0x0dab1266, 0x0db4f7a3, 0x0dbee01e, 0x0dc8cbd8, 0x0dd2bace, + 0x0ddcad02, 0x0de6a272, 0x0df09b1e, 0x0dfa9705, 0x0e049627, 0x0e0e9883, 0x0e189e19, 0x0e22a6e8, 0x0e2cb2f0, + 0x0e36c230, 0x0e40d4a8, 0x0e4aea56, 0x0e55033b, 0x0e5f1f56, 0x0e693ea7, 0x0e73612c, 0x0e7d86e5, 0x0e87afd3, + 0x0e91dbf3, 0x0e9c0b47, 0x0ea63dcc, 0x0eb07383, 0x0ebaac6b, 0x0ec4e883, 0x0ecf27cc, 0x0ed96a44, 0x0ee3afea, + 0x0eedf8bf, 0x0ef844c2, 0x0f0293f2, 0x0f0ce64e, 0x0f173bd6, 0x0f21948a, 0x0f2bf069, 0x0f364f72, 0x0f40b1a5, + 0x0f4b1701, 0x0f557f86, 0x0f5feb32, 0x0f6a5a07, 0x0f74cc02, 0x0f7f4124, 0x0f89b96b, 0x0f9434d8, 0x0f9eb369, + 0x0fa9351e, 0x0fb3b9f7, 0x0fbe41f3, 0x0fc8cd11, 0x0fd35b51, 0x0fddecb2, 0x0fe88134, 0x0ff318d6, 0x0ffdb397, + 0x10085177, 0x1012f275, 0x101d9691, 0x10283dca, 0x1032e81f, 0x103d9591, 0x1048461e, 0x1052f9c5, 0x105db087, + 0x10686a62, 0x10732756, 0x107de763, 0x1088aa87, 0x109370c2, 0x109e3a14, 0x10a9067c, 0x10b3d5f9, 0x10bea88b, + 0x10c97e31, 0x10d456eb, 0x10df32b8, 0x10ea1197, 0x10f4f387, 0x10ffd889, 0x110ac09b, 0x1115abbe, 0x112099ef, + 0x112b8b2f, 0x11367f7d, 0x114176d9, 0x114c7141, 0x11576eb6, 0x11626f36, 0x116d72c1, 0x11787957, 0x118382f6, + 0x118e8f9e, 0x11999f4f, 0x11a4b208, 0x11afc7c7, 0x11bae08e, 0x11c5fc5a, 0x11d11b2c, 0x11dc3d02, 0x11e761dd, + 0x11f289ba, 0x11fdb49b, 0x1208e27e, 0x12141362, 0x121f4748, 0x122a7e2d, 0x1235b812, 0x1240f4f6, 0x124c34d9, + 0x125777b9, 0x1262bd96, 0x126e0670, 0x12795245, 0x1284a115, 0x128ff2e0, 0x129b47a5, 0x12a69f63, 0x12b1fa19, + 0x12bd57c7, 0x12c8b86c, 0x12d41c08, 0x12df829a, 0x12eaec21, 0x12f6589d, 0x1301c80c, 0x130d3a6f, 0x1318afc4, + 0x1324280b, 0x132fa344, 0x133b216d, 0x1346a286, 0x1352268e, 0x135dad85, 0x1369376a, 0x1374c43c, 0x138053fb, + 0x138be6a5, 0x13977c3b, 0x13a314bc, 0x13aeb026, 0x13ba4e79, 0x13c5efb5, 0x13d193d9, 0x13dd3ae4, 0x13e8e4d6, + 0x13f491ad, 0x1400416a, 0x140bf40b, 0x1417a98f, 0x142361f7, 0x142f1d41, 0x143adb6d, 0x14469c7a, 0x14526067, + 0x145e2734, 0x1469f0df, 0x1475bd69, 0x14818cd0, 0x148d5f15, 0x14993435, 0x14a50c31, 0x14b0e708, 0x14bcc4b8, + 0x14c8a542, 0x14d488a5, 0x14e06edf, 0x14ec57f1, 0x14f843d9, 0x15043297, 0x1510242b, 0x151c1892, 0x15280fcd, + 0x153409dc, 0x154006bc, 0x154c066e, 0x155808f1, 0x15640e44, 0x15701666, 0x157c2157, 0x15882f16, 0x15943fa2, + 0x15a052fb, 0x15ac691f, 0x15b8820f, 0x15c49dc8, 0x15d0bc4c, 0x15dcdd98, 0x15e901ad, 0x15f52888, 0x1601522b, + 0x160d7e93, 0x1619adc1, 0x1625dfb3, 0x16321469, 0x163e4be2, 0x164a861d, 0x1656c31a, 0x166302d8, 0x166f4555, + 0x167b8a92, 0x1687d28e, 0x16941d47, 0x16a06abe, 0x16acbaf0, 0x16b90ddf, 0x16c56388, 0x16d1bbeb, 0x16de1708, + 0x16ea74dd, 0x16f6d56a, 0x170338ae, 0x170f9ea8, 0x171c0758, 0x172872bd, 0x1734e0d6, 0x174151a2, 0x174dc520, + 0x175a3b51, 0x1766b432, 0x17732fc4, 0x177fae05, 0x178c2ef4, 0x1798b292, 0x17a538dd, 0x17b1c1d4, 0x17be4d77, + 0x17cadbc5, 0x17d76cbc, 0x17e4005e, 0x17f096a7, 0x17fd2f98, 0x1809cb31, 0x1816696f, 0x18230a53, 0x182faddc, + 0x183c5408, 0x1848fcd8, 0x1855a849, 0x1862565d, 0x186f0711, 0x187bba64, 0x18887057, 0x189528e9, 0x18a1e418, + 0x18aea1e3, 0x18bb624b, 0x18c8254e, 0x18d4eaeb, 0x18e1b321, 0x18ee7df1, 0x18fb4b58, 0x19081b57, 0x1914edec, + 0x1921c317, 0x192e9ad6, 0x193b7529, 0x19485210, 0x19553189, 0x19621393, 0x196ef82e, 0x197bdf59, 0x1988c913, + 0x1995b55c, 0x19a2a432, 0x19af9595, 0x19bc8983, 0x19c97ffd, 0x19d67900, 0x19e3748e, 0x19f072a3, 0x19fd7341, + 0x1a0a7665, 0x1a177c10, 0x1a248440, 0x1a318ef4, 0x1a3e9c2c, 0x1a4babe7, 0x1a58be24, 0x1a65d2e2, 0x1a72ea20, + 0x1a8003de, 0x1a8d201a, 0x1a9a3ed5, 0x1aa7600c, 0x1ab483bf, 0x1ac1a9ee, 0x1aced297, 0x1adbfdba, 0x1ae92b56, + 0x1af65b69, 0x1b038df4, 0x1b10c2f5, 0x1b1dfa6b, 0x1b2b3456, 0x1b3870b5, 0x1b45af87, 0x1b52f0ca, 0x1b60347f, + 0x1b6d7aa4, 0x1b7ac339, 0x1b880e3c, 0x1b955bad, 0x1ba2ab8b, 0x1baffdd5, 0x1bbd528a, 0x1bcaa9a9, 0x1bd80332, + 0x1be55f24, 0x1bf2bd7d, 0x1c001e3d, 0x1c0d8164, 0x1c1ae6ef, 0x1c284edf, 0x1c35b932, 0x1c4325e7, 0x1c5094fe, + 0x1c5e0677, 0x1c6b7a4f, 0x1c78f086, 0x1c86691b, 0x1c93e40d, 0x1ca1615c, 0x1caee107, 0x1cbc630c, 0x1cc9e76b, + 0x1cd76e23, 0x1ce4f733, 0x1cf2829a, 0x1d001057, 0x1d0da06a, 0x1d1b32d1, 0x1d28c78c, 0x1d365e9a, 0x1d43f7f9, + 0x1d5193a9, 0x1d5f31aa, 0x1d6cd1f9, 0x1d7a7497, 0x1d881982, 0x1d95c0ba, 0x1da36a3d, 0x1db1160a, 0x1dbec422, + 0x1dcc7482, 0x1dda272b, 0x1de7dc1a, 0x1df59350, 0x1e034ccb, 0x1e11088a, 0x1e1ec68c, 0x1e2c86d1, 0x1e3a4958, + 0x1e480e20, 0x1e55d527, 0x1e639e6d, 0x1e7169f1, 0x1e7f37b2, 0x1e8d07b0, 0x1e9ad9e8, 0x1ea8ae5b, 0x1eb68507, + 0x1ec45dec, 0x1ed23908, 0x1ee0165b, 0x1eedf5e4, 0x1efbd7a1, 0x1f09bb92, 0x1f17a1b6, 0x1f258a0d, 0x1f337494, + 0x1f41614b, 0x1f4f5032, 0x1f5d4147, 0x1f6b3489, 0x1f7929f7, 0x1f872192, 0x1f951b56, 0x1fa31744, 0x1fb1155b, + 0x1fbf159a, 0x1fcd17ff, 0x1fdb1c8b, 0x1fe9233b, 0x1ff72c0f, 0x20053706, 0x20134420, 0x2021535a, 0x202f64b4, + 0x203d782e, 0x204b8dc6, 0x2059a57c, 0x2067bf4e, 0x2075db3b, 0x2083f943, 0x20921964, 0x20a03b9e, 0x20ae5fef, + 0x20bc8657, 0x20caaed5, 0x20d8d967, 0x20e7060e, 0x20f534c7, 0x21036592, 0x2111986e, 0x211fcd59, 0x212e0454, + 0x213c3d5d, 0x214a7873, 0x2158b594, 0x2166f4c1, 0x217535f8, 0x21837938, 0x2191be81, 0x21a005d0, 0x21ae4f26, + 0x21bc9a81, 0x21cae7e0, 0x21d93743, 0x21e788a8, 0x21f5dc0e, 0x22043174, 0x221288da, 0x2220e23e, 0x222f3da0, + 0x223d9afe, 0x224bfa58, 0x225a5bac, 0x2268bef9, 0x2277243f, 0x22858b7d, 0x2293f4b0, 0x22a25fda, 0x22b0ccf8, + 0x22bf3c09, 0x22cdad0d, 0x22dc2002, 0x22ea94e8, 0x22f90bbe, 0x23078482, 0x2315ff33, 0x23247bd1, 0x2332fa5b, + 0x23417acf, 0x234ffd2c, 0x235e8173, 0x236d07a0, 0x237b8fb4, 0x238a19ae, 0x2398a58c, 0x23a7334d, 0x23b5c2f1, + 0x23c45477, 0x23d2e7dd, 0x23e17d22, 0x23f01446, 0x23fead47, 0x240d4825, 0x241be4dd, 0x242a8371, 0x243923dd, + 0x2447c622, 0x24566a3e, 0x24651031, 0x2473b7f8, 0x24826194, 0x24910d03, 0x249fba44, 0x24ae6957, 0x24bd1a39, + 0x24cbccea, 0x24da816a, 0x24e937b7, 0x24f7efcf, 0x2506a9b3, 0x25156560, 0x252422d6, 0x2532e215, 0x2541a31a, + 0x255065e4, 0x255f2a74, 0x256df0c7, 0x257cb8dd, 0x258b82b4, 0x259a4e4c, 0x25a91ba4, 0x25b7eaba, 0x25c6bb8e, + 0x25d58e1e, 0x25e46269, 0x25f3386e, 0x2602102d, 0x2610e9a4, 0x261fc4d3, 0x262ea1b7, 0x263d8050, 0x264c609e, + 0x265b429e, 0x266a2650, 0x26790bb3, 0x2687f2c6, 0x2696db88, 0x26a5c5f7, 0x26b4b213, 0x26c39fda, 0x26d28f4c, + 0x26e18067, 0x26f0732b, 0x26ff6796, 0x270e5da7, 0x271d555d, 0x272c4eb7, 0x273b49b5, 0x274a4654, 0x27594495, + 0x27684475, 0x277745f4, 0x27864910, 0x27954dc9, 0x27a4541e, 0x27b35c0d, 0x27c26596, 0x27d170b7, 0x27e07d6f, + 0x27ef8bbd, 0x27fe9ba0, 0x280dad18, 0x281cc022, 0x282bd4be, 0x283aeaeb, 0x284a02a7, 0x28591bf2, 0x286836cb, + 0x28775330, 0x28867120, 0x2895909b, 0x28a4b19e, 0x28b3d42a, 0x28c2f83d, 0x28d21dd5, 0x28e144f3, 0x28f06d94, + 0x28ff97b8, 0x290ec35d, 0x291df082, 0x292d1f27, 0x293c4f4a, 0x294b80eb, 0x295ab407, 0x2969e89e, 0x29791eaf, + 0x29885639, 0x29978f3b, 0x29a6c9b3, 0x29b605a0, 0x29c54302, 0x29d481d7, 0x29e3c21e, 0x29f303d6, 0x2a0246fd, + 0x2a118b94, 0x2a20d198, 0x2a301909, 0x2a3f61e6, 0x2a4eac2c, 0x2a5df7dc, 0x2a6d44f4, 0x2a7c9374, 0x2a8be359, + 0x2a9b34a2, 0x2aaa8750, 0x2ab9db60, 0x2ac930d1, 0x2ad887a3, 0x2ae7dfd3, 0x2af73962, 0x2b06944e, 0x2b15f096, + 0x2b254e38, 0x2b34ad34, 0x2b440d89, 0x2b536f34, 0x2b62d236, 0x2b72368d, 0x2b819c38, 0x2b910336, 0x2ba06b86, + 0x2bafd526, 0x2bbf4015, 0x2bceac53, 0x2bde19de, 0x2bed88b5, 0x2bfcf8d7, 0x2c0c6a43, 0x2c1bdcf7, 0x2c2b50f3, + 0x2c3ac635, 0x2c4a3cbd, 0x2c59b488, 0x2c692d97, 0x2c78a7e7, 0x2c882378, 0x2c97a049, 0x2ca71e58, 0x2cb69da4, + 0x2cc61e2c, 0x2cd59ff0, 0x2ce522ed, 0x2cf4a723, 0x2d042c90, 0x2d13b334, 0x2d233b0d, 0x2d32c41a, 0x2d424e5a, + 0x2d51d9cc, 0x2d61666e, 0x2d70f440, 0x2d808340, 0x2d90136e, 0x2d9fa4c7, 0x2daf374c, 0x2dbecafa, 0x2dce5fd1, + 0x2dddf5cf, 0x2ded8cf4, 0x2dfd253d, 0x2e0cbeab, 0x2e1c593b, 0x2e2bf4ed, 0x2e3b91c0, 0x2e4b2fb1, 0x2e5acec1, + 0x2e6a6eee, 0x2e7a1037, 0x2e89b29b, 0x2e995618, 0x2ea8faad, 0x2eb8a05a, 0x2ec8471c, 0x2ed7eef4, 0x2ee797df, + 0x2ef741dc, 0x2f06eceb, 0x2f16990a, 0x2f264639, 0x2f35f475, 0x2f45a3bd, 0x2f555412, 0x2f650570, 0x2f74b7d8, + 0x2f846b48, 0x2f941fbe, 0x2fa3d53a, 0x2fb38bbb, 0x2fc3433f, 0x2fd2fbc5, 0x2fe2b54c, 0x2ff26fd3, 0x30022b58, + 0x3011e7db, 0x3021a55a, 0x303163d4, 0x30412348, 0x3050e3b5, 0x3060a519, 0x30706773, 0x30802ac3, 0x308fef06, + 0x309fb43d, 0x30af7a65, 0x30bf417d, 0x30cf0985, 0x30ded27a, 0x30ee9c5d, 0x30fe672b, 0x310e32e3, 0x311dff85, + 0x312dcd0f, 0x313d9b80, 0x314d6ad7, 0x315d3b12, 0x316d0c30, 0x317cde31, 0x318cb113, 0x319c84d4, 0x31ac5974, + 0x31bc2ef1, 0x31cc054b, 0x31dbdc7f, 0x31ebb48e, 0x31fb8d74, 0x320b6733, 0x321b41c7, 0x322b1d31, 0x323af96e, + 0x324ad67e, 0x325ab45f, 0x326a9311, 0x327a7291, 0x328a52e0, 0x329a33fb, 0x32aa15e1, 0x32b9f892, 0x32c9dc0c, + 0x32d9c04d, 0x32e9a555, 0x32f98b22, 0x330971b4, 0x33195909, 0x3329411f, 0x333929f6, 0x3349138c, 0x3358fde1, + 0x3368e8f2, 0x3378d4c0, 0x3388c147, 0x3398ae89, 0x33a89c82, 0x33b88b32, 0x33c87a98, 0x33d86ab2, 0x33e85b80, + 0x33f84d00, 0x34083f30, 0x34183210, 0x3428259f, 0x343819db, 0x34480ec3, 0x34580455, 0x3467fa92, 0x3477f176, + 0x3487e902, 0x3497e134, 0x34a7da0a, 0x34b7d384, 0x34c7cda0, 0x34d7c85e, 0x34e7c3bb, 0x34f7bfb7, 0x3507bc50, + 0x3517b985, 0x3527b756, 0x3537b5c0, 0x3547b4c3, 0x3557b45d, 0x3567b48d, 0x3577b552, 0x3587b6aa, 0x3597b895, + 0x35a7bb12, 0x35b7be1e, 0x35c7c1b9, 0x35d7c5e1, 0x35e7ca96, 0x35f7cfd6, 0x3607d5a0, 0x3617dbf3, 0x3627e2cd, + 0x3637ea2d, 0x3647f212, 0x3657fa7b, 0x36680366, 0x36780cd2, 0x368816bf, 0x3698212b, 0x36a82c14, 0x36b83779, + 0x36c8435a, 0x36d84fb4, 0x36e85c88, 0x36f869d2, 0x37087793, 0x371885c9, 0x37289473, 0x3738a38f, 0x3748b31d, + 0x3758c31a, 0x3768d387, 0x3778e461, 0x3788f5a7, 0x37990759, 0x37a91975, 0x37b92bf9, 0x37c93ee4, 0x37d95236, + 0x37e965ed, 0x37f97a08, 0x38098e85, 0x3819a363, 0x3829b8a2, 0x3839ce3f, 0x3849e43a, 0x3859fa91, 0x386a1143, + 0x387a284f, 0x388a3fb4, 0x389a5770, 0x38aa6f83, 0x38ba87ea, 0x38caa0a5, 0x38dab9b2, 0x38ead311, 0x38faecbf, + 0x390b06bc, 0x391b2107, 0x392b3b9e, 0x393b5680, 0x394b71ac, 0x395b8d20, 0x396ba8dc, 0x397bc4dd, 0x398be124, + 0x399bfdae, 0x39ac1a7a, 0x39bc3788, 0x39cc54d5, 0x39dc7261, 0x39ec902a, 0x39fcae2f, 0x3a0ccc70, 0x3a1ceaea, + 0x3a2d099c, 0x3a3d2885, 0x3a4d47a5, 0x3a5d66f9, 0x3a6d8680, 0x3a7da63a, 0x3a8dc625, 0x3a9de63f, 0x3aae0688, + 0x3abe26fe, 0x3ace47a0, 0x3ade686d, 0x3aee8963, 0x3afeaa82, 0x3b0ecbc7, 0x3b1eed32, 0x3b2f0ec2, 0x3b3f3075, + 0x3b4f524a, 0x3b5f7440, 0x3b6f9656, 0x3b7fb889, 0x3b8fdada, 0x3b9ffd46, 0x3bb01fce, 0x3bc0426e, 0x3bd06526, + 0x3be087f6, 0x3bf0aada, 0x3c00cdd4, 0x3c10f0e0, 0x3c2113fe, 0x3c31372d, 0x3c415a6b, 0x3c517db7, 0x3c61a110, + 0x3c71c475, 0x3c81e7e4, 0x3c920b5c, 0x3ca22edc, 0x3cb25262, 0x3cc275ee, 0x3cd2997e, 0x3ce2bd11, 0x3cf2e0a6, + 0x3d03043b, 0x3d1327cf, 0x3d234b61, 0x3d336ef0, 0x3d43927a, 0x3d53b5ff, 0x3d63d97c, 0x3d73fcf1, 0x3d84205c, + 0x3d9443bd, 0x3da46711, 0x3db48a58, 0x3dc4ad91, 0x3dd4d0ba, 0x3de4f3d1, 0x3df516d7, 0x3e0539c9, 0x3e155ca6, + 0x3e257f6d, 0x3e35a21d, 0x3e45c4b4, 0x3e55e731, 0x3e660994, 0x3e762bda, 0x3e864e03, 0x3e96700d, 0x3ea691f7, + 0x3eb6b3bf, 0x3ec6d565, 0x3ed6f6e8, 0x3ee71845, 0x3ef7397c, 0x3f075a8c, 0x3f177b73, 0x3f279c30, 0x3f37bcc2, + 0x3f47dd27, 0x3f57fd5f, 0x3f681d68, 0x3f783d40, 0x3f885ce7, 0x3f987c5c, 0x3fa89b9c, 0x3fb8baa7, 0x3fc8d97c, + 0x3fd8f819, 0x3fe9167e, 0x3ff934a8, 0x40095296, 0x40197049, 0x40298dbd, 0x4039aaf2, 0x4049c7e7, 0x4059e49a, + 0x406a010a, 0x407a1d36, 0x408a391d, 0x409a54bd, 0x40aa7015, 0x40ba8b25, 0x40caa5ea, 0x40dac063, 0x40eada90, + 0x40faf46e, 0x410b0dfe, 0x411b273d, 0x412b402a, 0x413b58c4, 0x414b710a, 0x415b88fa, 0x416ba093, 0x417bb7d5, + 0x418bcebe, 0x419be54c, 0x41abfb7e, 0x41bc1153, 0x41cc26ca, 0x41dc3be2, 0x41ec5099, 0x41fc64ef, 0x420c78e1, + 0x421c8c6f, 0x422c9f97, 0x423cb258, 0x424cc4b2, 0x425cd6a2, 0x426ce827, 0x427cf941, 0x428d09ee, 0x429d1a2c, + 0x42ad29fb, 0x42bd3959, 0x42cd4846, 0x42dd56bf, 0x42ed64c3, 0x42fd7252, 0x430d7f6a, 0x431d8c0a, 0x432d9831, + 0x433da3dd, 0x434daf0d, 0x435db9c0, 0x436dc3f5, 0x437dcdab, 0x438dd6df, 0x439ddf92, 0x43ade7c1, 0x43bdef6c, + 0x43cdf691, 0x43ddfd2f, 0x43ee0345, 0x43fe08d2, 0x440e0dd4, 0x441e124b, 0x442e1634, 0x443e198f, 0x444e1c5a, + 0x445e1e95, 0x446e203e, 0x447e2153, 0x448e21d5, 0x449e21c0, 0x44ae2115, 0x44be1fd1, 0x44ce1df4, 0x44de1b7d, + 0x44ee186a, 0x44fe14ba, 0x450e106b, 0x451e0b7e, 0x452e05ef, 0x453dffbf, 0x454df8eb, 0x455df173, 0x456de956, + 0x457de092, 0x458dd726, 0x459dcd10, 0x45adc251, 0x45bdb6e5, 0x45cdaacd, 0x45dd9e06, 0x45ed9091, 0x45fd826a, + 0x460d7392, 0x461d6407, 0x462d53c8, 0x463d42d4, 0x464d3129, 0x465d1ec6, 0x466d0baa, 0x467cf7d3, 0x468ce342, + 0x469ccdf3, 0x46acb7e7, 0x46bca11c, 0x46cc8990, 0x46dc7143, 0x46ec5833, 0x46fc3e5f, 0x470c23c6, 0x471c0867, + 0x472bec40, 0x473bcf50, 0x474bb196, 0x475b9311, 0x476b73c0, 0x477b53a1, 0x478b32b4, 0x479b10f6, 0x47aaee67, + 0x47bacb06, 0x47caa6d1, 0x47da81c7, 0x47ea5be7, 0x47fa3530, 0x480a0da1, 0x4819e537, 0x4829bbf3, 0x483991d3, + 0x484966d6, 0x48593afb, 0x48690e3f, 0x4878e0a3, 0x4888b225, 0x489882c4, 0x48a8527e, 0x48b82153, 0x48c7ef41, + 0x48d7bc47, 0x48e78863, 0x48f75396, 0x49071ddc, 0x4916e736, 0x4926afa2, 0x4936771f, 0x49463dac, 0x49560347, + 0x4965c7ef, 0x49758ba4, 0x49854e63, 0x4995102c, 0x49a4d0fe, 0x49b490d7, 0x49c44fb6, 0x49d40d9a, 0x49e3ca82, + 0x49f3866c, 0x4a034159, 0x4a12fb45, 0x4a22b430, 0x4a326c19, 0x4a4222ff, 0x4a51d8e1, 0x4a618dbd, 0x4a714192, + 0x4a80f45f, 0x4a90a623, 0x4aa056dd, 0x4ab0068b, 0x4abfb52c, 0x4acf62c0, 0x4adf0f44, 0x4aeebab9, 0x4afe651c, + 0x4b0e0e6c, 0x4b1db6a9, 0x4b2d5dd1, 0x4b3d03e2, 0x4b4ca8dd, 0x4b5c4cbf, 0x4b6bef88, 0x4b7b9136, 0x4b8b31c8, + 0x4b9ad13d, 0x4baa6f93, 0x4bba0ccb, 0x4bc9a8e2, 0x4bd943d7, 0x4be8dda9, 0x4bf87658, 0x4c080de1, 0x4c17a444, + 0x4c27397f, 0x4c36cd92, 0x4c46607b, 0x4c55f239, 0x4c6582cb, 0x4c75122f, 0x4c84a065, 0x4c942d6c, 0x4ca3b942, + 0x4cb343e6, 0x4cc2cd57, 0x4cd25594, 0x4ce1dc9c, 0x4cf1626d, 0x4d00e707, 0x4d106a68, 0x4d1fec8f, 0x4d2f6d7a, + 0x4d3eed2a, 0x4d4e6b9d, 0x4d5de8d1, 0x4d6d64c5, 0x4d7cdf79, 0x4d8c58eb, 0x4d9bd11a, 0x4dab4804, 0x4dbabdaa, + 0x4dca3209, 0x4dd9a520, 0x4de916ef, 0x4df88774, 0x4e07f6ae, 0x4e17649c, 0x4e26d13c, 0x4e363c8f, 0x4e45a692, + 0x4e550f44, 0x4e6476a4, 0x4e73dcb2, 0x4e83416c, 0x4e92a4d1, 0x4ea206df, 0x4eb16796, 0x4ec0c6f5, 0x4ed024fa, + 0x4edf81a5, 0x4eeedcf3, 0x4efe36e5, 0x4f0d8f79, 0x4f1ce6ad, 0x4f2c3c82, 0x4f3b90f4, 0x4f4ae405, 0x4f5a35b1, + 0x4f6985fa, 0x4f78d4dc, 0x4f882257, 0x4f976e6a, 0x4fa6b914, 0x4fb60254, 0x4fc54a28, 0x4fd49090, 0x4fe3d58b, + 0x4ff31917, 0x50025b33, 0x50119bde, 0x5020db17, 0x503018dd, 0x503f552f, 0x504e900b, 0x505dc971, 0x506d0160, + 0x507c37d7, 0x508b6cd3, 0x509aa055, 0x50a9d25b, 0x50b902e4, 0x50c831ef, 0x50d75f7b, 0x50e68b87, 0x50f5b612, + 0x5104df1a, 0x5114069f, 0x51232ca0, 0x5132511a, 0x5141740f, 0x5150957b, 0x515fb55f, 0x516ed3b8, 0x517df087, + 0x518d0bca, 0x519c257f, 0x51ab3da7, 0x51ba543f, 0x51c96947, 0x51d87cbd, 0x51e78ea1, 0x51f69ef1, 0x5205adad, + 0x5214bad3, 0x5223c662, 0x5232d05a, 0x5241d8b9, 0x5250df7d, 0x525fe4a7, 0x526ee835, 0x527dea26, 0x528cea78, + 0x529be92c, 0x52aae63f, 0x52b9e1b0, 0x52c8db80, 0x52d7d3ac, 0x52e6ca33, 0x52f5bf15, 0x5304b251, 0x5313a3e5, + 0x532293d0, 0x53318212, 0x53406ea8, 0x534f5993, 0x535e42d2, 0x536d2a62, 0x537c1043, 0x538af475, 0x5399d6f6, + 0x53a8b7c4, 0x53b796e0, 0x53c67447, 0x53d54ffa, 0x53e429f6, 0x53f3023b, 0x5401d8c8, 0x5410ad9c, 0x541f80b5, + 0x542e5213, 0x543d21b5, 0x544bef9a, 0x545abbc0, 0x54698627, 0x54784ece, 0x548715b3, 0x5495dad6, 0x54a49e35, + 0x54b35fd0, 0x54c21fa6, 0x54d0ddb5, 0x54df99fd, 0x54ee547c, 0x54fd0d32, 0x550bc41d, 0x551a793d, 0x55292c91, + 0x5537de16, 0x55468dce, 0x55553bb6, 0x5563e7cd, 0x55729213, 0x55813a87, 0x558fe127, 0x559e85f2, 0x55ad28e9, + 0x55bbca08, 0x55ca6950, 0x55d906c0, 0x55e7a257, 0x55f63c13, 0x5604d3f4, 0x561369f8, 0x5621fe1f, 0x56309067, + 0x563f20d1, 0x564daf5a, 0x565c3c02, 0x566ac6c7, 0x56794faa, 0x5687d6a8, 0x56965bc1, 0x56a4def4, 0x56b36040, + 0x56c1dfa4, 0x56d05d1f, 0x56ded8af, 0x56ed5255, 0x56fbca0f, 0x570a3fdc, 0x5718b3bc, 0x572725ac, 0x573595ad, + 0x574403bd, 0x57526fdb, 0x5760da07, 0x576f423f, 0x577da883, 0x578c0cd1, 0x579a6f29, 0x57a8cf8a, 0x57b72df2, + 0x57c58a61, 0x57d3e4d6, 0x57e23d50, 0x57f093cd, 0x57fee84e, 0x580d3ad1, 0x581b8b54, 0x5829d9d8, 0x5838265c, + 0x584670dd, 0x5854b95c, 0x5862ffd8, 0x5871444f, 0x587f86c1, 0x588dc72c, 0x589c0591, 0x58aa41ed, 0x58b87c40, + 0x58c6b489, 0x58d4eac7, 0x58e31ef9, 0x58f1511f, 0x58ff8137, 0x590daf40, 0x591bdb3a, 0x592a0524, 0x59382cfc, + 0x594652c2, 0x59547675, 0x59629815, 0x5970b79f, 0x597ed513, 0x598cf071, 0x599b09b7, 0x59a920e5, 0x59b735f9, + 0x59c548f4, 0x59d359d2, 0x59e16895, 0x59ef753b, 0x59fd7fc4, 0x5a0b882d, 0x5a198e77, 0x5a2792a0, 0x5a3594a9, + 0x5a43948e, 0x5a519251, 0x5a5f8df0, 0x5a6d876a, 0x5a7b7ebe, 0x5a8973ec, 0x5a9766f2, 0x5aa557d0, 0x5ab34685, + 0x5ac1330f, 0x5acf1d6f, 0x5add05a3, 0x5aeaebaa, 0x5af8cf84, 0x5b06b12f, 0x5b1490ab, 0x5b226df7, 0x5b304912, + 0x5b3e21fc, 0x5b4bf8b2, 0x5b59cd35, 0x5b679f84, 0x5b756f9e, 0x5b833d82, 0x5b91092e, 0x5b9ed2a3, 0x5bac99e0, + 0x5bba5ee3, 0x5bc821ac, 0x5bd5e23a, 0x5be3a08c, 0x5bf15ca1, 0x5bff1679, 0x5c0cce12, 0x5c1a836c, 0x5c283686, + 0x5c35e760, 0x5c4395f7, 0x5c51424c, 0x5c5eec5e, 0x5c6c942b, 0x5c7a39b4, 0x5c87dcf7, 0x5c957df3, 0x5ca31ca8, + 0x5cb0b915, 0x5cbe5338, 0x5ccbeb12, 0x5cd980a1, 0x5ce713e5, 0x5cf4a4dd, 0x5d023387, 0x5d0fbfe4, 0x5d1d49f2, + 0x5d2ad1b1, 0x5d38571f, 0x5d45da3c, 0x5d535b08, 0x5d60d981, 0x5d6e55a7, 0x5d7bcf78, 0x5d8946f5, 0x5d96bc1c, + 0x5da42eec, 0x5db19f65, 0x5dbf0d86, 0x5dcc794e, 0x5dd9e2bd, 0x5de749d1, 0x5df4ae8a, 0x5e0210e7, 0x5e0f70e7, + 0x5e1cce8a, 0x5e2a29ce, 0x5e3782b4, 0x5e44d93a, 0x5e522d5f, 0x5e5f7f23, 0x5e6cce85, 0x5e7a1b85, 0x5e876620, + 0x5e94ae58, 0x5ea1f42a, 0x5eaf3797, 0x5ebc789d, 0x5ec9b73c, 0x5ed6f372, 0x5ee42d41, 0x5ef164a5, 0x5efe999f, + 0x5f0bcc2f, 0x5f18fc52, 0x5f262a09, 0x5f335553, 0x5f407e2f, 0x5f4da49d, 0x5f5ac89b, 0x5f67ea29, 0x5f750946, + 0x5f8225f2, 0x5f8f402b, 0x5f9c57f2, 0x5fa96d44, 0x5fb68023, 0x5fc3908c, 0x5fd09e7f, 0x5fdda9fc, 0x5feab302, + 0x5ff7b990, 0x6004bda5, 0x6011bf40, 0x601ebe62, 0x602bbb09, 0x6038b534, 0x6045ace4, 0x6052a216, 0x605f94cb, + 0x606c8502, 0x607972b9, 0x60865df2, 0x609346aa, 0x60a02ce1, 0x60ad1096, 0x60b9f1c9, 0x60c6d079, 0x60d3aca5, + 0x60e0864d, 0x60ed5d70, 0x60fa320d, 0x61070424, 0x6113d3b4, 0x6120a0bc, 0x612d6b3c, 0x613a3332, 0x6146f89f, + 0x6153bb82, 0x61607bd9, 0x616d39a5, 0x6179f4e5, 0x6186ad98, 0x619363bd, 0x61a01753, 0x61acc85b, 0x61b976d3, + 0x61c622bc, 0x61d2cc13, 0x61df72d8, 0x61ec170c, 0x61f8b8ad, 0x620557ba, 0x6211f434, 0x621e8e18, 0x622b2568, + 0x6237ba21, 0x62444c44, 0x6250dbd0, 0x625d68c4, 0x6269f320, 0x62767ae2, 0x6283000b, 0x628f829a, 0x629c028e, + 0x62a87fe6, 0x62b4faa2, 0x62c172c2, 0x62cde844, 0x62da5b29, 0x62e6cb6e, 0x62f33915, 0x62ffa41c, 0x630c0c83, + 0x63187248, 0x6324d56d, 0x633135ef, 0x633d93ce, 0x6349ef0b, 0x635647a3, 0x63629d97, 0x636ef0e6, 0x637b418f, + 0x63878f92, 0x6393daef, 0x63a023a4, 0x63ac69b1, 0x63b8ad15, 0x63c4edd1, 0x63d12be3, 0x63dd674b, 0x63e9a008, + 0x63f5d61a, 0x64020980, 0x640e3a39, 0x641a6846, 0x642693a5, 0x6432bc56, 0x643ee258, 0x644b05ab, 0x6457264e, + 0x64634441, 0x646f5f83, 0x647b7814, 0x64878df3, 0x6493a120, 0x649fb199, 0x64abbf5f, 0x64b7ca71, 0x64c3d2ce, + 0x64cfd877, 0x64dbdb69, 0x64e7dba6, 0x64f3d92b, 0x64ffd3fa, 0x650bcc11, 0x6517c16f, 0x6523b415, 0x652fa402, + 0x653b9134, 0x65477bad, 0x6553636a, 0x655f486d, 0x656b2ab3, 0x65770a3d, 0x6582e70a, 0x658ec11a, 0x659a986d, + 0x65a66d00, 0x65b23ed5, 0x65be0deb, 0x65c9da41, 0x65d5a3d7, 0x65e16aac, 0x65ed2ebf, 0x65f8f011, 0x6604aea1, + 0x66106a6e, 0x661c2377, 0x6627d9be, 0x66338d40, 0x663f3dfd, 0x664aebf5, 0x66569728, 0x66623f95, 0x666de53b, + 0x6679881b, 0x66852833, 0x6690c583, 0x669c600b, 0x66a7f7ca, 0x66b38cc0, 0x66bf1eec, 0x66caae4f, 0x66d63ae6, + 0x66e1c4b3, 0x66ed4bb4, 0x66f8cfea, 0x67045153, 0x670fcfef, 0x671b4bbe, 0x6726c4bf, 0x67323af3, 0x673dae58, + 0x67491eee, 0x67548cb5, 0x675ff7ab, 0x676b5fd2, 0x6776c528, 0x678227ad, 0x678d8761, 0x6798e443, 0x67a43e52, + 0x67af958f, 0x67bae9f9, 0x67c63b8f, 0x67d18a52, 0x67dcd640, 0x67e81f59, 0x67f3659d, 0x67fea90c, 0x6809e9a5, + 0x68152768, 0x68206254, 0x682b9a68, 0x6836cfa6, 0x6842020b, 0x684d3199, 0x68585e4d, 0x68638829, 0x686eaf2b, + 0x6879d354, 0x6884f4a2, 0x68901316, 0x689b2eb0, 0x68a6476d, 0x68b15d50, 0x68bc7056, 0x68c78080, 0x68d28dcd, + 0x68dd983e, 0x68e89fd0, 0x68f3a486, 0x68fea65d, 0x6909a555, 0x6914a16f, 0x691f9aa9, 0x692a9104, 0x69358480, + 0x6940751b, 0x694b62d5, 0x69564daf, 0x696135a7, 0x696c1abe, 0x6976fcf3, 0x6981dc46, 0x698cb8b6, 0x69979243, + 0x69a268ed, 0x69ad3cb4, 0x69b80d97, 0x69c2db96, 0x69cda6b0, 0x69d86ee5, 0x69e33436, 0x69edf6a1, 0x69f8b626, + 0x6a0372c5, 0x6a0e2c7e, 0x6a18e350, 0x6a23973c, 0x6a2e4840, 0x6a38f65d, 0x6a43a191, 0x6a4e49de, 0x6a58ef42, + 0x6a6391be, 0x6a6e3151, 0x6a78cdfa, 0x6a8367ba, 0x6a8dfe90, 0x6a98927c, 0x6aa3237d, 0x6aadb194, 0x6ab83cc0, + 0x6ac2c500, 0x6acd4a55, 0x6ad7ccbf, 0x6ae24c3c, 0x6aecc8cd, 0x6af74271, 0x6b01b929, 0x6b0c2cf4, 0x6b169dd1, + 0x6b210bc1, 0x6b2b76c2, 0x6b35ded6, 0x6b4043fc, 0x6b4aa632, 0x6b55057a, 0x6b5f61d3, 0x6b69bb3d, 0x6b7411b7, + 0x6b7e6541, 0x6b88b5db, 0x6b930385, 0x6b9d4e3f, 0x6ba79607, 0x6bb1dadf, 0x6bbc1cc6, 0x6bc65bbb, 0x6bd097bf, + 0x6bdad0d0, 0x6be506f0, 0x6bef3a1d, 0x6bf96a58, 0x6c0397a0, 0x6c0dc1f5, 0x6c17e957, 0x6c220dc6, 0x6c2c2f41, + 0x6c364dc9, 0x6c40695c, 0x6c4a81fc, 0x6c5497a7, 0x6c5eaa5d, 0x6c68ba1f, 0x6c72c6eb, 0x6c7cd0c3, 0x6c86d7a6, + 0x6c90db92, 0x6c9adc8a, 0x6ca4da8b, 0x6caed596, 0x6cb8cdab, 0x6cc2c2ca, 0x6cccb4f2, 0x6cd6a424, 0x6ce0905e, + 0x6cea79a1, 0x6cf45fee, 0x6cfe4342, 0x6d0823a0, 0x6d120105, 0x6d1bdb73, 0x6d25b2e8, 0x6d2f8765, 0x6d3958ea, + 0x6d432777, 0x6d4cf30a, 0x6d56bba5, 0x6d608147, 0x6d6a43f0, 0x6d7403a0, 0x6d7dc056, 0x6d877a13, 0x6d9130d6, + 0x6d9ae4a0, 0x6da4956f, 0x6dae4345, 0x6db7ee20, 0x6dc19601, 0x6dcb3ae7, 0x6dd4dcd3, 0x6dde7bc4, 0x6de817bb, + 0x6df1b0b6, 0x6dfb46b7, 0x6e04d9bc, 0x6e0e69c7, 0x6e17f6d5, 0x6e2180e9, 0x6e2b0801, 0x6e348c1d, 0x6e3e0d3d, + 0x6e478b62, 0x6e51068a, 0x6e5a7eb7, 0x6e63f3e7, 0x6e6d661b, 0x6e76d552, 0x6e80418e, 0x6e89aacc, 0x6e93110f, + 0x6e9c7454, 0x6ea5d49d, 0x6eaf31e9, 0x6eb88c37, 0x6ec1e389, 0x6ecb37de, 0x6ed48936, 0x6eddd790, 0x6ee722ee, + 0x6ef06b4d, 0x6ef9b0b0, 0x6f02f315, 0x6f0c327c, 0x6f156ee6, 0x6f1ea852, 0x6f27dec1, 0x6f311232, 0x6f3a42a5, + 0x6f43701a, 0x6f4c9a91, 0x6f55c20a, 0x6f5ee686, 0x6f680803, 0x6f712682, 0x6f7a4203, 0x6f835a86, 0x6f8c700b, + 0x6f958291, 0x6f9e921a, 0x6fa79ea4, 0x6fb0a830, 0x6fb9aebd, 0x6fc2b24c, 0x6fcbb2dd, 0x6fd4b06f, 0x6fddab03, + 0x6fe6a299, 0x6fef9730, 0x6ff888c9, 0x70017763, 0x700a62ff, 0x70134b9c, 0x701c313b, 0x702513dc, 0x702df37e, + 0x7036d021, 0x703fa9c6, 0x7048806d, 0x70515415, 0x705a24bf, 0x7062f26b, 0x706bbd17, 0x707484c6, 0x707d4976, + 0x70860b28, 0x708ec9dc, 0x70978591, 0x70a03e48, 0x70a8f400, 0x70b1a6bb, 0x70ba5677, 0x70c30335, 0x70cbacf5, + 0x70d453b6, 0x70dcf77a, 0x70e59840, 0x70ee3607, 0x70f6d0d1, 0x70ff689d, 0x7107fd6b, 0x71108f3b, 0x71191e0d, + 0x7121a9e2, 0x712a32b9, 0x7132b892, 0x713b3b6e, 0x7143bb4c, 0x714c382d, 0x7154b211, 0x715d28f7, 0x71659ce0, + 0x716e0dcc, 0x71767bbb, 0x717ee6ac, 0x71874ea1, 0x718fb399, 0x71981594, 0x71a07493, 0x71a8d094, 0x71b1299a, + 0x71b97fa2, 0x71c1d2af, 0x71ca22bf, 0x71d26fd2, 0x71dab9ea, 0x71e30106, 0x71eb4526, 0x71f3864a, 0x71fbc472, + 0x7203ff9e, 0x720c37cf, 0x72146d05, 0x721c9f3f, 0x7224ce7e, 0x722cfac2, 0x7235240b, 0x723d4a59, 0x72456dad, + 0x724d8e05, 0x7255ab63, 0x725dc5c7, 0x7265dd31, 0x726df1a0, 0x72760315, 0x727e1191, 0x72861d12, 0x728e259a, + 0x72962b28, 0x729e2dbd, 0x72a62d59, 0x72ae29fc, 0x72b623a5, 0x72be1a56, 0x72c60e0e, 0x72cdfece, 0x72d5ec95, + 0x72ddd764, 0x72e5bf3b, 0x72eda41a, 0x72f58601, 0x72fd64f1, 0x730540e9, 0x730d19e9, 0x7314eff3, 0x731cc305, + 0x73249321, 0x732c6046, 0x73342a75, 0x733bf1ad, 0x7343b5ef, 0x734b773b, 0x73533591, 0x735af0f2, 0x7362a95d, + 0x736a5ed3, 0x73721153, 0x7379c0df, 0x73816d76, 0x73891719, 0x7390bdc7, 0x73986181, 0x73a00247, 0x73a7a01a, + 0x73af3af8, 0x73b6d2e4, 0x73be67dc, 0x73c5f9e1, 0x73cd88f3, 0x73d51513, 0x73dc9e40, 0x73e4247c, 0x73eba7c5, + 0x73f3281c, 0x73faa582, 0x74021ff7, 0x7409977b, 0x74110c0d, 0x74187daf, 0x741fec61, 0x74275822, 0x742ec0f3, + 0x743626d5, 0x743d89c7, 0x7444e9c9, 0x744c46dd, 0x7453a101, 0x745af837, 0x74624c7f, 0x74699dd8, 0x7470ec44, + 0x747837c2, 0x747f8052, 0x7486c5f5, 0x748e08ac, 0x74954875, 0x749c8552, 0x74a3bf43, 0x74aaf648, 0x74b22a62, + 0x74b95b90, 0x74c089d2, 0x74c7b52a, 0x74cedd97, 0x74d6031a, 0x74dd25b2, 0x74e44561, 0x74eb6226, 0x74f27c02, + 0x74f992f5, 0x7500a6ff, 0x7507b820, 0x750ec659, 0x7515d1aa, 0x751cda14, 0x7523df96, 0x752ae231, 0x7531e1e5, + 0x7538deb2, 0x753fd89a, 0x7546cf9b, 0x754dc3b7, 0x7554b4ed, 0x755ba33e, 0x75628eaa, 0x75697732, 0x75705cd5, + 0x75773f95, 0x757e1f71, 0x7584fc6a, 0x758bd67f, 0x7592adb2, 0x75998203, 0x75a05371, 0x75a721fe, 0x75adeda9, + 0x75b4b673, 0x75bb7c5c, 0x75c23f65, 0x75c8ff8d, 0x75cfbcd6, 0x75d6773f, 0x75dd2ec8, 0x75e3e373, 0x75ea953f, + 0x75f1442d, 0x75f7f03d, 0x75fe996f, 0x76053fc5, 0x760be33d, 0x761283d8, 0x76192197, 0x761fbc7b, 0x76265482, + 0x762ce9af, 0x76337c01, 0x763a0b78, 0x76409814, 0x764721d7, 0x764da8c1, 0x76542cd1, 0x765aae08, 0x76612c67, + 0x7667a7ee, 0x766e209d, 0x76749675, 0x767b0975, 0x7681799f, 0x7687e6f3, 0x768e5170, 0x7694b918, 0x769b1deb, + 0x76a17fe9, 0x76a7df13, 0x76ae3b68, 0x76b494ea, 0x76baeb98, 0x76c13f74, 0x76c7907c, 0x76cddeb3, 0x76d42a18, + 0x76da72ab, 0x76e0b86d, 0x76e6fb5e, 0x76ed3b7f, 0x76f378d0, 0x76f9b352, 0x76ffeb05, 0x77061fe8, 0x770c51fe, + 0x77128145, 0x7718adbf, 0x771ed76c, 0x7724fe4c, 0x772b225f, 0x773143a7, 0x77376223, 0x773d7dd3, 0x774396ba, + 0x7749acd5, 0x774fc027, 0x7755d0af, 0x775bde6f, 0x7761e965, 0x7767f193, 0x776df6fa, 0x7773f998, 0x7779f970, + 0x777ff681, 0x7785f0cd, 0x778be852, 0x7791dd12, 0x7797cf0d, 0x779dbe43, 0x77a3aab6, 0x77a99465, 0x77af7b50, + 0x77b55f79, 0x77bb40e0, 0x77c11f85, 0x77c6fb68, 0x77ccd48a, 0x77d2aaec, 0x77d87e8d, 0x77de4f6f, 0x77e41d92, + 0x77e9e8f5, 0x77efb19b, 0x77f57782, 0x77fb3aad, 0x7800fb1a, 0x7806b8ca, 0x780c73bf, 0x78122bf7, 0x7817e175, + 0x781d9438, 0x78234440, 0x7828f18f, 0x782e9c25, 0x78344401, 0x7839e925, 0x783f8b92, 0x78452b46, 0x784ac844, + 0x7850628b, 0x7855fa1c, 0x785b8ef8, 0x7861211e, 0x7866b090, 0x786c3d4d, 0x7871c757, 0x78774ead, 0x787cd351, + 0x78825543, 0x7887d483, 0x788d5111, 0x7892caef, 0x7898421c, 0x789db69a, 0x78a32868, 0x78a89787, 0x78ae03f8, + 0x78b36dbb, 0x78b8d4d1, 0x78be393a, 0x78c39af6, 0x78c8fa06, 0x78ce566c, 0x78d3b026, 0x78d90736, 0x78de5b9c, + 0x78e3ad58, 0x78e8fc6c, 0x78ee48d7, 0x78f3929b, 0x78f8d9b7, 0x78fe1e2c, 0x79035ffb, 0x79089f24, 0x790ddba8, + 0x79131587, 0x79184cc2, 0x791d8159, 0x7922b34d, 0x7927e29e, 0x792d0f4d, 0x7932395a, 0x793760c6, 0x793c8591, + 0x7941a7bd, 0x7946c749, 0x794be435, 0x7950fe84, 0x79561634, 0x795b2b47, 0x79603dbc, 0x79654d96, 0x796a5ad4, + 0x796f6576, 0x79746d7e, 0x797972eb, 0x797e75bf, 0x798375f9, 0x7988739b, 0x798d6ea5, 0x79926717, 0x79975cf2, + 0x799c5037, 0x79a140e6, 0x79a62f00, 0x79ab1a85, 0x79b00376, 0x79b4e9d3, 0x79b9cd9d, 0x79beaed4, 0x79c38d79, + 0x79c8698d, 0x79cd4310, 0x79d21a03, 0x79d6ee66, 0x79dbc03a, 0x79e08f7f, 0x79e55c36, 0x79ea265f, 0x79eeedfc, + 0x79f3b30c, 0x79f87590, 0x79fd3589, 0x7a01f2f7, 0x7a06addc, 0x7a0b6636, 0x7a101c08, 0x7a14cf52, 0x7a198013, + 0x7a1e2e4d, 0x7a22da01, 0x7a27832f, 0x7a2c29d7, 0x7a30cdfa, 0x7a356f99, 0x7a3a0eb4, 0x7a3eab4c, 0x7a434561, + 0x7a47dcf5, 0x7a4c7207, 0x7a510498, 0x7a5594a9, 0x7a5a223a, 0x7a5ead4d, 0x7a6335e0, 0x7a67bbf6, 0x7a6c3f8f, + 0x7a70c0ab, 0x7a753f4b, 0x7a79bb6f, 0x7a7e3519, 0x7a82ac48, 0x7a8720fe, 0x7a8b933b, 0x7a9002ff, 0x7a94704b, + 0x7a98db20, 0x7a9d437e, 0x7aa1a967, 0x7aa60cd9, 0x7aaa6dd7, 0x7aaecc61, 0x7ab32877, 0x7ab7821b, 0x7abbd94b, + 0x7ac02e0a, 0x7ac48058, 0x7ac8d035, 0x7acd1da3, 0x7ad168a1, 0x7ad5b130, 0x7ad9f751, 0x7ade3b05, 0x7ae27c4c, + 0x7ae6bb27, 0x7aeaf796, 0x7aef319a, 0x7af36934, 0x7af79e64, 0x7afbd12c, 0x7b00018a, 0x7b042f81, 0x7b085b10, + 0x7b0c8439, 0x7b10aafc, 0x7b14cf5a, 0x7b18f153, 0x7b1d10e8, 0x7b212e1a, 0x7b2548e9, 0x7b296155, 0x7b2d7761, + 0x7b318b0b, 0x7b359c55, 0x7b39ab3f, 0x7b3db7cb, 0x7b41c1f8, 0x7b45c9c8, 0x7b49cf3b, 0x7b4dd251, 0x7b51d30b, + 0x7b55d16b, 0x7b59cd70, 0x7b5dc71b, 0x7b61be6d, 0x7b65b366, 0x7b69a608, 0x7b6d9653, 0x7b718447, 0x7b756fe5, + 0x7b79592e, 0x7b7d4022, 0x7b8124c3, 0x7b850710, 0x7b88e70a, 0x7b8cc4b3, 0x7b90a00a, 0x7b947911, 0x7b984fc8, + 0x7b9c242f, 0x7b9ff648, 0x7ba3c612, 0x7ba79390, 0x7bab5ec1, 0x7baf27a5, 0x7bb2ee3f, 0x7bb6b28e, 0x7bba7493, + 0x7bbe344e, 0x7bc1f1c1, 0x7bc5acec, 0x7bc965cf, 0x7bcd1c6c, 0x7bd0d0c3, 0x7bd482d4, 0x7bd832a1, 0x7bdbe02a, + 0x7bdf8b70, 0x7be33473, 0x7be6db34, 0x7bea7fb4, 0x7bee21f4, 0x7bf1c1f3, 0x7bf55fb3, 0x7bf8fb35, 0x7bfc9479, + 0x7c002b7f, 0x7c03c04a, 0x7c0752d8, 0x7c0ae32b, 0x7c0e7144, 0x7c11fd23, 0x7c1586c9, 0x7c190e36, 0x7c1c936c, + 0x7c20166b, 0x7c239733, 0x7c2715c6, 0x7c2a9224, 0x7c2e0c4e, 0x7c318444, 0x7c34fa07, 0x7c386d98, 0x7c3bdef8, + 0x7c3f4e26, 0x7c42bb25, 0x7c4625f4, 0x7c498e95, 0x7c4cf507, 0x7c50594c, 0x7c53bb65, 0x7c571b51, 0x7c5a7913, + 0x7c5dd4aa, 0x7c612e17, 0x7c64855b, 0x7c67da76, 0x7c6b2d6a, 0x7c6e7e37, 0x7c71ccdd, 0x7c75195e, 0x7c7863ba, + 0x7c7babf1, 0x7c7ef206, 0x7c8235f7, 0x7c8577c6, 0x7c88b774, 0x7c8bf502, 0x7c8f306f, 0x7c9269bd, 0x7c95a0ec, + 0x7c98d5fe, 0x7c9c08f2, 0x7c9f39cb, 0x7ca26887, 0x7ca59528, 0x7ca8bfb0, 0x7cabe81d, 0x7caf0e72, 0x7cb232af, + 0x7cb554d4, 0x7cb874e2, 0x7cbb92db, 0x7cbeaebe, 0x7cc1c88d, 0x7cc4e047, 0x7cc7f5ef, 0x7ccb0984, 0x7cce1b08, + 0x7cd12a7b, 0x7cd437dd, 0x7cd74330, 0x7cda4c74, 0x7cdd53aa, 0x7ce058d3, 0x7ce35bef, 0x7ce65cff, 0x7ce95c04, + 0x7cec58ff, 0x7cef53f0, 0x7cf24cd7, 0x7cf543b7, 0x7cf8388f, 0x7cfb2b60, 0x7cfe1c2b, 0x7d010af1, 0x7d03f7b2, + 0x7d06e26f, 0x7d09cb29, 0x7d0cb1e0, 0x7d0f9696, 0x7d12794b, 0x7d1559ff, 0x7d1838b4, 0x7d1b156a, 0x7d1df022, + 0x7d20c8dd, 0x7d239f9b, 0x7d26745e, 0x7d294725, 0x7d2c17f1, 0x7d2ee6c4, 0x7d31b39f, 0x7d347e81, 0x7d37476b, + 0x7d3a0e5f, 0x7d3cd35d, 0x7d3f9665, 0x7d425779, 0x7d451699, 0x7d47d3c6, 0x7d4a8f01, 0x7d4d484b, 0x7d4fffa3, + 0x7d52b50c, 0x7d556885, 0x7d581a0f, 0x7d5ac9ac, 0x7d5d775c, 0x7d60231f, 0x7d62ccf6, 0x7d6574e3, 0x7d681ae6, + 0x7d6abeff, 0x7d6d612f, 0x7d700178, 0x7d729fd9, 0x7d753c54, 0x7d77d6e9, 0x7d7a6f9a, 0x7d7d0666, 0x7d7f9b4f, + 0x7d822e55, 0x7d84bf79, 0x7d874ebc, 0x7d89dc1e, 0x7d8c67a1, 0x7d8ef144, 0x7d91790a, 0x7d93fef2, 0x7d9682fd, + 0x7d99052d, 0x7d9b8581, 0x7d9e03fb, 0x7da0809b, 0x7da2fb62, 0x7da57451, 0x7da7eb68, 0x7daa60a8, 0x7dacd413, + 0x7daf45a9, 0x7db1b56a, 0x7db42357, 0x7db68f71, 0x7db8f9b9, 0x7dbb6230, 0x7dbdc8d6, 0x7dc02dac, 0x7dc290b3, + 0x7dc4f1eb, 0x7dc75156, 0x7dc9aef4, 0x7dcc0ac5, 0x7dce64cc, 0x7dd0bd07, 0x7dd31379, 0x7dd56821, 0x7dd7bb01, + 0x7dda0c1a, 0x7ddc5b6b, 0x7ddea8f7, 0x7de0f4bd, 0x7de33ebe, 0x7de586fc, 0x7de7cd76, 0x7dea122e, 0x7dec5525, + 0x7dee965a, 0x7df0d5d0, 0x7df31386, 0x7df54f7e, 0x7df789b8, 0x7df9c235, 0x7dfbf8f5, 0x7dfe2dfa, 0x7e006145, + 0x7e0292d5, 0x7e04c2ac, 0x7e06f0cb, 0x7e091d32, 0x7e0b47e1, 0x7e0d70db, 0x7e0f981f, 0x7e11bdaf, 0x7e13e18a, + 0x7e1603b3, 0x7e182429, 0x7e1a42ed, 0x7e1c6001, 0x7e1e7b64, 0x7e209518, 0x7e22ad1d, 0x7e24c375, 0x7e26d81f, + 0x7e28eb1d, 0x7e2afc70, 0x7e2d0c17, 0x7e2f1a15, 0x7e31266a, 0x7e333115, 0x7e353a1a, 0x7e374177, 0x7e39472e, + 0x7e3b4b3f, 0x7e3d4dac, 0x7e3f4e75, 0x7e414d9a, 0x7e434b1e, 0x7e4546ff, 0x7e474140, 0x7e4939e0, 0x7e4b30e2, + 0x7e4d2644, 0x7e4f1a09, 0x7e510c30, 0x7e52fcbc, 0x7e54ebab, 0x7e56d900, 0x7e58c4bb, 0x7e5aaedd, 0x7e5c9766, + 0x7e5e7e57, 0x7e6063b2, 0x7e624776, 0x7e6429a5, 0x7e660a3f, 0x7e67e945, 0x7e69c6b8, 0x7e6ba299, 0x7e6d7ce7, + 0x7e6f55a5, 0x7e712cd3, 0x7e730272, 0x7e74d682, 0x7e76a904, 0x7e7879f9, 0x7e7a4962, 0x7e7c173f, 0x7e7de392, + 0x7e7fae5a, 0x7e817799, 0x7e833f50, 0x7e85057f, 0x7e86ca27, 0x7e888d49, 0x7e8a4ee5, 0x7e8c0efd, 0x7e8dcd91, + 0x7e8f8aa1, 0x7e914630, 0x7e93003c, 0x7e94b8c8, 0x7e966fd4, 0x7e982560, 0x7e99d96e, 0x7e9b8bfe, 0x7e9d3d10, + 0x7e9eeca7, 0x7ea09ac2, 0x7ea24762, 0x7ea3f288, 0x7ea59c35, 0x7ea7446a, 0x7ea8eb27, 0x7eaa906c, 0x7eac343c, + 0x7eadd696, 0x7eaf777b, 0x7eb116ed, 0x7eb2b4eb, 0x7eb45177, 0x7eb5ec91, 0x7eb7863b, 0x7eb91e74, 0x7ebab53e, + 0x7ebc4a99, 0x7ebdde87, 0x7ebf7107, 0x7ec1021b, 0x7ec291c3, 0x7ec42001, 0x7ec5acd5, 0x7ec7383f, 0x7ec8c241, + 0x7eca4adb, 0x7ecbd20d, 0x7ecd57da, 0x7ecedc41, 0x7ed05f44, 0x7ed1e0e2, 0x7ed3611d, 0x7ed4dff6, 0x7ed65d6d, + 0x7ed7d983, 0x7ed95438, 0x7edacd8f, 0x7edc4586, 0x7eddbc20, 0x7edf315c, 0x7ee0a53c, 0x7ee217c1, 0x7ee388ea, + 0x7ee4f8b9, 0x7ee6672f, 0x7ee7d44c, 0x7ee94012, 0x7eeaaa80, 0x7eec1397, 0x7eed7b59, 0x7eeee1c6, 0x7ef046df, + 0x7ef1aaa5, 0x7ef30d18, 0x7ef46e39, 0x7ef5ce09, 0x7ef72c88, 0x7ef889b8, 0x7ef9e599, 0x7efb402c, 0x7efc9972, + 0x7efdf16b, 0x7eff4818, 0x7f009d79, 0x7f01f191, 0x7f03445f, 0x7f0495e4, 0x7f05e620, 0x7f073516, 0x7f0882c5, + 0x7f09cf2d, 0x7f0b1a51, 0x7f0c6430, 0x7f0daccc, 0x7f0ef425, 0x7f103a3b, 0x7f117f11, 0x7f12c2a5, 0x7f1404fa, + 0x7f15460f, 0x7f1685e6, 0x7f17c47f, 0x7f1901db, 0x7f1a3dfb, 0x7f1b78e0, 0x7f1cb28a, 0x7f1deafa, 0x7f1f2231, + 0x7f20582f, 0x7f218cf5, 0x7f22c085, 0x7f23f2de, 0x7f252401, 0x7f2653f0, 0x7f2782ab, 0x7f28b032, 0x7f29dc87, + 0x7f2b07aa, 0x7f2c319c, 0x7f2d5a5e, 0x7f2e81f0, 0x7f2fa853, 0x7f30cd88, 0x7f31f18f, 0x7f33146a, 0x7f343619, + 0x7f35569c, 0x7f3675f6, 0x7f379425, 0x7f38b12c, 0x7f39cd0a, 0x7f3ae7c0, 0x7f3c0150, 0x7f3d19ba, 0x7f3e30fe, + 0x7f3f471e, 0x7f405c1a, 0x7f416ff3, 0x7f4282a9, 0x7f43943e, 0x7f44a4b2, 0x7f45b405, 0x7f46c239, 0x7f47cf4e, + 0x7f48db45, 0x7f49e61f, 0x7f4aefdc, 0x7f4bf87e, 0x7f4d0004, 0x7f4e0670, 0x7f4f0bc2, 0x7f500ffb, 0x7f51131c, + 0x7f521525, 0x7f531618, 0x7f5415f4, 0x7f5514bb, 0x7f56126e, 0x7f570f0c, 0x7f580a98, 0x7f590511, 0x7f59fe78, + 0x7f5af6ce, 0x7f5bee14, 0x7f5ce44a, 0x7f5dd972, 0x7f5ecd8b, 0x7f5fc097, 0x7f60b296, 0x7f61a389, 0x7f629370, + 0x7f63824e, 0x7f647021, 0x7f655ceb, 0x7f6648ad, 0x7f673367, 0x7f681d19, 0x7f6905c6, 0x7f69ed6d, 0x7f6ad40f, + 0x7f6bb9ad, 0x7f6c9e48, 0x7f6d81e0, 0x7f6e6475, 0x7f6f460a, 0x7f70269d, 0x7f710631, 0x7f71e4c6, 0x7f72c25c, + 0x7f739ef4, 0x7f747a8f, 0x7f75552e, 0x7f762ed1, 0x7f770779, 0x7f77df27, 0x7f78b5db, 0x7f798b97, 0x7f7a605a, + 0x7f7b3425, 0x7f7c06fa, 0x7f7cd8d9, 0x7f7da9c2, 0x7f7e79b7, 0x7f7f48b8, 0x7f8016c5, 0x7f80e3e0, 0x7f81b009, + 0x7f827b40, 0x7f834588, 0x7f840edf, 0x7f84d747, 0x7f859ec1, 0x7f86654d, 0x7f872aec, 0x7f87ef9e, 0x7f88b365, + 0x7f897641, 0x7f8a3832, 0x7f8af93a, 0x7f8bb959, 0x7f8c7890, 0x7f8d36df, 0x7f8df448, 0x7f8eb0ca, 0x7f8f6c67, + 0x7f90271e, 0x7f90e0f2, 0x7f9199e2, 0x7f9251f0, 0x7f93091b, 0x7f93bf65, 0x7f9474ce, 0x7f952958, 0x7f95dd01, + 0x7f968fcd, 0x7f9741ba, 0x7f97f2ca, 0x7f98a2fd, 0x7f995254, 0x7f9a00d0, 0x7f9aae71, 0x7f9b5b38, 0x7f9c0726, + 0x7f9cb23b, 0x7f9d5c78, 0x7f9e05de, 0x7f9eae6e, 0x7f9f5627, 0x7f9ffd0b, 0x7fa0a31b, 0x7fa14856, 0x7fa1ecbf, + 0x7fa29054, 0x7fa33318, 0x7fa3d50b, 0x7fa4762c, 0x7fa5167e, 0x7fa5b601, 0x7fa654b5, 0x7fa6f29b, 0x7fa78fb3, + 0x7fa82bff, 0x7fa8c77f, 0x7fa96234, 0x7fa9fc1e, 0x7faa953e, 0x7fab2d94, 0x7fabc522, 0x7fac5be8, 0x7facf1e6, + 0x7fad871d, 0x7fae1b8f, 0x7faeaf3b, 0x7faf4222, 0x7fafd445, 0x7fb065a4, 0x7fb0f641, 0x7fb1861b, 0x7fb21534, + 0x7fb2a38c, 0x7fb33124, 0x7fb3bdfb, 0x7fb44a14, 0x7fb4d56f, 0x7fb5600c, 0x7fb5e9ec, 0x7fb6730f, 0x7fb6fb76, + 0x7fb78323, 0x7fb80a15, 0x7fb8904d, 0x7fb915cc, 0x7fb99a92, 0x7fba1ea0, 0x7fbaa1f7, 0x7fbb2497, 0x7fbba681, + 0x7fbc27b5, 0x7fbca835, 0x7fbd2801, 0x7fbda719, 0x7fbe257e, 0x7fbea331, 0x7fbf2032, 0x7fbf9c82, 0x7fc01821, + 0x7fc09311, 0x7fc10d52, 0x7fc186e4, 0x7fc1ffc8, 0x7fc277ff, 0x7fc2ef89, 0x7fc36667, 0x7fc3dc9a, 0x7fc45221, + 0x7fc4c6ff, 0x7fc53b33, 0x7fc5aebe, 0x7fc621a0, 0x7fc693db, 0x7fc7056f, 0x7fc7765c, 0x7fc7e6a3, 0x7fc85645, + 0x7fc8c542, 0x7fc9339b, 0x7fc9a150, 0x7fca0e63, 0x7fca7ad3, 0x7fcae6a2, 0x7fcb51cf, 0x7fcbbc5c, 0x7fcc2649, + 0x7fcc8f97, 0x7fccf846, 0x7fcd6058, 0x7fcdc7cb, 0x7fce2ea2, 0x7fce94dd, 0x7fcefa7b, 0x7fcf5f7f, 0x7fcfc3e8, + 0x7fd027b7, 0x7fd08aed, 0x7fd0ed8b, 0x7fd14f90, 0x7fd1b0fd, 0x7fd211d4, 0x7fd27214, 0x7fd2d1bf, 0x7fd330d4, + 0x7fd38f55, 0x7fd3ed41, 0x7fd44a9a, 0x7fd4a761, 0x7fd50395, 0x7fd55f37, 0x7fd5ba48, 0x7fd614c9, 0x7fd66eba, + 0x7fd6c81b, 0x7fd720ed, 0x7fd77932, 0x7fd7d0e8, 0x7fd82812, 0x7fd87eae, 0x7fd8d4bf, 0x7fd92a45, 0x7fd97f40, + 0x7fd9d3b0, 0x7fda2797, 0x7fda7af5, 0x7fdacdca, 0x7fdb2018, 0x7fdb71dd, 0x7fdbc31c, 0x7fdc13d5, 0x7fdc6408, + 0x7fdcb3b6, 0x7fdd02df, 0x7fdd5184, 0x7fdd9fa5, 0x7fdded44, 0x7fde3a60, 0x7fde86fb, 0x7fded314, 0x7fdf1eac, + 0x7fdf69c4, 0x7fdfb45d, 0x7fdffe76, 0x7fe04811, 0x7fe0912e, 0x7fe0d9ce, 0x7fe121f0, 0x7fe16996, 0x7fe1b0c1, + 0x7fe1f770, 0x7fe23da4, 0x7fe2835f, 0x7fe2c89f, 0x7fe30d67, 0x7fe351b5, 0x7fe3958c, 0x7fe3d8ec, 0x7fe41bd4, + 0x7fe45e46, 0x7fe4a042, 0x7fe4e1c8, 0x7fe522da, 0x7fe56378, 0x7fe5a3a1, 0x7fe5e358, 0x7fe6229b, 0x7fe6616d, + 0x7fe69fcc, 0x7fe6ddbb, 0x7fe71b39, 0x7fe75847, 0x7fe794e5, 0x7fe7d114, 0x7fe80cd5, 0x7fe84827, 0x7fe8830c, + 0x7fe8bd84, 0x7fe8f78f, 0x7fe9312f, 0x7fe96a62, 0x7fe9a32b, 0x7fe9db8a, 0x7fea137e, 0x7fea4b09, 0x7fea822b, + 0x7feab8e5, 0x7feaef37, 0x7feb2521, 0x7feb5aa4, 0x7feb8fc1, 0x7febc478, 0x7febf8ca, 0x7fec2cb6, 0x7fec603e, + 0x7fec9363, 0x7fecc623, 0x7fecf881, 0x7fed2a7c, 0x7fed5c16, 0x7fed8d4e, 0x7fedbe24, 0x7fedee9b, 0x7fee1eb1, + 0x7fee4e68, 0x7fee7dc0, 0x7feeacb9, 0x7feedb54, 0x7fef0991, 0x7fef3771, 0x7fef64f5, 0x7fef921d, 0x7fefbee8, + 0x7fefeb59, 0x7ff0176f, 0x7ff0432a, 0x7ff06e8c, 0x7ff09995, 0x7ff0c444, 0x7ff0ee9c, 0x7ff1189b, 0x7ff14243, + 0x7ff16b94, 0x7ff1948e, 0x7ff1bd32, 0x7ff1e581, 0x7ff20d7b, 0x7ff2351f, 0x7ff25c70, 0x7ff2836d, 0x7ff2aa17, + 0x7ff2d06d, 0x7ff2f672, 0x7ff31c24, 0x7ff34185, 0x7ff36695, 0x7ff38b55, 0x7ff3afc4, 0x7ff3d3e4, 0x7ff3f7b4, + 0x7ff41b35, 0x7ff43e69, 0x7ff4614e, 0x7ff483e6, 0x7ff4a631, 0x7ff4c82f, 0x7ff4e9e1, 0x7ff50b47, 0x7ff52c62, + 0x7ff54d33, 0x7ff56db9, 0x7ff58df5, 0x7ff5ade7, 0x7ff5cd90, 0x7ff5ecf1, 0x7ff60c09, 0x7ff62ada, 0x7ff64963, + 0x7ff667a5, 0x7ff685a1, 0x7ff6a357, 0x7ff6c0c7, 0x7ff6ddf1, 0x7ff6fad7, 0x7ff71778, 0x7ff733d6, 0x7ff74fef, + 0x7ff76bc6, 0x7ff78759, 0x7ff7a2ab, 0x7ff7bdba, 0x7ff7d888, 0x7ff7f315, 0x7ff80d61, 0x7ff8276c, 0x7ff84138, + 0x7ff85ac4, 0x7ff87412, 0x7ff88d20, 0x7ff8a5f0, 0x7ff8be82, 0x7ff8d6d7, 0x7ff8eeef, 0x7ff906c9, 0x7ff91e68, + 0x7ff935cb, 0x7ff94cf2, 0x7ff963dd, 0x7ff97a8f, 0x7ff99105, 0x7ff9a742, 0x7ff9bd45, 0x7ff9d30f, 0x7ff9e8a0, + 0x7ff9fdf9, 0x7ffa131a, 0x7ffa2803, 0x7ffa3cb4, 0x7ffa512f, 0x7ffa6573, 0x7ffa7981, 0x7ffa8d59, 0x7ffaa0fc, + 0x7ffab46a, 0x7ffac7a3, 0x7ffadaa8, 0x7ffaed78, 0x7ffb0015, 0x7ffb127f, 0x7ffb24b6, 0x7ffb36bb, 0x7ffb488d, + 0x7ffb5a2e, 0x7ffb6b9d, 0x7ffb7cdb, 0x7ffb8de9, 0x7ffb9ec6, 0x7ffbaf73, 0x7ffbbff1, 0x7ffbd03f, 0x7ffbe05e, + 0x7ffbf04f, 0x7ffc0012, 0x7ffc0fa6, 0x7ffc1f0d, 0x7ffc2e47, 0x7ffc3d54, 0x7ffc4c35, 0x7ffc5ae9, 0x7ffc6971, + 0x7ffc77ce, 0x7ffc8600, 0x7ffc9407, 0x7ffca1e4, 0x7ffcaf96, 0x7ffcbd1f, 0x7ffcca7e, 0x7ffcd7b4, 0x7ffce4c1, + 0x7ffcf1a5, 0x7ffcfe62, 0x7ffd0af6, 0x7ffd1763, 0x7ffd23a9, 0x7ffd2fc8, 0x7ffd3bc1, 0x7ffd4793, 0x7ffd533f, + 0x7ffd5ec5, 0x7ffd6a27, 0x7ffd7563, 0x7ffd807a, 0x7ffd8b6e, 0x7ffd963d, 0x7ffda0e8, 0x7ffdab70, 0x7ffdb5d5, + 0x7ffdc017, 0x7ffdca36, 0x7ffdd434, 0x7ffdde0f, 0x7ffde7c9, 0x7ffdf161, 0x7ffdfad8, 0x7ffe042f, 0x7ffe0d65, + 0x7ffe167b, 0x7ffe1f71, 0x7ffe2848, 0x7ffe30ff, 0x7ffe3997, 0x7ffe4211, 0x7ffe4a6c, 0x7ffe52a9, 0x7ffe5ac8, + 0x7ffe62c9, 0x7ffe6aae, 0x7ffe7275, 0x7ffe7a1f, 0x7ffe81ad, 0x7ffe891f, 0x7ffe9075, 0x7ffe97b0, 0x7ffe9ece, + 0x7ffea5d2, 0x7ffeacbb, 0x7ffeb38a, 0x7ffeba3e, 0x7ffec0d8, 0x7ffec758, 0x7ffecdbf, 0x7ffed40d, 0x7ffeda41, + 0x7ffee05d, 0x7ffee660, 0x7ffeec4b, 0x7ffef21f, 0x7ffef7da, 0x7ffefd7e, 0x7fff030b, 0x7fff0881, 0x7fff0de0, + 0x7fff1328, 0x7fff185b, 0x7fff1d77, 0x7fff227e, 0x7fff276f, 0x7fff2c4b, 0x7fff3112, 0x7fff35c4, 0x7fff3a62, + 0x7fff3eeb, 0x7fff4360, 0x7fff47c2, 0x7fff4c0f, 0x7fff504a, 0x7fff5471, 0x7fff5885, 0x7fff5c87, 0x7fff6076, + 0x7fff6452, 0x7fff681d, 0x7fff6bd6, 0x7fff6f7d, 0x7fff7313, 0x7fff7698, 0x7fff7a0c, 0x7fff7d6f, 0x7fff80c2, + 0x7fff8404, 0x7fff8736, 0x7fff8a58, 0x7fff8d6b, 0x7fff906e, 0x7fff9362, 0x7fff9646, 0x7fff991c, 0x7fff9be3, + 0x7fff9e9c, 0x7fffa146, 0x7fffa3e2, 0x7fffa671, 0x7fffa8f1, 0x7fffab65, 0x7fffadca, 0x7fffb023, 0x7fffb26f, + 0x7fffb4ae, 0x7fffb6e0, 0x7fffb906, 0x7fffbb20, 0x7fffbd2e, 0x7fffbf30, 0x7fffc126, 0x7fffc311, 0x7fffc4f1, + 0x7fffc6c5, 0x7fffc88f, 0x7fffca4d, 0x7fffcc01, 0x7fffcdab, 0x7fffcf4a, 0x7fffd0e0, 0x7fffd26b, 0x7fffd3ec, + 0x7fffd564, 0x7fffd6d2, 0x7fffd838, 0x7fffd993, 0x7fffdae6, 0x7fffdc31, 0x7fffdd72, 0x7fffdeab, 0x7fffdfdb, + 0x7fffe104, 0x7fffe224, 0x7fffe33c, 0x7fffe44d, 0x7fffe556, 0x7fffe657, 0x7fffe751, 0x7fffe844, 0x7fffe930, + 0x7fffea15, 0x7fffeaf3, 0x7fffebca, 0x7fffec9b, 0x7fffed66, 0x7fffee2a, 0x7fffeee8, 0x7fffefa0, 0x7ffff053, + 0x7ffff0ff, 0x7ffff1a6, 0x7ffff247, 0x7ffff2e4, 0x7ffff37a, 0x7ffff40c, 0x7ffff499, 0x7ffff520, 0x7ffff5a3, + 0x7ffff621, 0x7ffff69b, 0x7ffff710, 0x7ffff781, 0x7ffff7ee, 0x7ffff857, 0x7ffff8bb, 0x7ffff91c, 0x7ffff979, + 0x7ffff9d2, 0x7ffffa27, 0x7ffffa79, 0x7ffffac8, 0x7ffffb13, 0x7ffffb5b, 0x7ffffba0, 0x7ffffbe2, 0x7ffffc21, + 0x7ffffc5d, 0x7ffffc96, 0x7ffffccd, 0x7ffffd01, 0x7ffffd32, 0x7ffffd61, 0x7ffffd8e, 0x7ffffdb8, 0x7ffffde0, + 0x7ffffe07, 0x7ffffe2b, 0x7ffffe4d, 0x7ffffe6d, 0x7ffffe8b, 0x7ffffea8, 0x7ffffec3, 0x7ffffedc, 0x7ffffef4, + 0x7fffff0a, 0x7fffff1f, 0x7fffff33, 0x7fffff45, 0x7fffff56, 0x7fffff66, 0x7fffff75, 0x7fffff82, 0x7fffff8f, + 0x7fffff9a, 0x7fffffa5, 0x7fffffaf, 0x7fffffb8, 0x7fffffc0, 0x7fffffc8, 0x7fffffce, 0x7fffffd5, 0x7fffffda, + 0x7fffffdf, 0x7fffffe4, 0x7fffffe8, 0x7fffffeb, 0x7fffffef, 0x7ffffff1, 0x7ffffff4, 0x7ffffff6, 0x7ffffff8, + 0x7ffffff9, 0x7ffffffb, 0x7ffffffc, 0x7ffffffd, 0x7ffffffd, 0x7ffffffe, 0x7fffffff, 0x7fffffff, 0x7fffffff, + 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, + 0x7fffffff, +}; + +/* {sin(2*i*PI/4096, cos(2*i*PI/4096}, with i = 0 to 512 */ +const int32_t sincos_lookup0[1026] = { + 0x00000000, 0x7fffffff, 0x003243f5, 0x7ffff621, 0x006487e3, 0x7fffd886, 0x0096cbc1, 0x7fffa72c, 0x00c90f88, + 0x7fff6216, 0x00fb5330, 0x7fff0943, 0x012d96b1, 0x7ffe9cb2, 0x015fda03, 0x7ffe1c65, 0x01921d20, 0x7ffd885a, + 0x01c45ffe, 0x7ffce093, 0x01f6a297, 0x7ffc250f, 0x0228e4e2, 0x7ffb55ce, 0x025b26d7, 0x7ffa72d1, 0x028d6870, + 0x7ff97c18, 0x02bfa9a4, 0x7ff871a2, 0x02f1ea6c, 0x7ff75370, 0x03242abf, 0x7ff62182, 0x03566a96, 0x7ff4dbd9, + 0x0388a9ea, 0x7ff38274, 0x03bae8b2, 0x7ff21553, 0x03ed26e6, 0x7ff09478, 0x041f6480, 0x7feeffe1, 0x0451a177, + 0x7fed5791, 0x0483ddc3, 0x7feb9b85, 0x04b6195d, 0x7fe9cbc0, 0x04e8543e, 0x7fe7e841, 0x051a8e5c, 0x7fe5f108, + 0x054cc7b1, 0x7fe3e616, 0x057f0035, 0x7fe1c76b, 0x05b137df, 0x7fdf9508, 0x05e36ea9, 0x7fdd4eec, 0x0615a48b, + 0x7fdaf519, 0x0647d97c, 0x7fd8878e, 0x067a0d76, 0x7fd6064c, 0x06ac406f, 0x7fd37153, 0x06de7262, 0x7fd0c8a3, + 0x0710a345, 0x7fce0c3e, 0x0742d311, 0x7fcb3c23, 0x077501be, 0x7fc85854, 0x07a72f45, 0x7fc560cf, 0x07d95b9e, + 0x7fc25596, 0x080b86c2, 0x7fbf36aa, 0x083db0a7, 0x7fbc040a, 0x086fd947, 0x7fb8bdb8, 0x08a2009a, 0x7fb563b3, + 0x08d42699, 0x7fb1f5fc, 0x09064b3a, 0x7fae7495, 0x09386e78, 0x7faadf7c, 0x096a9049, 0x7fa736b4, 0x099cb0a7, + 0x7fa37a3c, 0x09cecf89, 0x7f9faa15, 0x0a00ece8, 0x7f9bc640, 0x0a3308bd, 0x7f97cebd, 0x0a6522fe, 0x7f93c38c, + 0x0a973ba5, 0x7f8fa4b0, 0x0ac952aa, 0x7f8b7227, 0x0afb6805, 0x7f872bf3, 0x0b2d7baf, 0x7f82d214, 0x0b5f8d9f, + 0x7f7e648c, 0x0b919dcf, 0x7f79e35a, 0x0bc3ac35, 0x7f754e80, 0x0bf5b8cb, 0x7f70a5fe, 0x0c27c389, 0x7f6be9d4, + 0x0c59cc68, 0x7f671a05, 0x0c8bd35e, 0x7f62368f, 0x0cbdd865, 0x7f5d3f75, 0x0cefdb76, 0x7f5834b7, 0x0d21dc87, + 0x7f531655, 0x0d53db92, 0x7f4de451, 0x0d85d88f, 0x7f489eaa, 0x0db7d376, 0x7f434563, 0x0de9cc40, 0x7f3dd87c, + 0x0e1bc2e4, 0x7f3857f6, 0x0e4db75b, 0x7f32c3d1, 0x0e7fa99e, 0x7f2d1c0e, 0x0eb199a4, 0x7f2760af, 0x0ee38766, + 0x7f2191b4, 0x0f1572dc, 0x7f1baf1e, 0x0f475bff, 0x7f15b8ee, 0x0f7942c7, 0x7f0faf25, 0x0fab272b, 0x7f0991c4, + 0x0fdd0926, 0x7f0360cb, 0x100ee8ad, 0x7efd1c3c, 0x1040c5bb, 0x7ef6c418, 0x1072a048, 0x7ef05860, 0x10a4784b, + 0x7ee9d914, 0x10d64dbd, 0x7ee34636, 0x11082096, 0x7edc9fc6, 0x1139f0cf, 0x7ed5e5c6, 0x116bbe60, 0x7ecf1837, + 0x119d8941, 0x7ec8371a, 0x11cf516a, 0x7ec14270, 0x120116d5, 0x7eba3a39, 0x1232d979, 0x7eb31e78, 0x1264994e, + 0x7eabef2c, 0x1296564d, 0x7ea4ac58, 0x12c8106f, 0x7e9d55fc, 0x12f9c7aa, 0x7e95ec1a, 0x132b7bf9, 0x7e8e6eb2, + 0x135d2d53, 0x7e86ddc6, 0x138edbb1, 0x7e7f3957, 0x13c0870a, 0x7e778166, 0x13f22f58, 0x7e6fb5f4, 0x1423d492, + 0x7e67d703, 0x145576b1, 0x7e5fe493, 0x148715ae, 0x7e57dea7, 0x14b8b17f, 0x7e4fc53e, 0x14ea4a1f, 0x7e47985b, + 0x151bdf86, 0x7e3f57ff, 0x154d71aa, 0x7e37042a, 0x157f0086, 0x7e2e9cdf, 0x15b08c12, 0x7e26221f, 0x15e21445, + 0x7e1d93ea, 0x16139918, 0x7e14f242, 0x16451a83, 0x7e0c3d29, 0x1676987f, 0x7e0374a0, 0x16a81305, 0x7dfa98a8, + 0x16d98a0c, 0x7df1a942, 0x170afd8d, 0x7de8a670, 0x173c6d80, 0x7ddf9034, 0x176dd9de, 0x7dd6668f, 0x179f429f, + 0x7dcd2981, 0x17d0a7bc, 0x7dc3d90d, 0x1802092c, 0x7dba7534, 0x183366e9, 0x7db0fdf8, 0x1864c0ea, 0x7da77359, + 0x18961728, 0x7d9dd55a, 0x18c7699b, 0x7d9423fc, 0x18f8b83c, 0x7d8a5f40, 0x192a0304, 0x7d808728, 0x195b49ea, + 0x7d769bb5, 0x198c8ce7, 0x7d6c9ce9, 0x19bdcbf3, 0x7d628ac6, 0x19ef0707, 0x7d58654d, 0x1a203e1b, 0x7d4e2c7f, + 0x1a517128, 0x7d43e05e, 0x1a82a026, 0x7d3980ec, 0x1ab3cb0d, 0x7d2f0e2b, 0x1ae4f1d6, 0x7d24881b, 0x1b161479, + 0x7d19eebf, 0x1b4732ef, 0x7d0f4218, 0x1b784d30, 0x7d048228, 0x1ba96335, 0x7cf9aef0, 0x1bda74f6, 0x7ceec873, + 0x1c0b826a, 0x7ce3ceb2, 0x1c3c8b8c, 0x7cd8c1ae, 0x1c6d9053, 0x7ccda169, 0x1c9e90b8, 0x7cc26de5, 0x1ccf8cb3, + 0x7cb72724, 0x1d00843d, 0x7cabcd28, 0x1d31774d, 0x7ca05ff1, 0x1d6265dd, 0x7c94df83, 0x1d934fe5, 0x7c894bde, + 0x1dc4355e, 0x7c7da505, 0x1df5163f, 0x7c71eaf9, 0x1e25f282, 0x7c661dbc, 0x1e56ca1e, 0x7c5a3d50, 0x1e879d0d, + 0x7c4e49b7, 0x1eb86b46, 0x7c4242f2, 0x1ee934c3, 0x7c362904, 0x1f19f97b, 0x7c29fbee, 0x1f4ab968, 0x7c1dbbb3, + 0x1f7b7481, 0x7c116853, 0x1fac2abf, 0x7c0501d2, 0x1fdcdc1b, 0x7bf88830, 0x200d888d, 0x7bebfb70, 0x203e300d, + 0x7bdf5b94, 0x206ed295, 0x7bd2a89e, 0x209f701c, 0x7bc5e290, 0x20d0089c, 0x7bb9096b, 0x21009c0c, 0x7bac1d31, + 0x21312a65, 0x7b9f1de6, 0x2161b3a0, 0x7b920b89, 0x219237b5, 0x7b84e61f, 0x21c2b69c, 0x7b77ada8, 0x21f3304f, + 0x7b6a6227, 0x2223a4c5, 0x7b5d039e, 0x225413f8, 0x7b4f920e, 0x22847de0, 0x7b420d7a, 0x22b4e274, 0x7b3475e5, + 0x22e541af, 0x7b26cb4f, 0x23159b88, 0x7b190dbc, 0x2345eff8, 0x7b0b3d2c, 0x23763ef7, 0x7afd59a4, 0x23a6887f, + 0x7aef6323, 0x23d6cc87, 0x7ae159ae, 0x24070b08, 0x7ad33d45, 0x243743fa, 0x7ac50dec, 0x24677758, 0x7ab6cba4, + 0x2497a517, 0x7aa8766f, 0x24c7cd33, 0x7a9a0e50, 0x24f7efa2, 0x7a8b9348, 0x25280c5e, 0x7a7d055b, 0x2558235f, + 0x7a6e648a, 0x2588349d, 0x7a5fb0d8, 0x25b84012, 0x7a50ea47, 0x25e845b6, 0x7a4210d8, 0x26184581, 0x7a332490, + 0x26483f6c, 0x7a24256f, 0x26783370, 0x7a151378, 0x26a82186, 0x7a05eead, 0x26d809a5, 0x79f6b711, 0x2707ebc7, + 0x79e76ca7, 0x2737c7e3, 0x79d80f6f, 0x27679df4, 0x79c89f6e, 0x27976df1, 0x79b91ca4, 0x27c737d3, 0x79a98715, + 0x27f6fb92, 0x7999dec4, 0x2826b928, 0x798a23b1, 0x2856708d, 0x797a55e0, 0x288621b9, 0x796a7554, 0x28b5cca5, + 0x795a820e, 0x28e5714b, 0x794a7c12, 0x29150fa1, 0x793a6361, 0x2944a7a2, 0x792a37fe, 0x29743946, 0x7919f9ec, + 0x29a3c485, 0x7909a92d, 0x29d34958, 0x78f945c3, 0x2a02c7b8, 0x78e8cfb2, 0x2a323f9e, 0x78d846fb, 0x2a61b101, + 0x78c7aba2, 0x2a911bdc, 0x78b6fda8, 0x2ac08026, 0x78a63d11, 0x2aefddd8, 0x789569df, 0x2b1f34eb, 0x78848414, + 0x2b4e8558, 0x78738bb3, 0x2b7dcf17, 0x786280bf, 0x2bad1221, 0x7851633b, 0x2bdc4e6f, 0x78403329, 0x2c0b83fa, + 0x782ef08b, 0x2c3ab2b9, 0x781d9b65, 0x2c69daa6, 0x780c33b8, 0x2c98fbba, 0x77fab989, 0x2cc815ee, 0x77e92cd9, + 0x2cf72939, 0x77d78daa, 0x2d263596, 0x77c5dc01, 0x2d553afc, 0x77b417df, 0x2d843964, 0x77a24148, 0x2db330c7, + 0x7790583e, 0x2de2211e, 0x777e5cc3, 0x2e110a62, 0x776c4edb, 0x2e3fec8b, 0x775a2e89, 0x2e6ec792, 0x7747fbce, + 0x2e9d9b70, 0x7735b6af, 0x2ecc681e, 0x77235f2d, 0x2efb2d95, 0x7710f54c, 0x2f29ebcc, 0x76fe790e, 0x2f58a2be, + 0x76ebea77, 0x2f875262, 0x76d94989, 0x2fb5fab2, 0x76c69647, 0x2fe49ba7, 0x76b3d0b4, 0x30133539, 0x76a0f8d2, + 0x3041c761, 0x768e0ea6, 0x30705217, 0x767b1231, 0x309ed556, 0x76680376, 0x30cd5115, 0x7654e279, 0x30fbc54d, + 0x7641af3d, 0x312a31f8, 0x762e69c4, 0x3158970e, 0x761b1211, 0x3186f487, 0x7607a828, 0x31b54a5e, 0x75f42c0b, + 0x31e39889, 0x75e09dbd, 0x3211df04, 0x75ccfd42, 0x32401dc6, 0x75b94a9c, 0x326e54c7, 0x75a585cf, 0x329c8402, + 0x7591aedd, 0x32caab6f, 0x757dc5ca, 0x32f8cb07, 0x7569ca99, 0x3326e2c3, 0x7555bd4c, 0x3354f29b, 0x75419de7, + 0x3382fa88, 0x752d6c6c, 0x33b0fa84, 0x751928e0, 0x33def287, 0x7504d345, 0x340ce28b, 0x74f06b9e, 0x343aca87, + 0x74dbf1ef, 0x3468aa76, 0x74c7663a, 0x34968250, 0x74b2c884, 0x34c4520d, 0x749e18cd, 0x34f219a8, 0x7489571c, + 0x351fd918, 0x74748371, 0x354d9057, 0x745f9dd1, 0x357b3f5d, 0x744aa63f, 0x35a8e625, 0x74359cbd, 0x35d684a6, + 0x74208150, 0x36041ad9, 0x740b53fb, 0x3631a8b8, 0x73f614c0, 0x365f2e3b, 0x73e0c3a3, 0x368cab5c, 0x73cb60a8, + 0x36ba2014, 0x73b5ebd1, 0x36e78c5b, 0x73a06522, 0x3714f02a, 0x738acc9e, 0x37424b7b, 0x73752249, 0x376f9e46, + 0x735f6626, 0x379ce885, 0x73499838, 0x37ca2a30, 0x7333b883, 0x37f76341, 0x731dc70a, 0x382493b0, 0x7307c3d0, + 0x3851bb77, 0x72f1aed9, 0x387eda8e, 0x72db8828, 0x38abf0ef, 0x72c54fc1, 0x38d8fe93, 0x72af05a7, 0x39060373, + 0x7298a9dd, 0x3932ff87, 0x72823c67, 0x395ff2c9, 0x726bbd48, 0x398cdd32, 0x72552c85, 0x39b9bebc, 0x723e8a20, + 0x39e6975e, 0x7227d61c, 0x3a136712, 0x7211107e, 0x3a402dd2, 0x71fa3949, 0x3a6ceb96, 0x71e35080, 0x3a99a057, + 0x71cc5626, 0x3ac64c0f, 0x71b54a41, 0x3af2eeb7, 0x719e2cd2, 0x3b1f8848, 0x7186fdde, 0x3b4c18ba, 0x716fbd68, + 0x3b78a007, 0x71586b74, 0x3ba51e29, 0x71410805, 0x3bd19318, 0x7129931f, 0x3bfdfecd, 0x71120cc5, 0x3c2a6142, + 0x70fa74fc, 0x3c56ba70, 0x70e2cbc6, 0x3c830a50, 0x70cb1128, 0x3caf50da, 0x70b34525, 0x3cdb8e09, 0x709b67c0, + 0x3d07c1d6, 0x708378ff, 0x3d33ec39, 0x706b78e3, 0x3d600d2c, 0x70536771, 0x3d8c24a8, 0x703b44ad, 0x3db832a6, + 0x7023109a, 0x3de4371f, 0x700acb3c, 0x3e10320d, 0x6ff27497, 0x3e3c2369, 0x6fda0cae, 0x3e680b2c, 0x6fc19385, + 0x3e93e950, 0x6fa90921, 0x3ebfbdcd, 0x6f906d84, 0x3eeb889c, 0x6f77c0b3, 0x3f1749b8, 0x6f5f02b2, 0x3f430119, + 0x6f463383, 0x3f6eaeb8, 0x6f2d532c, 0x3f9a5290, 0x6f1461b0, 0x3fc5ec98, 0x6efb5f12, 0x3ff17cca, 0x6ee24b57, + 0x401d0321, 0x6ec92683, 0x40487f94, 0x6eaff099, 0x4073f21d, 0x6e96a99d, 0x409f5ab6, 0x6e7d5193, 0x40cab958, + 0x6e63e87f, 0x40f60dfb, 0x6e4a6e66, 0x4121589b, 0x6e30e34a, 0x414c992f, 0x6e174730, 0x4177cfb1, 0x6dfd9a1c, + 0x41a2fc1a, 0x6de3dc11, 0x41ce1e65, 0x6dca0d14, 0x41f93689, 0x6db02d29, 0x42244481, 0x6d963c54, 0x424f4845, + 0x6d7c3a98, 0x427a41d0, 0x6d6227fa, 0x42a5311b, 0x6d48047e, 0x42d0161e, 0x6d2dd027, 0x42faf0d4, 0x6d138afb, + 0x4325c135, 0x6cf934fc, 0x4350873c, 0x6cdece2f, 0x437b42e1, 0x6cc45698, 0x43a5f41e, 0x6ca9ce3b, 0x43d09aed, + 0x6c8f351c, 0x43fb3746, 0x6c748b3f, 0x4425c923, 0x6c59d0a9, 0x4450507e, 0x6c3f055d, 0x447acd50, 0x6c242960, + 0x44a53f93, 0x6c093cb6, 0x44cfa740, 0x6bee3f62, 0x44fa0450, 0x6bd3316a, 0x452456bd, 0x6bb812d1, 0x454e9e80, + 0x6b9ce39b, 0x4578db93, 0x6b81a3cd, 0x45a30df0, 0x6b66536b, 0x45cd358f, 0x6b4af279, 0x45f7526b, 0x6b2f80fb, + 0x4621647d, 0x6b13fef5, 0x464b6bbe, 0x6af86c6c, 0x46756828, 0x6adcc964, 0x469f59b4, 0x6ac115e2, 0x46c9405c, + 0x6aa551e9, 0x46f31c1a, 0x6a897d7d, 0x471cece7, 0x6a6d98a4, 0x4746b2bc, 0x6a51a361, 0x47706d93, 0x6a359db9, + 0x479a1d67, 0x6a1987b0, 0x47c3c22f, 0x69fd614a, 0x47ed5be6, 0x69e12a8c, 0x4816ea86, 0x69c4e37a, 0x48406e08, + 0x69a88c19, 0x4869e665, 0x698c246c, 0x48935397, 0x696fac78, 0x48bcb599, 0x69532442, 0x48e60c62, 0x69368bce, + 0x490f57ee, 0x6919e320, 0x49389836, 0x68fd2a3d, 0x4961cd33, 0x68e06129, 0x498af6df, 0x68c387e9, 0x49b41533, + 0x68a69e81, 0x49dd282a, 0x6889a4f6, 0x4a062fbd, 0x686c9b4b, 0x4a2f2be6, 0x684f8186, 0x4a581c9e, 0x683257ab, + 0x4a8101de, 0x68151dbe, 0x4aa9dba2, 0x67f7d3c5, 0x4ad2a9e2, 0x67da79c3, 0x4afb6c98, 0x67bd0fbd, 0x4b2423be, + 0x679f95b7, 0x4b4ccf4d, 0x67820bb7, 0x4b756f40, 0x676471c0, 0x4b9e0390, 0x6746c7d8, 0x4bc68c36, 0x67290e02, + 0x4bef092d, 0x670b4444, 0x4c177a6e, 0x66ed6aa1, 0x4c3fdff4, 0x66cf8120, 0x4c6839b7, 0x66b187c3, 0x4c9087b1, + 0x66937e91, 0x4cb8c9dd, 0x6675658c, 0x4ce10034, 0x66573cbb, 0x4d092ab0, 0x66390422, 0x4d31494b, 0x661abbc5, + 0x4d595bfe, 0x65fc63a9, 0x4d8162c4, 0x65ddfbd3, 0x4da95d96, 0x65bf8447, 0x4dd14c6e, 0x65a0fd0b, 0x4df92f46, + 0x65826622, 0x4e210617, 0x6563bf92, 0x4e48d0dd, 0x6545095f, 0x4e708f8f, 0x6526438f, 0x4e984229, 0x65076e25, + 0x4ebfe8a5, 0x64e88926, 0x4ee782fb, 0x64c99498, 0x4f0f1126, 0x64aa907f, 0x4f369320, 0x648b7ce0, 0x4f5e08e3, + 0x646c59bf, 0x4f857269, 0x644d2722, 0x4faccfab, 0x642de50d, 0x4fd420a4, 0x640e9386, 0x4ffb654d, 0x63ef3290, + 0x50229da1, 0x63cfc231, 0x5049c999, 0x63b0426d, 0x5070e92f, 0x6390b34a, 0x5097fc5e, 0x637114cc, 0x50bf031f, + 0x635166f9, 0x50e5fd6d, 0x6331a9d4, 0x510ceb40, 0x6311dd64, 0x5133cc94, 0x62f201ac, 0x515aa162, 0x62d216b3, + 0x518169a5, 0x62b21c7b, 0x51a82555, 0x6292130c, 0x51ced46e, 0x6271fa69, 0x51f576ea, 0x6251d298, 0x521c0cc2, + 0x62319b9d, 0x524295f0, 0x6211557e, 0x5269126e, 0x61f1003f, 0x528f8238, 0x61d09be5, 0x52b5e546, 0x61b02876, + 0x52dc3b92, 0x618fa5f7, 0x53028518, 0x616f146c, 0x5328c1d0, 0x614e73da, 0x534ef1b5, 0x612dc447, 0x537514c2, + 0x610d05b7, 0x539b2af0, 0x60ec3830, 0x53c13439, 0x60cb5bb7, 0x53e73097, 0x60aa7050, 0x540d2005, 0x60897601, + 0x5433027d, 0x60686ccf, 0x5458d7f9, 0x604754bf, 0x547ea073, 0x60262dd6, 0x54a45be6, 0x6004f819, 0x54ca0a4b, + 0x5fe3b38d, 0x54efab9c, 0x5fc26038, 0x55153fd4, 0x5fa0fe1f, 0x553ac6ee, 0x5f7f8d46, 0x556040e2, 0x5f5e0db3, + 0x5585adad, 0x5f3c7f6b, 0x55ab0d46, 0x5f1ae274, 0x55d05faa, 0x5ef936d1, 0x55f5a4d2, 0x5ed77c8a, 0x561adcb9, + 0x5eb5b3a2, 0x56400758, 0x5e93dc1f, 0x566524aa, 0x5e71f606, 0x568a34a9, 0x5e50015d, 0x56af3750, 0x5e2dfe29, + 0x56d42c99, 0x5e0bec6e, 0x56f9147e, 0x5de9cc33, 0x571deefa, 0x5dc79d7c, 0x5742bc06, 0x5da5604f, 0x57677b9d, + 0x5d8314b1, 0x578c2dba, 0x5d60baa7, 0x57b0d256, 0x5d3e5237, 0x57d5696d, 0x5d1bdb65, 0x57f9f2f8, 0x5cf95638, + 0x581e6ef1, 0x5cd6c2b5, 0x5842dd54, 0x5cb420e0, 0x58673e1b, 0x5c9170bf, 0x588b9140, 0x5c6eb258, 0x58afd6bd, + 0x5c4be5b0, 0x58d40e8c, 0x5c290acc, 0x58f838a9, 0x5c0621b2, 0x591c550e, 0x5be32a67, 0x594063b5, 0x5bc024f0, + 0x59646498, 0x5b9d1154, 0x598857b2, 0x5b79ef96, 0x59ac3cfd, 0x5b56bfbd, 0x59d01475, 0x5b3381ce, 0x59f3de12, + 0x5b1035cf, 0x5a1799d1, 0x5aecdbc5, 0x5a3b47ab, 0x5ac973b5, 0x5a5ee79a, 0x5aa5fda5, 0x5a82799a, 0x5a82799a}; + +/* {sin((2*i+1*PI/4096, cos((2*i+1*PI/4096}, with i = 0 to 511 */ +const int32_t sincos_lookup1[1024] = { + 0x001921fb, 0x7ffffd88, 0x004b65ee, 0x7fffe9cb, 0x007da9d4, 0x7fffc251, 0x00afeda8, 0x7fff8719, 0x00e23160, + 0x7fff3824, 0x011474f6, 0x7ffed572, 0x0146b860, 0x7ffe5f03, 0x0178fb99, 0x7ffdd4d7, 0x01ab3e97, 0x7ffd36ee, + 0x01dd8154, 0x7ffc8549, 0x020fc3c6, 0x7ffbbfe6, 0x024205e8, 0x7ffae6c7, 0x027447b0, 0x7ff9f9ec, 0x02a68917, + 0x7ff8f954, 0x02d8ca16, 0x7ff7e500, 0x030b0aa4, 0x7ff6bcf0, 0x033d4abb, 0x7ff58125, 0x036f8a51, 0x7ff4319d, + 0x03a1c960, 0x7ff2ce5b, 0x03d407df, 0x7ff1575d, 0x040645c7, 0x7fefcca4, 0x04388310, 0x7fee2e30, 0x046abfb3, + 0x7fec7c02, 0x049cfba7, 0x7feab61a, 0x04cf36e5, 0x7fe8dc78, 0x05017165, 0x7fe6ef1c, 0x0533ab20, 0x7fe4ee06, + 0x0565e40d, 0x7fe2d938, 0x05981c26, 0x7fe0b0b1, 0x05ca5361, 0x7fde7471, 0x05fc89b8, 0x7fdc247a, 0x062ebf22, + 0x7fd9c0ca, 0x0660f398, 0x7fd74964, 0x06932713, 0x7fd4be46, 0x06c5598a, 0x7fd21f72, 0x06f78af6, 0x7fcf6ce8, + 0x0729bb4e, 0x7fcca6a7, 0x075bea8c, 0x7fc9ccb2, 0x078e18a7, 0x7fc6df08, 0x07c04598, 0x7fc3dda9, 0x07f27157, + 0x7fc0c896, 0x08249bdd, 0x7fbd9fd0, 0x0856c520, 0x7fba6357, 0x0888ed1b, 0x7fb7132b, 0x08bb13c5, 0x7fb3af4e, + 0x08ed3916, 0x7fb037bf, 0x091f5d06, 0x7facac7f, 0x09517f8f, 0x7fa90d8e, 0x0983a0a7, 0x7fa55aee, 0x09b5c048, + 0x7fa1949e, 0x09e7de6a, 0x7f9dbaa0, 0x0a19fb04, 0x7f99ccf4, 0x0a4c1610, 0x7f95cb9a, 0x0a7e2f85, 0x7f91b694, + 0x0ab0475c, 0x7f8d8de1, 0x0ae25d8d, 0x7f895182, 0x0b147211, 0x7f850179, 0x0b4684df, 0x7f809dc5, 0x0b7895f0, + 0x7f7c2668, 0x0baaa53b, 0x7f779b62, 0x0bdcb2bb, 0x7f72fcb4, 0x0c0ebe66, 0x7f6e4a5e, 0x0c40c835, 0x7f698461, + 0x0c72d020, 0x7f64aabf, 0x0ca4d620, 0x7f5fbd77, 0x0cd6da2d, 0x7f5abc8a, 0x0d08dc3f, 0x7f55a7fa, 0x0d3adc4e, + 0x7f507fc7, 0x0d6cda53, 0x7f4b43f2, 0x0d9ed646, 0x7f45f47b, 0x0dd0d01f, 0x7f409164, 0x0e02c7d7, 0x7f3b1aad, + 0x0e34bd66, 0x7f359057, 0x0e66b0c3, 0x7f2ff263, 0x0e98a1e9, 0x7f2a40d2, 0x0eca90ce, 0x7f247ba5, 0x0efc7d6b, + 0x7f1ea2dc, 0x0f2e67b8, 0x7f18b679, 0x0f604faf, 0x7f12b67c, 0x0f923546, 0x7f0ca2e7, 0x0fc41876, 0x7f067bba, + 0x0ff5f938, 0x7f0040f6, 0x1027d784, 0x7ef9f29d, 0x1059b352, 0x7ef390ae, 0x108b8c9b, 0x7eed1b2c, 0x10bd6356, + 0x7ee69217, 0x10ef377d, 0x7edff570, 0x11210907, 0x7ed94538, 0x1152d7ed, 0x7ed28171, 0x1184a427, 0x7ecbaa1a, + 0x11b66dad, 0x7ec4bf36, 0x11e83478, 0x7ebdc0c6, 0x1219f880, 0x7eb6aeca, 0x124bb9be, 0x7eaf8943, 0x127d7829, + 0x7ea85033, 0x12af33ba, 0x7ea1039b, 0x12e0ec6a, 0x7e99a37c, 0x1312a230, 0x7e922fd6, 0x13445505, 0x7e8aa8ac, + 0x137604e2, 0x7e830dff, 0x13a7b1bf, 0x7e7b5fce, 0x13d95b93, 0x7e739e1d, 0x140b0258, 0x7e6bc8eb, 0x143ca605, + 0x7e63e03b, 0x146e4694, 0x7e5be40c, 0x149fe3fc, 0x7e53d462, 0x14d17e36, 0x7e4bb13c, 0x1503153a, 0x7e437a9c, + 0x1534a901, 0x7e3b3083, 0x15663982, 0x7e32d2f4, 0x1597c6b7, 0x7e2a61ed, 0x15c95097, 0x7e21dd73, 0x15fad71b, + 0x7e194584, 0x162c5a3b, 0x7e109a24, 0x165dd9f0, 0x7e07db52, 0x168f5632, 0x7dff0911, 0x16c0cef9, 0x7df62362, + 0x16f2443e, 0x7ded2a47, 0x1723b5f9, 0x7de41dc0, 0x17552422, 0x7ddafdce, 0x17868eb3, 0x7dd1ca75, 0x17b7f5a3, + 0x7dc883b4, 0x17e958ea, 0x7dbf298d, 0x181ab881, 0x7db5bc02, 0x184c1461, 0x7dac3b15, 0x187d6c82, 0x7da2a6c6, + 0x18aec0db, 0x7d98ff17, 0x18e01167, 0x7d8f4409, 0x19115e1c, 0x7d85759f, 0x1942a6f3, 0x7d7b93da, 0x1973ebe6, + 0x7d719eba, 0x19a52ceb, 0x7d679642, 0x19d669fc, 0x7d5d7a74, 0x1a07a311, 0x7d534b50, 0x1a38d823, 0x7d4908d9, + 0x1a6a0929, 0x7d3eb30f, 0x1a9b361d, 0x7d3449f5, 0x1acc5ef6, 0x7d29cd8c, 0x1afd83ad, 0x7d1f3dd6, 0x1b2ea43a, + 0x7d149ad5, 0x1b5fc097, 0x7d09e489, 0x1b90d8bb, 0x7cff1af5, 0x1bc1ec9e, 0x7cf43e1a, 0x1bf2fc3a, 0x7ce94dfb, + 0x1c240786, 0x7cde4a98, 0x1c550e7c, 0x7cd333f3, 0x1c861113, 0x7cc80a0f, 0x1cb70f43, 0x7cbcccec, 0x1ce80906, + 0x7cb17c8d, 0x1d18fe54, 0x7ca618f3, 0x1d49ef26, 0x7c9aa221, 0x1d7adb73, 0x7c8f1817, 0x1dabc334, 0x7c837ad8, + 0x1ddca662, 0x7c77ca65, 0x1e0d84f5, 0x7c6c06c0, 0x1e3e5ee5, 0x7c602fec, 0x1e6f342c, 0x7c5445e9, 0x1ea004c1, + 0x7c4848ba, 0x1ed0d09d, 0x7c3c3860, 0x1f0197b8, 0x7c3014de, 0x1f325a0b, 0x7c23de35, 0x1f63178f, 0x7c179467, + 0x1f93d03c, 0x7c0b3777, 0x1fc4840a, 0x7bfec765, 0x1ff532f2, 0x7bf24434, 0x2025dcec, 0x7be5ade6, 0x205681f1, + 0x7bd9047c, 0x208721f9, 0x7bcc47fa, 0x20b7bcfe, 0x7bbf7860, 0x20e852f6, 0x7bb295b0, 0x2118e3dc, 0x7ba59fee, + 0x21496fa7, 0x7b989719, 0x2179f64f, 0x7b8b7b36, 0x21aa77cf, 0x7b7e4c45, 0x21daf41d, 0x7b710a49, 0x220b6b32, + 0x7b63b543, 0x223bdd08, 0x7b564d36, 0x226c4996, 0x7b48d225, 0x229cb0d5, 0x7b3b4410, 0x22cd12bd, 0x7b2da2fa, + 0x22fd6f48, 0x7b1feee5, 0x232dc66d, 0x7b1227d3, 0x235e1826, 0x7b044dc7, 0x238e646a, 0x7af660c2, 0x23beab33, + 0x7ae860c7, 0x23eeec78, 0x7ada4dd8, 0x241f2833, 0x7acc27f7, 0x244f5e5c, 0x7abdef25, 0x247f8eec, 0x7aafa367, + 0x24afb9da, 0x7aa144bc, 0x24dfdf20, 0x7a92d329, 0x250ffeb7, 0x7a844eae, 0x25401896, 0x7a75b74f, 0x25702cb7, + 0x7a670d0d, 0x25a03b11, 0x7a584feb, 0x25d0439f, 0x7a497feb, 0x26004657, 0x7a3a9d0f, 0x26304333, 0x7a2ba75a, + 0x26603a2c, 0x7a1c9ece, 0x26902b39, 0x7a0d836d, 0x26c01655, 0x79fe5539, 0x26effb76, 0x79ef1436, 0x271fda96, + 0x79dfc064, 0x274fb3ae, 0x79d059c8, 0x277f86b5, 0x79c0e062, 0x27af53a6, 0x79b15435, 0x27df1a77, 0x79a1b545, + 0x280edb23, 0x79920392, 0x283e95a1, 0x79823f20, 0x286e49ea, 0x797267f2, 0x289df7f8, 0x79627e08, 0x28cd9fc1, + 0x79528167, 0x28fd4140, 0x79427210, 0x292cdc6d, 0x79325006, 0x295c7140, 0x79221b4b, 0x298bffb2, 0x7911d3e2, + 0x29bb87bc, 0x790179cd, 0x29eb0957, 0x78f10d0f, 0x2a1a847b, 0x78e08dab, 0x2a49f920, 0x78cffba3, 0x2a796740, + 0x78bf56f9, 0x2aa8ced3, 0x78ae9fb0, 0x2ad82fd2, 0x789dd5cb, 0x2b078a36, 0x788cf94c, 0x2b36ddf7, 0x787c0a36, + 0x2b662b0e, 0x786b088c, 0x2b957173, 0x7859f44f, 0x2bc4b120, 0x7848cd83, 0x2bf3ea0d, 0x7837942b, 0x2c231c33, + 0x78264849, 0x2c52478a, 0x7814e9df, 0x2c816c0c, 0x780378f1, 0x2cb089b1, 0x77f1f581, 0x2cdfa071, 0x77e05f91, + 0x2d0eb046, 0x77ceb725, 0x2d3db928, 0x77bcfc3f, 0x2d6cbb10, 0x77ab2ee2, 0x2d9bb5f6, 0x77994f11, 0x2dcaa9d5, + 0x77875cce, 0x2df996a3, 0x7775581d, 0x2e287c5a, 0x776340ff, 0x2e575af3, 0x77511778, 0x2e863267, 0x773edb8b, + 0x2eb502ae, 0x772c8d3a, 0x2ee3cbc1, 0x771a2c88, 0x2f128d99, 0x7707b979, 0x2f41482e, 0x76f5340e, 0x2f6ffb7a, + 0x76e29c4b, 0x2f9ea775, 0x76cff232, 0x2fcd4c19, 0x76bd35c7, 0x2ffbe95d, 0x76aa670d, 0x302a7f3a, 0x76978605, + 0x30590dab, 0x768492b4, 0x308794a6, 0x76718d1c, 0x30b61426, 0x765e7540, 0x30e48c22, 0x764b4b23, 0x3112fc95, + 0x76380ec8, 0x31416576, 0x7624c031, 0x316fc6be, 0x76115f63, 0x319e2067, 0x75fdec60, 0x31cc7269, 0x75ea672a, + 0x31fabcbd, 0x75d6cfc5, 0x3228ff5c, 0x75c32634, 0x32573a3f, 0x75af6a7b, 0x32856d5e, 0x759b9c9b, 0x32b398b3, + 0x7587bc98, 0x32e1bc36, 0x7573ca75, 0x330fd7e1, 0x755fc635, 0x333debab, 0x754bafdc, 0x336bf78f, 0x7537876c, + 0x3399fb85, 0x75234ce8, 0x33c7f785, 0x750f0054, 0x33f5eb89, 0x74faa1b3, 0x3423d78a, 0x74e63108, 0x3451bb81, + 0x74d1ae55, 0x347f9766, 0x74bd199f, 0x34ad6b32, 0x74a872e8, 0x34db36df, 0x7493ba34, 0x3508fa66, 0x747eef85, + 0x3536b5be, 0x746a12df, 0x356468e2, 0x74552446, 0x359213c9, 0x744023bc, 0x35bfb66e, 0x742b1144, 0x35ed50c9, + 0x7415ece2, 0x361ae2d3, 0x7400b69a, 0x36486c86, 0x73eb6e6e, 0x3675edd9, 0x73d61461, 0x36a366c6, 0x73c0a878, + 0x36d0d746, 0x73ab2ab4, 0x36fe3f52, 0x73959b1b, 0x372b9ee3, 0x737ff9ae, 0x3758f5f2, 0x736a4671, 0x37864477, + 0x73548168, 0x37b38a6d, 0x733eaa96, 0x37e0c7cc, 0x7328c1ff, 0x380dfc8d, 0x7312c7a5, 0x383b28a9, 0x72fcbb8c, + 0x38684c19, 0x72e69db7, 0x389566d6, 0x72d06e2b, 0x38c278d9, 0x72ba2cea, 0x38ef821c, 0x72a3d9f7, 0x391c8297, + 0x728d7557, 0x39497a43, 0x7276ff0d, 0x39766919, 0x7260771b, 0x39a34f13, 0x7249dd86, 0x39d02c2a, 0x72333251, + 0x39fd0056, 0x721c7580, 0x3a29cb91, 0x7205a716, 0x3a568dd4, 0x71eec716, 0x3a834717, 0x71d7d585, 0x3aaff755, + 0x71c0d265, 0x3adc9e86, 0x71a9bdba, 0x3b093ca3, 0x71929789, 0x3b35d1a5, 0x717b5fd3, 0x3b625d86, 0x7164169d, + 0x3b8ee03e, 0x714cbbeb, 0x3bbb59c7, 0x71354fc0, 0x3be7ca1a, 0x711dd220, 0x3c143130, 0x7106430e, 0x3c408f03, + 0x70eea28e, 0x3c6ce38a, 0x70d6f0a4, 0x3c992ec0, 0x70bf2d53, 0x3cc5709e, 0x70a7589f, 0x3cf1a91c, 0x708f728b, + 0x3d1dd835, 0x70777b1c, 0x3d49fde1, 0x705f7255, 0x3d761a19, 0x70475839, 0x3da22cd7, 0x702f2ccd, 0x3dce3614, + 0x7016f014, 0x3dfa35c8, 0x6ffea212, 0x3e262bee, 0x6fe642ca, 0x3e52187f, 0x6fcdd241, 0x3e7dfb73, 0x6fb5507a, + 0x3ea9d4c3, 0x6f9cbd79, 0x3ed5a46b, 0x6f841942, 0x3f016a61, 0x6f6b63d8, 0x3f2d26a0, 0x6f529d40, 0x3f58d921, + 0x6f39c57d, 0x3f8481dd, 0x6f20dc92, 0x3fb020ce, 0x6f07e285, 0x3fdbb5ec, 0x6eeed758, 0x40074132, 0x6ed5bb10, + 0x4032c297, 0x6ebc8db0, 0x405e3a16, 0x6ea34f3d, 0x4089a7a8, 0x6e89ffb9, 0x40b50b46, 0x6e709f2a, 0x40e064ea, + 0x6e572d93, 0x410bb48c, 0x6e3daaf8, 0x4136fa27, 0x6e24175c, 0x416235b2, 0x6e0a72c5, 0x418d6729, 0x6df0bd35, + 0x41b88e84, 0x6dd6f6b1, 0x41e3abbc, 0x6dbd1f3c, 0x420ebecb, 0x6da336dc, 0x4239c7aa, 0x6d893d93, 0x4264c653, + 0x6d6f3365, 0x428fbabe, 0x6d551858, 0x42baa4e6, 0x6d3aec6e, 0x42e584c3, 0x6d20afac, 0x43105a50, 0x6d066215, + 0x433b2585, 0x6cec03af, 0x4365e65b, 0x6cd1947c, 0x43909ccd, 0x6cb71482, 0x43bb48d4, 0x6c9c83c3, 0x43e5ea68, + 0x6c81e245, 0x44108184, 0x6c67300b, 0x443b0e21, 0x6c4c6d1a, 0x44659039, 0x6c319975, 0x449007c4, 0x6c16b521, + 0x44ba74bd, 0x6bfbc021, 0x44e4d71c, 0x6be0ba7b, 0x450f2edb, 0x6bc5a431, 0x45397bf4, 0x6baa7d49, 0x4563be60, + 0x6b8f45c7, 0x458df619, 0x6b73fdae, 0x45b82318, 0x6b58a503, 0x45e24556, 0x6b3d3bcb, 0x460c5cce, 0x6b21c208, + 0x46366978, 0x6b0637c1, 0x46606b4e, 0x6aea9cf8, 0x468a624a, 0x6acef1b2, 0x46b44e65, 0x6ab335f4, 0x46de2f99, + 0x6a9769c1, 0x470805df, 0x6a7b8d1e, 0x4731d131, 0x6a5fa010, 0x475b9188, 0x6a43a29a, 0x478546de, 0x6a2794c1, + 0x47aef12c, 0x6a0b7689, 0x47d8906d, 0x69ef47f6, 0x48022499, 0x69d3090e, 0x482badab, 0x69b6b9d3, 0x48552b9b, + 0x699a5a4c, 0x487e9e64, 0x697dea7b, 0x48a805ff, 0x69616a65, 0x48d16265, 0x6944da10, 0x48fab391, 0x6928397e, + 0x4923f97b, 0x690b88b5, 0x494d341e, 0x68eec7b9, 0x49766373, 0x68d1f68f, 0x499f8774, 0x68b5153a, 0x49c8a01b, + 0x689823bf, 0x49f1ad61, 0x687b2224, 0x4a1aaf3f, 0x685e106c, 0x4a43a5b0, 0x6840ee9b, 0x4a6c90ad, 0x6823bcb7, + 0x4a957030, 0x68067ac3, 0x4abe4433, 0x67e928c5, 0x4ae70caf, 0x67cbc6c0, 0x4b0fc99d, 0x67ae54ba, 0x4b387af9, + 0x6790d2b6, 0x4b6120bb, 0x677340ba, 0x4b89badd, 0x67559eca, 0x4bb24958, 0x6737ecea, 0x4bdacc28, 0x671a2b20, + 0x4c034345, 0x66fc596f, 0x4c2baea9, 0x66de77dc, 0x4c540e4e, 0x66c0866d, 0x4c7c622d, 0x66a28524, 0x4ca4aa41, + 0x66847408, 0x4ccce684, 0x6666531d, 0x4cf516ee, 0x66482267, 0x4d1d3b7a, 0x6629e1ec, 0x4d455422, 0x660b91af, + 0x4d6d60df, 0x65ed31b5, 0x4d9561ac, 0x65cec204, 0x4dbd5682, 0x65b0429f, 0x4de53f5a, 0x6591b38c, 0x4e0d1c30, + 0x657314cf, 0x4e34ecfc, 0x6554666d, 0x4e5cb1b9, 0x6535a86b, 0x4e846a60, 0x6516dacd, 0x4eac16eb, 0x64f7fd98, + 0x4ed3b755, 0x64d910d1, 0x4efb4b96, 0x64ba147d, 0x4f22d3aa, 0x649b08a0, 0x4f4a4f89, 0x647bed3f, 0x4f71bf2e, + 0x645cc260, 0x4f992293, 0x643d8806, 0x4fc079b1, 0x641e3e38, 0x4fe7c483, 0x63fee4f8, 0x500f0302, 0x63df7c4d, + 0x50363529, 0x63c0043b, 0x505d5af1, 0x63a07cc7, 0x50847454, 0x6380e5f6, 0x50ab814d, 0x63613fcd, 0x50d281d5, + 0x63418a50, 0x50f975e6, 0x6321c585, 0x51205d7b, 0x6301f171, 0x5147388c, 0x62e20e17, 0x516e0715, 0x62c21b7e, + 0x5194c910, 0x62a219aa, 0x51bb7e75, 0x628208a1, 0x51e22740, 0x6261e866, 0x5208c36a, 0x6241b8ff, 0x522f52ee, + 0x62217a72, 0x5255d5c5, 0x62012cc2, 0x527c4bea, 0x61e0cff5, 0x52a2b556, 0x61c06410, 0x52c91204, 0x619fe918, + 0x52ef61ee, 0x617f5f12, 0x5315a50e, 0x615ec603, 0x533bdb5d, 0x613e1df0, 0x536204d7, 0x611d66de, 0x53882175, + 0x60fca0d2, 0x53ae3131, 0x60dbcbd1, 0x53d43406, 0x60bae7e1, 0x53fa29ed, 0x6099f505, 0x542012e1, 0x6078f344, + 0x5445eedb, 0x6057e2a2, 0x546bbdd7, 0x6036c325, 0x54917fce, 0x601594d1, 0x54b734ba, 0x5ff457ad, 0x54dcdc96, + 0x5fd30bbc, 0x5502775c, 0x5fb1b104, 0x55280505, 0x5f90478a, 0x554d858d, 0x5f6ecf53, 0x5572f8ed, 0x5f4d4865, + 0x55985f20, 0x5f2bb2c5, 0x55bdb81f, 0x5f0a0e77, 0x55e303e6, 0x5ee85b82, 0x5608426e, 0x5ec699e9, 0x562d73b2, + 0x5ea4c9b3, 0x565297ab, 0x5e82eae5, 0x5677ae54, 0x5e60fd84, 0x569cb7a8, 0x5e3f0194, 0x56c1b3a1, 0x5e1cf71c, + 0x56e6a239, 0x5dfade20, 0x570b8369, 0x5dd8b6a7, 0x5730572e, 0x5db680b4, 0x57551d80, 0x5d943c4e, 0x5779d65b, + 0x5d71e979, 0x579e81b8, 0x5d4f883b, 0x57c31f92, 0x5d2d189a, 0x57e7afe4, 0x5d0a9a9a, 0x580c32a7, 0x5ce80e41, + 0x5830a7d6, 0x5cc57394, 0x58550f6c, 0x5ca2ca99, 0x58796962, 0x5c801354, 0x589db5b3, 0x5c5d4dcc, 0x58c1f45b, + 0x5c3a7a05, 0x58e62552, 0x5c179806, 0x590a4893, 0x5bf4a7d2, 0x592e5e19, 0x5bd1a971, 0x595265df, 0x5bae9ce7, + 0x59765fde, 0x5b8b8239, 0x599a4c12, 0x5b68596d, 0x59be2a74, 0x5b452288, 0x59e1faff, 0x5b21dd90, 0x5a05bdae, + 0x5afe8a8b, 0x5a29727b, 0x5adb297d, 0x5a4d1960, 0x5ab7ba6c, 0x5a70b258, 0x5a943d5e, +}; + +const int32_t INVSQ_LOOKUP_I[64 + 1] = { + 92682, 91966, 91267, 90583, 89915, 89261, 88621, 87995, 87381, 86781, 86192, 85616, 85051, + 84497, 83953, 83420, 82897, 82384, 81880, 81385, 80899, 80422, 79953, 79492, 79039, 78594, + 78156, 77726, 77302, 76885, 76475, 76072, 75674, 75283, 74898, 74519, 74146, 73778, 73415, + 73058, 72706, 72359, 72016, 71679, 71347, 71019, 70695, 70376, 70061, 69750, 69444, 69141, + 68842, 68548, 68256, 67969, 67685, 67405, 67128, 66855, 66585, 66318, 66054, 65794, 65536, +}; + +const int32_t INVSQ_LOOKUP_IDel[64] = { + 716, 699, 684, 668, 654, 640, 626, 614, 600, 589, 576, 565, 554, 544, 533, 523, 513, 504, 495, 486, 477, 469, + 461, 453, 445, 438, 430, 424, 417, 410, 403, 398, 391, 385, 379, 373, 368, 363, 357, 352, 347, 343, 337, 332, + 328, 324, 319, 315, 311, 306, 303, 299, 294, 292, 287, 284, 280, 277, 273, 270, 267, 264, 260, 258, +}; + +static const int32_t COS_LOOKUP_I[COS_LOOKUP_I_SZ + 1] = { + 16384, 16379, 16364, 16340, 16305, 16261, 16207, 16143, 16069, 15986, 15893, 15791, 15679, + 15557, 15426, 15286, 15137, 14978, 14811, 14635, 14449, 14256, 14053, 13842, 13623, 13395, + 13160, 12916, 12665, 12406, 12140, 11866, 11585, 11297, 11003, 10702, 10394, 10080, 9760, + 9434, 9102, 8765, 8423, 8076, 7723, 7366, 7005, 6639, 6270, 5897, 5520, 5139, + 4756, 4370, 3981, 3590, 3196, 2801, 2404, 2006, 1606, 1205, 804, 402, 0, + -401, -803, -1204, -1605, -2005, -2403, -2800, -3195, -3589, -3980, -4369, -4755, -5138, + -5519, -5896, -6269, -6638, -7004, -7365, -7722, -8075, -8422, -8764, -9101, -9433, -9759, + -10079, -10393, -10701, -11002, -11296, -11584, -11865, -12139, -12405, -12664, -12915, -13159, -13394, + -13622, -13841, -14052, -14255, -14448, -14634, -14810, -14977, -15136, -15285, -15425, -15556, -15678, + -15790, -15892, -15985, -16068, -16142, -16206, -16260, -16304, -16339, -16363, -16378, -16383, +}; \ No newline at end of file diff --git a/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.cpp b/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.cpp new file mode 100644 index 0000000..7b81513 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.cpp @@ -0,0 +1,3316 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ********************************************************************/ +/* + * vorbis decoder.cpp + * based on Xiph.Org Foundation vorbis decoder + * adapted for the ESP32 by schreibfaul1 + * + * Created on: 13.02.2023 + * Updated on: 14.02.2026 + */ +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// O G G I M P L. +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +#include "vorbis_decoder.h" +#include "lookup.h" + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool VorbisDecoder::init() { + setDefaults(); + m_ogg_items.lastSegmentTable.alloc(4096, "m_lastSegmentTable"); + m_out16.alloc_array(4608 * 2, "m_out16"); + if (m_ogg_items.lastSegmentTable.valid() && m_out16.valid()) m_f_isValid = true; + return m_f_isValid; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::reset() { + clearGlobalConfigurations(); + if (m_codebooks.valid()) m_codebooks.reset(); + if (m_floor_param.valid()) m_floor_param.reset(); + if (m_floor_type.valid()) m_floor_type.reset(); + if (m_residue_param.valid()) m_residue_param.reset(); + if (m_map_param.valid()) m_map_param.reset(); + if (m_mode_param.valid()) m_mode_param.reset(); + if (m_dsp_state.valid()) m_dsp_state.reset(); + m_ogg_items.segment_table.clear(); + m_out16.reset(); + m_f_isValid = false; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::clear() { + m_bitReader.reset(); + m_ogg_items.reset(); + m_ogg_items.lastSegmentTable.alloc(4096, "m_lastSegmentTable"); + m_vorbisBlockPicItem.clear(); + m_out16.clear(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool VorbisDecoder::isValid() { + return m_f_isValid; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::setDefaults() { + m_pageNr = 0; + m_f_newSteamTitle = false; // streamTitle + m_f_newMetadataBlockPicture = false; + m_f_parseOggDone = false; + m_f_oggFirstPage = false; + m_f_oggContinuedPage = false; + m_f_oggLastPage = false; + m_f_comment_done = false; + if (m_dsp_state.valid()) { vorbis_dsp_destroy(m_dsp_state); } + m_vorbisChannels = 0; + m_vorbisSamplerate = 0; + m_vorbisBitRate = 0; + m_vorbisValidSamples = 0; + m_vorbisCurrentFilePos = 0; + m_vorbisAudioDataStart = 0; + m_vorbisOldMode = 0xFF; + m_vorbisError = 0; + m_vorbisBlockPicPos = 0; + m_vorbisBlockPicLen = 0; + m_commentBlockSegmentSize = 0; + m_vorbisBlockPicItem.shrink_to_fit(); + clear(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::clearGlobalConfigurations() { // mode, mapping, floor etc + vorbis_book_clear(m_codebooks); + vorbis_dsp_destroy(m_dsp_state); + + if (m_nrOfFloors) { + for (int32_t i = 0; i < m_nrOfFloors; i++) { + m_floor_param[i]->_class.reset(); + m_floor_param[i]->partitionclass.reset(); + m_floor_param[i]->postlist.reset(); + m_floor_param[i]->forward_index.reset(); + m_floor_param[i]->hineighbor.reset(); + m_floor_param[i]->loneighbor.reset(); + m_floor_param[i].reset(); + } + m_floor_param.reset(); + m_nrOfFloors = 0; + } + + if (m_nrOfResidues) { + for (int32_t i = 0; i < m_nrOfResidues; i++) { + m_residue_param[i].stagemasks.reset(); + m_residue_param[i].stagebooks.reset(); + } + m_residue_param.reset(); + m_nrOfResidues = 0; + } + + if (m_nrOfMaps) { + for (int32_t i = 0; i < m_nrOfMaps; i++) { + m_map_param[i].chmuxlist.reset(); + m_map_param[i].submaplist.reset(); + m_map_param[i].coupling.reset(); + } + m_map_param.reset(); + m_nrOfMaps = 0; + } + + if (m_floor_type.valid()) m_floor_type.reset(); + if (m_residue_param.valid()) m_residue_param.reset(); + if (m_map_param.valid()) m_map_param.reset(); + if (m_mode_param.valid()) m_mode_param.reset(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + int32_t ret = 0; + int32_t bytesLeft_begin = *bytesLeft; + m_ogg_items.data_ptr = inbuf; // save for bitReader underrun + + if (!m_ogg_items.segment_table.size()) { + ret = parse_OGG(inbuf, bytesLeft); + m_f_parseOggDone = true; + if (!m_ogg_items.segment_table.size()) { /* VORBIS_LOG_WARN("OggS without segments?") */ + ; + } + goto exit; + } + // With the last segment of a table, we don't know whether it will be continued in the next Ogg page. + // So the last segment is saved. m_lastSegmentTableLen specifies the size of the last saved segment. + // If the next Ogg Page does not contain a 'continuedPage', the last segment is played first. However, + // if 'continuedPage' is set, the first segment of the new page is added to the saved segment and played. + + if (m_ogg_items.segment_table.size()) { + m_vorbis_segment_length = m_ogg_items.segment_table[0]; + m_ogg_items.segment_table.pop_front(); + VORBIS_LOG_DEBUG("continue {}", m_f_oggContinuedPage); + } + + if (m_pageNr < 4) + if (special_index_of(inbuf, "vorbis", 10) == 1) m_pageNr++; + + switch (m_pageNr) { + case 0: ret = VORBIS_PARSE_OGG_DONE; break; + case 1: + m_comment.reset(); + ret = vorbisDecodePage1(inbuf, bytesLeft, m_vorbis_segment_length); // blocksize, channels, samplerates + break; + case 2: + ret = vorbisDecodePage2(inbuf, bytesLeft, m_vorbis_segment_length, m_vorbisCurrentFilePos); // comments + break; + case 3: + ret = vorbisDecodePage3(inbuf, bytesLeft, m_vorbis_segment_length); // codebooks + break; + case 4: + ret = vorbisDecodePage4(inbuf, bytesLeft, m_vorbis_segment_length, m_out16.get()); // decode audio + break; + default: + VORBIS_LOG_ERROR("unknown page {}", m_pageNr); + ret = VORBIS_ERR; + break; + } +exit: + if (m_ogg_items.bytes_consumed_from_other > 0) { + *bytesLeft -= m_ogg_items.bytes_consumed_from_other; + m_ogg_items.bytes_consumed_from_other = 0; + } + if (ret >= 0) { m_vorbisCurrentFilePos += bytesLeft_begin - (*bytesLeft); } + if (ret < 0) { + VORBIS_LOG_ERROR("ret {}", ret); + m_ogg_items.segment_table.clear(); + } + if (ret == 0) { + if (m_vorbisChannels == 1) { + for (int i = 0; i < m_vorbisValidSamples; i++) { + outbuf[i * 2] = m_out16[i] << 16; + outbuf[i * 2 + 1] = m_out16[i] << 16; + } + } + + if (m_vorbisChannels == 2) { + for (int i = 0; i < m_vorbisValidSamples * 2; i++) { outbuf[i] = m_out16[i] << 16; } + } + } + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————-------------------------------------------------------------------------------- +int32_t VorbisDecoder::vorbisDecodePage1(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength) { + int32_t ret = VORBIS_PARSE_OGG_DONE; + clearGlobalConfigurations(); // if a new codebook is required, delete the old one + int32_t idx = special_index_of(inbuf, "vorbis", 10); + if (idx == 1) { + // VORBIS_LOG_INFO("first packet (identification segmentLength) {}", segmentLength); + m_identificatonHeaderLength = segmentLength; + ret = parseVorbisFirstPacket(inbuf, segmentLength); + } else { + VORBIS_LOG_ERROR("vorbis identificator not found"); + ret = VORBIS_ERR; + } + + *bytesLeft -= segmentLength; + return ret; +} +// —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————-------------------------------------------------------------------------------- +int32_t VorbisDecoder::vorbisDecodePage2(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, uint32_t current_file_pos) { + + int32_t ret = 0; + ret = parseVorbisComment(inbuf, segmentLength, current_file_pos); + + if (ret == VORBIS_COMMENT_INVALID) { + VORBIS_LOG_DEBUG("VORBIS_COMMENT_INVALID"); + } else if (ret == VORBIS_COMMENT_NEED_MORE) { + VORBIS_LOG_DEBUG("VORBIS_COMMENT_NEED_MORE"); + *bytesLeft -= segmentLength; + } else if (ret == VORBIS_COMMENT_DONE) { + VORBIS_LOG_DEBUG("VORBIS_COMMENT_DONE"); + *bytesLeft -= segmentLength; + VORBIS_LOG_DEBUG("bytesLeft {}", *bytesLeft); + } else { + VORBIS_LOG_DEBUG("VORBIS_UNKNOWN"); + } + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::vorbisDecodePage3(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength) { + int32_t ret = VORBIS_PARSE_OGG_DONE; + int32_t idx = special_index_of(inbuf, "vorbis", 10); + if (idx == 1) { + m_oggPage3Len = segmentLength - 7; // skip ".vorbis" + bitReader_setData(inbuf + 7, m_oggPage3Len); // skip also ".vorbis" + VORBIS_LOG_DEBUG(" segmentLength {}", segmentLength); + ret = parseVorbisCodebook(); + } else { + VORBIS_LOG_ERROR("no \"vorbis\" something went wrong, segmentLenght: {}", segmentLength); + ret = VORBIS_ERR; + } + m_pageNr = 4; + m_dsp_state = vorbis_dsp_create(); + + *bytesLeft -= segmentLength; + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::vorbisDecodePage4(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, int16_t* outbuf) { + + if (m_vorbisAudioDataStart == 0) { m_vorbisAudioDataStart = m_vorbisCurrentFilePos; } + + int32_t ret = 0; + uint16_t outBuffSize = 4608 * 2; + + if (m_f_oggLastPage) { + if (segmentLength > 1) { + bitReader_setData(inbuf, segmentLength); + ret = vorbis_dsp_synthesis(inbuf, segmentLength, outbuf); + m_vorbisValidSamples = vorbis_dsp_pcmout(outbuf, outBuffSize); + } else { + m_ogg_items.lastSegmentTableLen = 0; + m_vorbisValidSamples = 0; + ret = VORBIS_PARSE_OGG_DONE; + } + VORBIS_LOG_DEBUG("last page, sl {}", segmentLength); + goto exit; + } + + if (m_ogg_items.segment_table.size()) { + if (m_f_oggContinuedPage) { + m_f_oggContinuedPage = false; + memcpy(m_ogg_items.lastSegmentTable.get() + m_ogg_items.lastSegmentTableLen, inbuf, segmentLength); + bitReader_setData(m_ogg_items.lastSegmentTable.get(), m_ogg_items.lastSegmentTableLen + segmentLength); + ret = vorbis_dsp_synthesis(m_ogg_items.lastSegmentTable.get(), m_ogg_items.lastSegmentTableLen + segmentLength, outbuf); + m_vorbisValidSamples = vorbis_dsp_pcmout(outbuf, outBuffSize); + m_ogg_items.lastSegmentTableLen = 0; + goto exit; + } else if (m_ogg_items.lastSegmentTableLen) { + bitReader_setData(m_ogg_items.lastSegmentTable.get(), m_ogg_items.lastSegmentTableLen); + ret = vorbis_dsp_synthesis(m_ogg_items.lastSegmentTable.get(), m_ogg_items.lastSegmentTableLen, outbuf); + m_vorbisValidSamples = vorbis_dsp_pcmout(outbuf, outBuffSize); + + bitReader_setData(inbuf, segmentLength); + ret = vorbis_dsp_synthesis(inbuf, segmentLength, outbuf); + m_vorbisValidSamples += vorbis_dsp_pcmout(outbuf + (m_vorbisValidSamples * m_vorbisChannels), outBuffSize); + m_ogg_items.lastSegmentTableLen = false; + goto exit; + } else { + bitReader_setData(inbuf, segmentLength); + ret = vorbis_dsp_synthesis(inbuf, segmentLength, outbuf); + if (ret < 0) { + VORBIS_LOG_ERROR("segmentLength {}", segmentLength); + ps_ptr hd; + hd.set_name("p4"); + hd.copy_from(inbuf, 10); + hd.hex_dump(10); + } + m_vorbisValidSamples = vorbis_dsp_pcmout(outbuf, outBuffSize); + goto exit; + } + } else { + memcpy(m_ogg_items.lastSegmentTable.get(), inbuf, segmentLength); + m_ogg_items.lastSegmentTableLen = segmentLength; + m_vorbisValidSamples = 0; + ret = 0; + } +exit: + if (ret == OV_ENOTAUDIO) { + m_vorbisValidSamples = 0; + VORBIS_LOG_INFO("non audio package at pos {}", m_vorbisCurrentFilePos); + ret = 0; + } + *bytesLeft -= segmentLength; + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t VorbisDecoder::getChannels() { + return m_vorbisChannels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::getSampleRate() { + return m_vorbisSamplerate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t VorbisDecoder::getBitsPerSample() { + return 16; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::getBitRate() { + return m_vorbisBitRate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::getAudioDataStart() { + return m_vorbisAudioDataStart; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::getOutputSamples() { + return m_vorbisValidSamples; // 1024 +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::getAudioFileDuration() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* VorbisDecoder::getStreamTitle() { + if (m_f_newSteamTitle) { + m_f_newSteamTitle = false; + return m_comment.stream_title.c_get(); + } + return NULL; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector VorbisDecoder::getMetadataBlockPicture() { + if (m_f_newMetadataBlockPicture) { + m_f_newMetadataBlockPicture = false; + return m_comment.pic_vec; + } + std::vector v; + return v; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* VorbisDecoder::arg1() { + return ""; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* VorbisDecoder::arg2() { + return ""; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::val1() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::val2() { + return 0; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::parseVorbisFirstPacket(uint8_t* inbuf, int16_t nBytes) { // 4.2.2. Identification header + // https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-820005 + // first bytes are: '.vorbis' + uint16_t pos = 7; + uint32_t version = *(inbuf + pos); + version += *(inbuf + pos + 1) << 8; + version += *(inbuf + pos + 2) << 16; + version += *(inbuf + pos + 3) << 24; + (void)version; + + uint8_t channels = *(inbuf + pos + 4); + + uint32_t sampleRate = *(inbuf + pos + 5); + sampleRate += *(inbuf + pos + 6) << 8; + sampleRate += *(inbuf + pos + 7) << 16; + sampleRate += *(inbuf + pos + 8) << 24; + + uint32_t br_max = *(inbuf + pos + 9); + br_max += *(inbuf + pos + 10) << 8; + br_max += *(inbuf + pos + 11) << 16; + br_max += *(inbuf + pos + 12) << 24; + + uint32_t br_nominal = *(inbuf + pos + 13); + br_nominal += *(inbuf + pos + 14) << 8; + br_nominal += *(inbuf + pos + 15) << 16; + br_nominal += *(inbuf + pos + 16) << 24; + + uint32_t br_min = *(inbuf + pos + 17); + br_min += *(inbuf + pos + 18) << 8; + br_min += *(inbuf + pos + 19) << 16; + br_min += *(inbuf + pos + 20) << 24; + + uint8_t blocksize = *(inbuf + pos + 21); + + m_blocksizes[0] = 1 << (blocksize & 0x0F); + m_blocksizes[1] = 1 << ((blocksize & 0xF0) >> 4); + + if (m_blocksizes[0] < 64) { + VORBIS_LOG_ERROR("Vorbis, blocksize[0] too low {}", m_blocksizes[0]); + return -1; + } + if (m_blocksizes[1] < m_blocksizes[0]) { + VORBIS_LOG_ERROR("Vorbis, m_blocksizes[1] {} is smaller than m_blocksizes[0] {}", m_blocksizes[1], m_blocksizes[0]); + return -1; + } + if (m_blocksizes[1] > 8192) { + VORBIS_LOG_ERROR("Vorbis, m_blocksizes[1] is too big: {}", m_blocksizes[1]); + return -1; + } + + if (channels < 1 || channels > 2) { + VORBIS_LOG_ERROR("Vorbis, nr of channels is not valid ch={}", channels); + return -1; + } + m_vorbisChannels = channels; + + if (sampleRate < 4096 || sampleRate > 64000) { + VORBIS_LOG_ERROR("Vorbis, sampleRate is not valid sr={}", sampleRate); + return -1; + } + m_vorbisSamplerate = sampleRate; + + m_vorbisBitRate = br_nominal; + + return VORBIS_PARSE_OGG_DONE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::parseVorbisComment(uint8_t* inbuf, int16_t nBytes, uint32_t current_file_pos) { + // reference https://xiph.org/vorbis/doc/v-comment.html + + constexpr uint32_t MAX_COMMENT_SIZE = 1024; + int32_t available_bytes = nBytes; + + auto parse_comment = [&](ps_ptr comment) -> void { + int idx = comment.index_of("="); + if (idx <= 0) return; + ps_ptr key = comment.substr(0, idx); + ps_ptr val = comment.substr(idx + 1); + if (key.starts_with_icase("metadata_block_picture")) { + if (m_comment.item_vec.size() % 2 != 0) { VORBIS_LOG_ERROR("vec.size is odd: {}", m_comment.item_vec.size()); } + m_comment.item_vec[0] += strlen("METADATA_BLOCK_PICTURE="); + for (int i = 0; i < m_comment.item_vec.size(); i += 2) { + m_comment.pic_vec.push_back(m_comment.item_vec[i]); // start pos + m_comment.pic_vec.push_back(m_comment.item_vec[i + 1] - m_comment.item_vec[i]); // len = end pos - start pos + } + m_comment.item_vec.clear(); + m_f_newMetadataBlockPicture = true; + // for (int i = 0; i < m_comment.pic_vec.size(); i += 2) { OPUS_LOG_INFO("Segment {} {} - {}", i / 2, m_comment.pic_vec[i], m_comment.pic_vec[i + 1]); } + VORBIS_LOG_DEBUG("Skipping embedded picture ({} bytes)", val.size()); + return; + } + if (key.starts_with_icase("artist")) { + if (!m_comment.stream_title.valid()) { + m_comment.stream_title.assign(val.c_get()); + } else { + m_comment.stream_title.append(" - "); + m_comment.stream_title.append(val.c_get()); + } + audio.info(audio, Audio::evt_id3data, "Artist: {}", val.c_get()); + } + if (key.starts_with_icase("title")) { + if (!m_comment.stream_title.valid()) { + m_comment.stream_title.assign(val.c_get()); + } else { + m_comment.stream_title.append(" - "); + m_comment.stream_title.append(val.c_get()); + } + audio.info(audio, Audio::evt_id3data, "Title: {}", val.c_get()); + } + if (key.starts_with_icase("work")) { audio.info(audio, Audio::evt_id3data, "Work: {}", val.c_get()); } + if (key.starts_with_icase("composer")) { audio.info(audio, Audio::evt_id3data, "Composer: {}", val.c_get()); } + if (key.starts_with_icase("genre")) { audio.info(audio, Audio::evt_id3data, "Genre: {}", val.c_get()); } + if (key.starts_with_icase("date")) { audio.info(audio, Audio::evt_id3data, "Date: {}", val.c_get()); } + if (key.starts_with_icase("album")) { audio.info(audio, Audio::evt_id3data, "Album: {}", val.c_get()); } + if (key.starts_with_icase("comment")) { audio.info(audio, Audio::evt_id3data, "Comments: {}", val.c_get()); } + if (key.starts_with_icase("tracknumber")) { audio.info(audio, Audio::evt_id3data, "Track number/Position in set: {}", val.c_get()); } + + if (m_comment.stream_title.valid()) m_f_newSteamTitle = true; + // comment.println(); // optional output + m_comment.item_vec.clear(); + }; + + auto fill_content = [&](uint8_t* buff, uint32_t len) -> void { + // defensive guards (avoid signed/unsigned confusion) + const uint32_t S_MAX = MAX_COMMENT_SIZE; + uint32_t s = m_comment.comment_content.strlen(); // vorhandene länge + if (s >= S_MAX) { + // already full — nothing more to add + VORBIS_LOG_DEBUG("comment_content already at or above MAX_COMMENT_SIZE ({} >= {})", s, S_MAX); + return; + } + + // clamp len to something sensible (len can come from the caller, so check) + uint32_t available_space = S_MAX - s; + uint32_t to_fill = (len <= available_space) ? len : available_space; + + VORBIS_LOG_DEBUG("strlen {}, incoming len {}, to_fill {}", s, len, to_fill); + + // defensive: wenn to_fill == 0, nichts tun + if (to_fill == 0) return; + + // copy/append execute safely + const char* src = reinterpret_cast(buff); + if (s == 0) { + // initial copy + m_comment.comment_content.copy_from(src, to_fill); + } else { + // append, ensure append argument limited to to_fill + m_comment.comment_content.append(src, to_fill); + } + }; + + // 🔹 1. If the previous comment block was incomplete → continue now + if (m_comment.oob) { + int64_t tmp_to_read = (int64_t)m_comment.comment_size - (int64_t)m_comment.save_len; + if (tmp_to_read < 0) tmp_to_read = 0; + uint32_t to_read = (uint32_t)tmp_to_read; + if (available_bytes <= 0) { // clamp to available_bytes (available_bytes ist signed int) + // nothing to do + if (m_comment.list_length == 0) return VORBIS_COMMENT_DONE; + return VORBIS_COMMENT_NEED_MORE; + } + if ((uint32_t)available_bytes < to_read) to_read = (uint32_t)available_bytes; + + VORBIS_LOG_DEBUG("to_read {}, available_bytes {}", to_read, available_bytes); + m_comment.start_pos = current_file_pos; + VORBIS_LOG_DEBUG("partial start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf, to_read); + m_comment.save_len += to_read; + m_comment.pointer = to_read; + available_bytes -= to_read; + if (m_comment.save_len == m_comment.comment_size) { + VORBIS_LOG_DEBUG("end {}", m_comment.start_pos + to_read); + m_comment.item_vec.push_back(m_comment.start_pos + to_read); + // m_comment.comment_content.println(); + parse_comment(m_comment.comment_content); + m_comment.comment_content.reset(); + m_comment.oob = false; + m_comment.list_length--; + } else { + VORBIS_LOG_DEBUG("partial end {}", m_comment.start_pos + nBytes); + m_comment.item_vec.push_back(m_comment.start_pos + nBytes); + } + if (m_comment.list_length == 0) return VORBIS_COMMENT_DONE; + if (available_bytes == 0) return VORBIS_COMMENT_NEED_MORE; + // fall through + } + // 🔹 2. If this is the first page → read header + bool first_call = (m_comment.pointer == 0 && m_comment.list_length == 0); + if (first_call) { + int32_t idx = specialIndexOf(inbuf, "vorbis", 10); + if (idx != 1) return VORBIS_COMMENT_INVALID; + + m_comment.pointer = 7; // skip ".vorbis" + available_bytes -= 7; + uint32_t vendorLength = little_endian(inbuf + m_comment.pointer); + m_comment.pointer += 4 + vendorLength; // skip vendor string + available_bytes -= 4 + vendorLength; + m_comment.list_length = little_endian(inbuf + m_comment.pointer); + m_comment.pointer += 4; + available_bytes -= 4; + VORBIS_LOG_DEBUG("VendorLen={}, CommentCount={}", vendorLength, m_comment.list_length); + } + + // 🔹 3. read comments + while (m_comment.list_length > 0) { + + // --- handle possible split 4-byte comment length --- + if (m_comment.partial_length > 0 || available_bytes < 4) { + uint8_t bytes_to_copy = std::min(4 - m_comment.partial_length, available_bytes); + memcpy(m_comment.length_bytes + m_comment.partial_length, inbuf + (nBytes - available_bytes), bytes_to_copy); + + m_comment.partial_length += bytes_to_copy; + available_bytes -= bytes_to_copy; + m_comment.pointer += bytes_to_copy; + + VORBIS_LOG_DEBUG("Partial length bytes collected: {}/4", m_comment.partial_length); + + if (m_comment.partial_length < 4) { + // still incomplete → need more data next call + return VORBIS_COMMENT_NEED_MORE; + } + + // now we have all 4 bytes + m_comment.comment_size = little_endian(m_comment.length_bytes); + m_comment.partial_length = 0; // reset for next comment + VORBIS_LOG_DEBUG("m_comment.comment_size (assembled) {}", m_comment.comment_size); + } else { + memcpy(m_comment.length_bytes, inbuf + (nBytes - available_bytes), 4); + m_comment.comment_size = little_endian(m_comment.length_bytes); + m_comment.pointer += 4; + available_bytes -= 4; + VORBIS_LOG_DEBUG("m_comment.comment_size {}", m_comment.comment_size); + } + + if (m_comment.comment_size <= available_bytes) { // can completely read + m_comment.start_pos = current_file_pos + m_comment.pointer; + VORBIS_LOG_DEBUG("start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf + (nBytes - available_bytes), m_comment.comment_size); + m_comment.end_pos = m_comment.start_pos + m_comment.comment_size; + VORBIS_LOG_DEBUG("end {}", m_comment.end_pos); + m_comment.item_vec.push_back(m_comment.end_pos); + m_comment.pointer += m_comment.comment_size; + available_bytes -= m_comment.comment_size; + parse_comment(m_comment.comment_content); + m_comment.comment_content.reset(); + m_comment.list_length--; + if (m_comment.list_length == 0) return VORBIS_COMMENT_DONE; + } + + else { // out of bounds + m_comment.start_pos = current_file_pos + m_comment.pointer; + VORBIS_LOG_DEBUG("start {}", m_comment.start_pos); + m_comment.item_vec.push_back(m_comment.start_pos); + fill_content(inbuf + (nBytes - available_bytes), available_bytes); + m_comment.save_len = available_bytes; + VORBIS_LOG_DEBUG("partial_end {}", m_comment.start_pos + m_comment.save_len); + m_comment.item_vec.push_back(m_comment.start_pos + m_comment.save_len); + m_comment.pointer = 0; + m_comment.oob = true; + return VORBIS_COMMENT_NEED_MORE; + } + } + return VORBIS_COMMENT_NEED_MORE; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::parseVorbisCodebook() { + + int32_t i; + int32_t ret = 0; + + m_nrOfCodebooks = bitReader(8) + 1; + m_codebooks.calloc_array(m_nrOfCodebooks, "m_codebooks"); + VORBIS_LOG_DEBUG("nr of codebooks {}", m_nrOfCodebooks); + for (i = 0; i < m_nrOfCodebooks; i++) { + VORBIS_LOG_DEBUG("codebooks {}", i); + ret = vorbis_book_unpack(m_codebooks.get() + i); + if (ret) VORBIS_LOG_ERROR("Vorbis codebook {} returned a err", i); + if (ret) goto err_out; + } + + /* time backend settings, not actually used */ + i = bitReader(6); + for (; i >= 0; i--) { + ret = bitReader(16); + if (ret != 0) { + VORBIS_LOG_ERROR("err while reading backend settings"); + goto err_out; + } + } + /* floor backend settings */ + m_nrOfFloors = bitReader(6) + 1; + m_floor_param.calloc_array(m_nrOfFloors, "m_floor_param"); + m_floor_type.alloc(sizeof(int8_t) * m_nrOfFloors, "m_floor_type"); + VORBIS_LOG_DEBUG("nr of floors {}", m_nrOfFloors); + for (i = 0; i < m_nrOfFloors; i++) { + VORBIS_LOG_DEBUG("floors {}", i); + m_floor_type[i] = bitReader(16); + if (m_floor_type[i] < 0 || m_floor_type[i] >= VI_FLOORB) { + VORBIS_LOG_ERROR("err while reading floors"); + goto err_out; + } + if (m_floor_type[i]) { + m_floor_param[i] = floor1_info_unpack(); + } else { + m_floor_param[i] = floor0_info_unpack(); + } + if (!m_floor_param[i].valid()) { + VORBIS_LOG_ERROR("floor parameter not found"); + goto err_out; + } + } + + /* residue backend settings */ + m_nrOfResidues = bitReader(6) + 1; + m_residue_param.calloc_array(m_nrOfResidues, "m_residue_param"); + VORBIS_LOG_DEBUG("nr of residues {}", m_nrOfResidues); + for (i = 0; i < m_nrOfResidues; i++) { + VORBIS_LOG_DEBUG("residue {}", i); + if (res_unpack(m_residue_param.get() + i)) { + VORBIS_LOG_ERROR("err while unpacking residues"); + goto err_out; + } + } + + // /* map backend settings */ + m_nrOfMaps = bitReader(6) + 1; + m_map_param.calloc_array(m_nrOfMaps, "m_map_param"); + for (i = 0; i < m_nrOfMaps; i++) { + if (bitReader(16) != 0) goto err_out; + if (mapping_info_unpack(m_map_param.get() + i)) { + VORBIS_LOG_ERROR("err while unpacking mappings"); + goto err_out; + } + } + + /* mode settings */ + m_nrOfModes = bitReader(6) + 1; + m_mode_param.alloc(sizeof(vorbis_info_mode_t) * m_nrOfModes, "m_mode_param"); + for (i = 0; i < m_nrOfModes; i++) { + m_mode_param[i].blockflag = bitReader(1); + if (bitReader(16)) goto err_out; + if (bitReader(16)) goto err_out; + m_mode_param[i].mapping = bitReader(8); + if (m_mode_param[i].mapping >= m_nrOfMaps) { + VORBIS_LOG_ERROR("too many modes"); + goto err_out; + } + } + + if (bitReader(1) != 1) { + VORBIS_LOG_ERROR("codebooks, end bit not found"); + goto err_out; + } + // if(m_setupHeaderLength != m_bitReader.headptr - m_bitReader.data){ + // VORBIS_LOG_ERROR("Error reading setup header, assumed {} bytes, read {} bytes", m_setupHeaderLength, m_bitReader.headptr - m_bitReader.data); + // goto err_out; + // } + /* top level EOP check */ + + return VORBIS_PARSE_OGG_DONE; + +err_out: + // vorbis_info_clear(vi); + VORBIS_LOG_ERROR("err in codebook! at pos {}", m_bitReader.headptr - m_bitReader.data); + return (OV_EBADHEADER); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::parse_OGG(uint8_t* inbuf, int32_t* bytesLeft) { + // reference https://www.xiph.org/ogg/doc/rfc3533.txt + int32_t ret = 0; + uint32_t ogg_lengt_total = 0; + (void)ret; + int32_t idx = special_index_of(inbuf, "OggS", 8192); + if (idx != 0) { + if (m_f_oggContinuedPage) { + VORBIS_LOG_ERROR("Vorbis decoder asynchron, 'OggS' not found"); + return VORBIS_ERR; + } + inbuf += idx; + *bytesLeft -= idx; + } + uint8_t version = *(inbuf + 4); + (void)version; + uint8_t headerType = *(inbuf + 5); + (void)headerType; + uint64_t granulePosition = (uint64_t)*(inbuf + 13) << 56; // granule_position: an 8 Byte field containing - + granulePosition += (uint64_t)*(inbuf + 12) << 48; // position information. For an audio stream, it MAY + granulePosition += (uint64_t)*(inbuf + 11) << 40; // contain the total number of PCM samples encoded + granulePosition += (uint64_t)*(inbuf + 10) << 32; // after including all frames finished on this page. + granulePosition += *(inbuf + 9) << 24; // This is a hint for the decoder and gives it some timing + granulePosition += *(inbuf + 8) << 16; // and position information. A special value of -1 (in two's + granulePosition += *(inbuf + 7) << 8; // complement) indicates that no packets finish on this page. + granulePosition += *(inbuf + 6); + (void)granulePosition; + uint32_t bitstreamSerialNr = *(inbuf + 17) << 24; // bitstream_serial_number: a 4 Byte field containing the + bitstreamSerialNr += *(inbuf + 16) << 16; // unique serial number by which the logical bitstream + bitstreamSerialNr += *(inbuf + 15) << 8; // is identified. + bitstreamSerialNr += *(inbuf + 14); + (void)bitstreamSerialNr; + uint32_t pageSequenceNr = *(inbuf + 21) << 24; // page_sequence_number: a 4 Byte field containing the sequence + pageSequenceNr += *(inbuf + 20) << 16; // number of the page so the decoder can identify page loss + pageSequenceNr += *(inbuf + 19) << 8; // This sequence number is increasing on each logical bitstream + pageSequenceNr += *(inbuf + 18); + (void)pageSequenceNr; + uint32_t CRCchecksum = *(inbuf + 25) << 24; + CRCchecksum += *(inbuf + 24) << 16; + CRCchecksum += *(inbuf + 23) << 8; + CRCchecksum += *(inbuf + 22); + (void)CRCchecksum; + uint8_t pageSegments = *(inbuf + 26); // giving the number of segment entries + // read the segment table (contains pageSegments bytes), 1...251: Length of the frame in bytes, + // 255: A second byte is needed. The total length is first_byte + second byte + + ogg_lengt_total = 27 + pageSegments; + for (int32_t i = 0; i < pageSegments; i++) { + int32_t n = *(inbuf + 27 + i); + while (*(inbuf + 27 + i) == 255) { + i++; + if (i == pageSegments) break; + n += *(inbuf + 27 + i); + } + m_ogg_items.segment_table.push_back(n); + ogg_lengt_total += n; + } + m_vorbisCompressionRatio = (float)(960 * 2 * pageSegments) / ogg_lengt_total; // const 960 validBytes out + + bool continuedPage = headerType & 0x01; // set: page contains data of a packet continued from the previous page + bool firstPage = headerType & 0x02; // set: this is the first page of a logical bitstream (bos) + bool lastPage = headerType & 0x04; // set: this is the last page of a logical bitstream (eos) + + uint16_t headerSize = pageSegments + 27; + + // VORBIS_LOG_INFO("headerSize {}, m_vorbisSegmentLength {}, m_vorbisSegmentTableSize {}", headerSize, m_vorbisSegmentLength, m_vorbisSegmentTableSize); + if (firstPage || continuedPage || lastPage) { + // VORBIS_LOG_INFO("firstPage {} continuedPage {} lastPage {}", firstPage, continuedPage, lastPage); + } + + *bytesLeft -= headerSize; + inbuf += headerSize; + + m_f_oggFirstPage = firstPage; + m_f_oggContinuedPage = continuedPage; + m_f_oggLastPage = lastPage; + + if (firstPage) { m_pageNr = 0; } + + return VORBIS_PARSE_OGG_DONE; // no error +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + // assume we have a ogg wrapper + int32_t idx = special_index_of(buf, "OggS", nBytes); + if (idx >= 0) { // Magic Word found + // VORBIS_LOG_INFO("OggS found at {}", idx); + return idx; + } + VORBIS_LOG_ERROR("Vorbis, sync 'OggS' not found"); + return VORBIS_ERR; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* VorbisDecoder::whoIsIt() { + return "VORBIS"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) { + return; // nothing todo +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::vorbis_book_unpack(codebook_t* s) { + ps_ptr lengthlist; + uint8_t quantvals = 0; + int32_t i, j; + int32_t maptype; + int32_t ret = 0; + + /* make sure alignment is correct */ + if (bitReader(24) != 0x564342) { + VORBIS_LOG_ERROR("Vorbis, string \"VCB\" not found"); // VorbisCodeBook + goto _eofout; // "BCV" + } + + /* first the basic parameters */ + ret = bitReader(16); + if (ret < 0) VORBIS_LOG_ERROR("error in vorbis_book_unpack, ret ={}", ret); + if (ret > 255) VORBIS_LOG_ERROR("error in vorbis_book_unpack, ret ={}", ret); + s->dim = (uint8_t)ret; + s->entries = bitReader(24); + if (s->entries == -1) { + VORBIS_LOG_ERROR("no entries in unpack codebooks ?"); + goto _eofout; + } + + /* codeword ordering.... length ordered or unordered? */ + switch (bitReader(1)) { + case 0: + /* unordered */ + lengthlist.alloc_array(s->entries * 2, "lengthlist"); + + /* allocated but unused entries? */ + if (bitReader(1)) { + /* yes, unused entries */ + + for (i = 0; i < s->entries; i++) { + if (bitReader(1)) { + int32_t num = bitReader(5); + if (num == -1) goto _eofout; + lengthlist[i] = num + 1; + s->used_entries++; + if (num + 1 > s->dec_maxlength) s->dec_maxlength = num + 1; + } else + lengthlist[i] = 0; + } + } else { + /* all entries used; no tagging */ + s->used_entries = s->entries; + for (i = 0; i < s->entries; i++) { + int32_t num = bitReader(5); + if (num == -1) goto _eofout; + lengthlist[i] = num + 1; + + if (num + 1 > s->dec_maxlength) s->dec_maxlength = num + 1; + } + } + break; + case 1: + /* ordered */ + { + int32_t length = bitReader(5) + 1; + + s->used_entries = s->entries; + lengthlist.alloc_array(s->entries * 2, "lengthlist"); + + for (i = 0; i < s->entries;) { + int32_t num = bitReader(_ilog(s->entries - i)); + if (num == -1) goto _eofout; + for (j = 0; j < num && i < s->entries; j++, i++) lengthlist[i] = length; + s->dec_maxlength = length; + length++; + } + } + break; + default: + /* EOF */ + goto _eofout; + } + + /* Do we have a mapping to unpack? */ + if ((maptype = bitReader(4)) > 0) { + s->q_min = _float32_unpack(bitReader(32), &s->q_minp); + s->q_del = _float32_unpack(bitReader(32), &s->q_delp); + + s->q_bits = bitReader(4) + 1; + s->q_seq = bitReader(1); + + s->q_del >>= s->q_bits; + s->q_delp += s->q_bits; + } + + switch (maptype) { + case 0: + /* no mapping; decode type 0 */ + /* how many bytes for the indexing? */ + /* this is the correct boundary here; we lose one bit to node/leaf mark */ + s->dec_nodeb = _determine_node_bytes(s->used_entries, _ilog(s->entries) / 8 + 1); + s->dec_leafw = _determine_leaf_words(s->dec_nodeb, _ilog(s->entries) / 8 + 1); + s->dec_type = 0; + ret = _make_decode_table(s, lengthlist.get(), quantvals, maptype); + if (ret != 0) { goto _errout; } + break; + + case 1: + /* mapping type 1; implicit values by lattice position */ + quantvals = _book_maptype1_quantvals(s); + + /* dec_type choices here are 1,2; 3 doesn't make sense */ + { + /* packed values */ + int32_t total1 = (s->q_bits * s->dim + 8) / 8; /* remember flag bit */ + /* vector of column offsets; remember flag bit */ + int32_t total2 = (_ilog(quantvals - 1) * s->dim + 8) / 8 + (s->q_bits + 7) / 8; + + if (total1 <= 4 && total1 <= total2) { + /* use dec_type 1: vector of packed values */ + /* need quantized values before */ + s->q_val.calloc_array(sizeof(uint16_t) * quantvals, "q_val"); + for (i = 0; i < quantvals; i++) ((uint16_t*)s->q_val.get())[i] = bitReader(s->q_bits); + + if (oggpack_eop()) { goto _eofout; } + + s->dec_type = 1; + s->dec_nodeb = _determine_node_bytes(s->used_entries, (s->q_bits * s->dim + 8) / 8); + s->dec_leafw = _determine_leaf_words(s->dec_nodeb, (s->q_bits * s->dim + 8) / 8); + ret = _make_decode_table(s, lengthlist.get(), quantvals, maptype); + if (ret) { goto _errout; } + } else { + /* use dec_type 2: packed vector of column offsets */ + /* need quantized values before */ + if (s->q_bits <= 8) { + s->q_val.alloc(quantvals, "q_val"); + for (i = 0; i < quantvals; i++) ((uint8_t*)s->q_val.get())[i] = bitReader(s->q_bits); + } else { + s->q_val.alloc(quantvals * 2, "q_val"); + for (i = 0; i < quantvals; i++) ((uint16_t*)s->q_val.get())[i] = bitReader(s->q_bits); + } + + if (oggpack_eop()) goto _eofout; + + s->q_pack = _ilog(quantvals - 1); + s->dec_type = 2; + s->dec_nodeb = _determine_node_bytes(s->used_entries, (_ilog(quantvals - 1) * s->dim + 8) / 8); + s->dec_leafw = _determine_leaf_words(s->dec_nodeb, (_ilog(quantvals - 1) * s->dim + 8) / 8); + + ret = _make_decode_table(s, lengthlist.get(), quantvals, maptype); + if (ret) { goto _errout; } + } + } + break; + case 2: + /* mapping type 2; explicit array of values */ + quantvals = s->entries * s->dim; + /* dec_type choices here are 1,3; 2 is not possible */ + + if ((s->q_bits * s->dim + 8) / 8 <= 4) { /* remember flag bit */ + /* use dec_type 1: vector of packed values */ + + s->dec_type = 1; + s->dec_nodeb = _determine_node_bytes(s->used_entries, (s->q_bits * s->dim + 8) / 8); + s->dec_leafw = _determine_leaf_words(s->dec_nodeb, (s->q_bits * s->dim + 8) / 8); + if (_make_decode_table(s, lengthlist.get(), quantvals, maptype)) goto _errout; + } else { + /* use dec_type 3: scalar offset into packed value array */ + + s->dec_type = 3; + s->dec_nodeb = _determine_node_bytes(s->used_entries, _ilog(s->used_entries - 1) / 8 + 1); + s->dec_leafw = _determine_leaf_words(s->dec_nodeb, _ilog(s->used_entries - 1) / 8 + 1); + if (_make_decode_table(s, lengthlist.get(), quantvals, maptype)) goto _errout; + + /* get the vals & pack them */ + s->q_pack = (s->q_bits + 7) / 8 * s->dim; + s->q_val.alloc(s->q_pack * s->used_entries, "q_val"); + + if (s->q_bits <= 8) { + for (i = 0; i < s->used_entries * s->dim; i++) ((uint8_t*)(s->q_val.get()))[i] = bitReader(s->q_bits); + } else { + for (i = 0; i < s->used_entries * s->dim; i++) ((uint16_t*)(s->q_val.get()))[i] = bitReader(s->q_bits); + } + } + break; + default: VORBIS_LOG_ERROR("maptype {} schould be 0, 1 or 2", maptype); goto _errout; + } + if (oggpack_eop()) goto _eofout; + return 0; // ok +_errout: +_eofout: + vorbis_book_clear(m_codebooks); + return VORBIS_ERR; // error +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::special_index_of(uint8_t* base, const char* str, int32_t baselen, bool exact) { + int32_t result = -1; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int32_t i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int32_t j = 0; j < strlen(str) + exact; j++) { + if (*(base + i + j) != *(str + j)) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::bitReader_setData(uint8_t* buff, uint32_t buffSize) { + m_bitReader.data = buff; + m_bitReader.headptr = buff; + m_bitReader.length = buffSize; + m_bitReader.headend = buffSize * 8; + m_bitReader.headbit = 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* Read in bits without advancing the bitptr; bits <= 32 */ +int32_t VorbisDecoder::bitReader_look(uint16_t nBits) { + uint32_t m = mask[nBits]; + int32_t ret = 0; + + nBits += m_bitReader.headbit; + + if (nBits >= m_bitReader.headend << 3) { + uint8_t* ptr = m_bitReader.headptr; + if (nBits) { + ret = *ptr++ >> m_bitReader.headbit; + if (nBits > 8) { + ret |= *ptr++ << (8 - m_bitReader.headbit); + if (nBits > 16) { + ret |= *ptr++ << (16 - m_bitReader.headbit); + if (nBits > 24) { + ret |= *ptr++ << (24 - m_bitReader.headbit); + if (nBits > 32 && m_bitReader.headbit) { ret |= *ptr << (32 - m_bitReader.headbit); } + } + } + } + } + } else { + /* make this a switch jump-table */ + ret = m_bitReader.headptr[0] >> m_bitReader.headbit; + if (nBits > 8) { + ret |= m_bitReader.headptr[1] << (8 - m_bitReader.headbit); + if (nBits > 16) { + ret |= m_bitReader.headptr[2] << (16 - m_bitReader.headbit); + if (nBits > 24) { + ret |= m_bitReader.headptr[3] << (24 - m_bitReader.headbit); + if (nBits > 32 && m_bitReader.headbit) ret |= m_bitReader.headptr[4] << (32 - m_bitReader.headbit); + } + } + } + } + + ret &= (int32_t)m; + return ret; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::bitReader(uint16_t nBits) { + if (!m_bitReader.headptr || nBits == 0) return 0; + + uint32_t val = 0; + uint32_t bits_collected = 0; + + while (nBits > 0) { + + // Check whether the BitReader is empty (end of the current Ogg page) + if (m_bitReader.headptr >= m_bitReader.data + m_bitReader.length) { + + // ------------------------------------------------------------ + // 🧩 Ogg limit exceeded → read next page + // ------------------------------------------------------------ + uint8_t leftover = 0; + uint8_t bits_left = 0; + + // If in the middle of the byte: save remaining bits + if (m_bitReader.headbit > 0 && m_bitReader.headptr > m_bitReader.data) { + leftover = *(m_bitReader.headptr - 1) >> (8 - m_bitReader.headbit); + bits_left = m_bitReader.headbit; + } + + // Load new Ogg page + int32_t oggLen = 256; + int32_t ret = parse_OGG(m_bitReader.headptr, &oggLen); + uint32_t header_consumed = (256 - oggLen); + VORBIS_LOG_DEBUG("header_consumed {}", header_consumed); + if (ret != VORBIS_PARSE_OGG_DONE) { + VORBIS_LOG_ERROR("bitReader: failed to continue across Ogg page"); + return -1; + } + + // Apply first segment + if (!m_ogg_items.segment_table.empty()) { + VORBIS_LOG_DEBUG("old segment {}", m_vorbis_segment_length); + m_vorbis_segment_length = m_ogg_items.segment_table.front(); + m_ogg_items.segment_table.pop_front(); + VORBIS_LOG_DEBUG("new segment {}", m_vorbis_segment_length); + uint32_t header_consumed = (256 - oggLen); + m_ogg_items.bytes_consumed_from_other = m_vorbis_segment_length + header_consumed; + } else { + VORBIS_LOG_ERROR("bitReader: empty Ogg segment table"); + return -1; + } + + // New page data starts behind header+lacing + uint8_t* newPage = m_bitReader.headptr + header_consumed; + bitReader_setData(newPage, m_vorbis_segment_length); + + // If remaining bits exist → append to the beginning of the new page + if (bits_left > 0) { + m_bitReader.data[0] = (m_bitReader.data[0] << bits_left) | leftover; + m_bitReader.headbit = bits_left; + } else { + m_bitReader.headbit = 0; + } + + m_bitReader.headptr = m_bitReader.data; + m_bitReader.headend = m_vorbis_segment_length; + + VORBIS_LOG_INFO("BitReader: crossed Ogg boundary (bits_left={}, new_segment={})", bits_left, m_vorbis_segment_length); + continue; + } + + // ------------------------------------------------------------ + // 🧩 Normal reading of bits from the current byte + // ------------------------------------------------------------ + uint8_t current_byte = *m_bitReader.headptr; + uint32_t bits_avail = 8 - m_bitReader.headbit; + uint32_t take = std::min(bits_avail, nBits); + + uint32_t mask = ((1u << take) - 1); + val |= ((current_byte >> m_bitReader.headbit) & mask) << bits_collected; + + bits_collected += take; + nBits -= take; + m_bitReader.headbit += take; + + // Byte vollständig gelesen? + if (m_bitReader.headbit >= 8) { + m_bitReader.headbit = 0; + m_bitReader.headptr++; + m_bitReader.headend--; + } + } + + if (m_bitReader.headend <= 0) { VORBIS_LOG_WARN("bitReader nearly empty: {} bytes left", m_bitReader.headend); } + + return val; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int8_t VorbisDecoder::bitReader_adv(uint16_t nBits) { + // new bit position in the current byte + uint32_t newBit = m_bitReader.headbit + nBits; + + // Calculate how many whole bytes we skip + uint32_t byteAdvance = newBit >> 3; + + // Remaining bits in the current byte + m_bitReader.headbit = newBit & 7; + + // Check if we would go past the end + if (byteAdvance > (uint32_t)m_bitReader.headend || (byteAdvance == (uint32_t)m_bitReader.headend && m_bitReader.headbit > 0)) { + VORBIS_LOG_ERROR("bitReader_adv: ran out of data (advance={}, left={})", byteAdvance, m_bitReader.headend); + return -1; + } + + // Continue byte pointer + m_bitReader.headptr += byteAdvance; + m_bitReader.headend -= byteAdvance; + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::ilog(uint32_t v) { + int32_t ret = 0; + if (v) --v; + while (v) { + ret++; + v >>= 1; + } + return (ret); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t VorbisDecoder::_ilog(uint32_t v) { + uint8_t ret = 0; + while (v) { + ret++; + v >>= 1; + } + return (ret); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 32 bit float (not IEEE; nonnormalized mantissa + biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + Why not IEEE? It's just not that important here. */ + +int32_t VorbisDecoder::_float32_unpack(int32_t val, int32_t* point) { + int32_t mant = val & 0x1fffff; + bool sign = val < 0; + + *point = ((val & 0x7fe00000L) >> 21) - 788; + + if (mant) { + while (!(mant & 0x40000000)) { + mant <<= 1; + *point -= 1; + } + if (sign) mant = -mant; + } else { + *point = -9999; + } + return mant; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* choose the smallest supported node size that fits our decode table. Legal bytewidths are 1/1 1/2 2/2 2/4 4/4 */ +int32_t VorbisDecoder::_determine_node_bytes(uint32_t used, uint8_t leafwidth) { + /* special case small books to size 4 to avoid multiple special cases in repack */ + if (used < 2) return 4; + + if (leafwidth == 3) leafwidth = 4; + if (_ilog((3 * used - 6)) + 1 <= leafwidth * 4) return leafwidth / 2 ? leafwidth / 2 : 1; + return leafwidth; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* convenience/clarity; leaves are specified as multiple of node word size (1 or 2) */ +int32_t VorbisDecoder::_determine_leaf_words(int32_t nodeb, int32_t leafwidth) { + if (leafwidth > nodeb) return 2; + return 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::_make_decode_table(codebook_t* s, int32_t* lengthlist, uint8_t quantvals, int32_t maptype) { + ps_ptr work; + + if (s->dec_nodeb == 4) { + s->dec_table.alloc((s->used_entries + 1) * sizeof(*work), "dec_table"); + /* +1 (rather than -2) is to accommodate 0 and 1 sized books, which are specialcased to nodeb==4 */ + if (_make_words(lengthlist, s->entries, (uint32_t*)s->dec_table.get(), quantvals, s, maptype)) return 1; + + return 0; + } + + work.alloc((s->used_entries * 2) * sizeof(int32_t), "work"); + work.clear(); + + if (_make_words(lengthlist, s->entries, work.get(), quantvals, s, maptype)) { return 1; } + s->dec_table.alloc((s->used_entries * (s->dec_leafw + 1) - 2) * s->dec_nodeb, "dec_table"); + if (s->dec_leafw == 1) { + switch (s->dec_nodeb) { + case 1: + for (uint32_t i = 0; i < s->used_entries * 2 - 2; i++) ((uint8_t*)s->dec_table.get())[i] = (uint16_t)((work[i] & 0x80000000UL) >> 24) | work[i]; + break; + case 2: + for (uint32_t i = 0; i < s->used_entries * 2 - 2; i++) ((uint16_t*)s->dec_table.get())[i] = (uint16_t)((work[i] & 0x80000000UL) >> 16) | work[i]; + break; + } + } else { + /* more complex; we have to do a two-pass repack that updates the node indexing. */ + uint32_t top = s->used_entries * 3 - 2; + if (s->dec_nodeb == 1) { + uint8_t* out = (uint8_t*)s->dec_table.get(); + + for (int32_t i = s->used_entries * 2 - 4; i >= 0; i -= 2) { + if (work[i] & 0x80000000UL) { + if (work[i + 1] & 0x80000000UL) { + top -= 4; + out[top] = (uint8_t)(work[i] >> 8 & 0x7f) | 0x80; + out[top + 1] = (uint8_t)(work[i + 1] >> 8 & 0x7f) | 0x80; + out[top + 2] = (uint8_t)work[i] & 0xff; + out[top + 3] = (uint8_t)work[i + 1] & 0xff; + } else { + top -= 3; + out[top] = (uint8_t)(work[i] >> 8 & 0x7f) | 0x80; + out[top + 1] = (uint8_t)work[work[i + 1] * 2]; + out[top + 2] = (uint8_t)work[i] & 0xff; + } + } else { + if (work[i + 1] & 0x80000000UL) { + top -= 3; + out[top] = (uint8_t)work[work[i] * 2]; + out[top + 1] = (uint8_t)(work[i + 1] >> 8 & 0x7f) | 0x80; + out[top + 2] = (uint8_t)work[i + 1] & 0xff; + } else { + top -= 2; + out[top] = (uint8_t)work[work[i] * 2]; + out[top + 1] = (uint8_t)work[work[i + 1] * 2]; + } + } + work[i] = top; + } + } else { + uint16_t* out = (uint16_t*)s->dec_table.get(); + for (int32_t i = s->used_entries * 2 - 4; i >= 0; i -= 2) { + if (work[i] & 0x80000000UL) { + if (work[i + 1] & 0x80000000UL) { + top -= 4; + out[top] = (uint16_t)(work[i] >> 16 & 0x7fff) | 0x8000; + out[top + 1] = (uint16_t)(work[i + 1] >> 16 & 0x7fff) | 0x8000; + out[top + 2] = (uint16_t)work[i] & 0xffff; + out[top + 3] = (uint16_t)work[i + 1] & 0xffff; + } else { + top -= 3; + out[top] = (uint16_t)(work[i] >> 16 & 0x7fff) | 0x8000; + out[top + 1] = (uint16_t)work[work[i + 1] * 2]; + out[top + 2] = (uint16_t)work[i] & 0xffff; + } + } else { + if (work[i + 1] & 0x80000000UL) { + top -= 3; + out[top] = (uint16_t)work[work[i] * 2]; + out[top + 1] = (uint16_t)(work[i + 1] >> 16 & 0x7fff) | 0x8000; + out[top + 2] = (uint16_t)work[i + 1] & 0xffff; + } else { + top -= 2; + out[top] = (uint16_t)work[work[i] * 2]; + out[top + 1] = (uint16_t)work[work[i + 1] * 2]; + } + } + work[i] = (uint32_t)top; + } + } + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* given a list of word lengths, number of used entries, and byte width of a leaf, generate the decode table */ +int32_t VorbisDecoder::_make_words(int32_t* l, uint16_t n, uint32_t* work, uint8_t quantvals, codebook_t* b, int32_t maptype) { + + int32_t i, j, count = 0; + uint32_t top = 0; + uint32_t marker[33]; + + if (n < 2) { + work[0] = 0x80000000; + } else { + memset(marker, 0, sizeof(marker)); + + for (i = 0; i < n; i++) { + int32_t length = l[i]; + if (length) { + uint32_t entry = marker[length]; + uint32_t chase = 0; + if (count && !entry) return -1; /* overpopulated tree! */ + + /* chase the tree as far as it's already populated, fill in past */ + for (j = 0; j < length - 1; j++) { + uint32_t bit = (entry >> (length - j - 1)) & 1; + if (chase >= top) { + top++; + work[chase * 2] = top; + work[chase * 2 + 1] = 0; + } else if (!work[chase * 2 + bit]) { + work[chase * 2 + bit] = top; + } + chase = work[chase * 2 + bit]; + } + { + int32_t bit = (entry >> (length - j - 1)) & 1; + if (chase >= top) { + top++; + work[chase * 2 + 1] = 0; + } + work[chase * 2 + bit] = decpack(i, count++, quantvals, b, maptype) | 0x80000000; + } + + /* Look to see if the next shorter marker points to the node above. if so, update it and repeat. */ + for (j = length; j > 0; j--) { + if (marker[j] & 1) { + marker[j] = marker[j - 1] << 1; + break; + } + marker[j]++; + } + + /* prune the tree; the implicit invariant says all the int32_ter markers were dangling from our + just-taken node. Dangle them from our *new* node. */ + for (j = length + 1; j < 33; j++) + if ((marker[j] >> 1) == entry) { + entry = marker[j]; + marker[j] = marker[j - 1] << 1; + } else + break; + } + } + } + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::decpack(int32_t entry, int32_t used_entry, uint8_t quantvals, codebook_t* b, int32_t maptype) { + uint32_t ret = 0; + + switch (b->dec_type) { + case 0: return (uint32_t)entry; + + case 1: + if (maptype == 1) { + /* vals are already read into temporary column vector here */ + assert(b->dim >= 0); + for (uint8_t j = 0; j < b->dim; j++) { + uint32_t off = (uint32_t)(entry % quantvals); + entry /= quantvals; + assert((b->q_bits * j) >= 0); + uint32_t shift = (uint32_t)b->q_bits * j; + ret |= ((uint16_t*)(b->q_val.get()))[off] << shift; + } + } else { + assert(b->dim >= 0); + for (uint8_t j = 0; j < b->dim; j++) { + assert((b->q_bits * j) >= 0); + uint32_t shift = (uint32_t)b->q_bits * j; + int32_t _ret = bitReader(b->q_bits) << shift; + assert(_ret >= 0); + ret |= (uint32_t)_ret; + } + } + return ret; + + case 2: + assert(b->dim >= 0); + for (uint8_t j = 0; j < b->dim; j++) { + uint32_t off = uint32_t(entry % quantvals); + entry /= quantvals; + assert(b->q_pack * j >= 0); + assert(b->q_pack * j <= 255); + ret |= off << (uint8_t)(b->q_pack * j); + } + return ret; + + case 3: return (uint32_t)used_entry; + } + return 0; /* silence compiler */ +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* most of the time, entries%dimensions == 0, but we need to be well defined. We define that the possible vales at each scalar is values == entries/dim. If entries%dim != 0, we'll have 'too few' + values (values*dimentries); + uint8_t vals = b->entries >> ((bits - 1) * (b->dim - 1) / b->dim); + + while (1) { + uint32_t acc = 1; + uint32_t acc1 = 1; + + for (uint8_t i = 0; i < b->dim; i++) { + acc *= vals; + acc1 *= vals + 1; + } + if (acc <= b->entries && acc1 > b->entries) { + return (vals); + } else { + if (acc > b->entries) { + vals--; + } else { + vals++; + } + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::oggpack_eop() { + if (m_bitReader.headptr - m_bitReader.data > m_bitReader.length) { + VORBIS_LOG_INFO("s_bitReader.headptr - data {}, bitReader.length {}", m_bitReader.headptr - m_bitReader.data, m_bitReader.length); + return -1; + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +ps_ptr VorbisDecoder::floor0_info_unpack() { + + int32_t j; + + ps_ptr info; + info.calloc_array(1, "info"); + + info->order = bitReader(8); + info->rate = bitReader(16); + info->barkmap = bitReader(16); + info->ampbits = bitReader(6); + info->ampdB = bitReader(8); + info->numbooks = bitReader(4) + 1; + + if (info->order < 1) goto err_out; + if (info->rate < 1) goto err_out; + if (info->barkmap < 1) goto err_out; + + for (j = 0; j < info->numbooks; j++) { + info->books[j] = bitReader(8); + if (info->books[j] >= m_nrOfCodebooks) goto err_out; + } + + if (oggpack_eop()) goto err_out; + return (info); + +err_out: + return {}; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +ps_ptr VorbisDecoder::floor1_info_unpack() { + + ps_ptr B; + int32_t j, k, count = 0, maxclass = -1, rangebits; + + ps_ptr info; + info.calloc_array(1, "info"); + + /* read partitions */ + info->partitions = bitReader(5); /* only 0 to 31 legal */ + info->partitionclass.alloc(info->partitions * sizeof(uint8_t), "partitionclass"); + for (j = 0; j < info->partitions; j++) { + info->partitionclass[j] = bitReader(4); /* only 0 to 15 legal */ + if (maxclass < info->partitionclass[j]) maxclass = info->partitionclass[j]; + } + + /* read partition classes */ + info->_class.alloc((uint32_t)(maxclass + 1) * sizeof(floor1class_t), "_class"); + for (j = 0; j < maxclass + 1; j++) { + info->_class[j].class_dim = bitReader(3) + 1; /* 1 to 8 */ + info->_class[j].class_subs = bitReader(2); /* 0,1,2,3 bits */ + if (oggpack_eop() < 0) goto err_out; + if (info->_class[j].class_subs) { + info->_class[j].class_book = bitReader(8); + } else { + info->_class[j].class_book = 0; + } + if (info->_class[j].class_book >= m_nrOfCodebooks) goto err_out; + for (k = 0; k < (1 << info->_class[j].class_subs); k++) { + info->_class[j].class_subbook[k] = (uint8_t)bitReader(8) - 1; + if (info->_class[j].class_subbook[k] >= m_nrOfCodebooks && info->_class[j].class_subbook[k] != 0xff) goto err_out; + } + } + + /* read the post list */ + info->mult = bitReader(2) + 1; /* only 1,2,3,4 legal now */ + rangebits = bitReader(4); + + for (j = 0, k = 0; j < info->partitions; j++) count += info->_class[info->partitionclass[j]].class_dim; + info->postlist.alloc((count + 2) * sizeof(uint16_t), "postlist"); + info->forward_index.alloc((count + 2) * sizeof(uint8_t), "forward_index"); + info->loneighbor.alloc(count * sizeof(uint8_t), "loneighbor"); + info->hineighbor.alloc(count * sizeof(uint8_t), "hineighbor"); + + count = 0; + for (j = 0, k = 0; j < info->partitions; j++) { + count += info->_class[info->partitionclass[j]].class_dim; + if (count > VIF_POSIT) goto err_out; + for (; k < count; k++) { + int32_t t = info->postlist[k + 2] = bitReader(rangebits); + if (t >= (1 << rangebits)) goto err_out; + } + } + if (oggpack_eop()) goto err_out; + info->postlist[0] = 0; + info->postlist[1] = 1 << rangebits; + info->posts = count + 2; + + /* also store a sorted position index */ + for (j = 0; j < info->posts; j++) info->forward_index[j] = j; + + // vorbis_mergesort-------------------------------------------------------------------------------- + vorbis_mergesort(info->forward_index.get(), info->postlist.get(), info->posts); + //------------------------------------------------------------------------------------------------- + /* discover our neighbors for decode where we don't use fit flags (that would push the neighbors outward) */ + for (j = 0; j < info->posts - 2; j++) { + int32_t lo = 0; + int32_t hi = 1; + int32_t lx = 0; + int32_t hx = info->postlist[1]; + int32_t currentx = info->postlist[j + 2]; + for (k = 0; k < j + 2; k++) { + int32_t x = info->postlist[k]; + if (x > lx && x < currentx) { + lo = k; + lx = x; + } + if (x < hx && x > currentx) { + hi = k; + hx = x; + } + } + info->loneighbor[j] = lo; + info->hineighbor[j] = hi; + } + + return (info); + +err_out: + return {}; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::vorbis_mergesort(uint8_t* index, uint16_t* vals, uint16_t n) { + uint16_t i, j; + ps_ptr B_mem; + B_mem.alloc(n * sizeof(uint8_t)); + + if (!B_mem.valid()) return; + + uint8_t* A = index; + uint8_t* B = B_mem.get(); + bool flipped = false; + + for (i = 1; i < n; i <<= 1) { + for (j = 0; j + i < n;) { + uint16_t k1 = j; + uint16_t mid = j + i; + uint16_t k2 = mid; + uint16_t end = (j + i * 2 < n ? j + i * 2 : n); + while (k1 < mid && k2 < end) { + if (vals[A[k1]] < vals[A[k2]]) + B[j++] = A[k1++]; + else + B[j++] = A[k2++]; + } + while (k1 < mid) B[j++] = A[k1++]; + while (k2 < end) B[j++] = A[k2++]; + } + + for (; j < n; j++) B[j] = A[j]; + + std::swap(A, B); // swap pointer + flipped = !flipped; + } + + if (A != index) { + std::memcpy(index, A, n); // result back to index + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* vorbis_info is for range checking */ +int32_t VorbisDecoder::res_unpack(vorbis_info_residue* info) { + int32_t j, k; + + info->type = bitReader(16); + if (info->type > 2 || info->type < 0) goto errout; + info->begin = bitReader(24); + info->end = bitReader(24); + info->grouping = bitReader(24) + 1; + info->partitions = bitReader(6) + 1; + info->groupbook = bitReader(8); + if (info->groupbook >= m_nrOfCodebooks) goto errout; + + info->stagemasks.alloc(info->partitions * sizeof(uint8_t)); + info->stagebooks.alloc(info->partitions * 8 * sizeof(uint8_t)); + + for (j = 0; j < info->partitions; j++) { + int32_t cascade = bitReader(3); + if (bitReader(1)) cascade |= (bitReader(5) << 3); + info->stagemasks[j] = cascade; + } + + for (j = 0; j < info->partitions; j++) { + for (k = 0; k < 8; k++) { + if ((info->stagemasks[j] >> k) & 1) { + uint8_t book = bitReader(8); + if (book >= m_nrOfCodebooks) goto errout; + info->stagebooks[j * 8 + k] = book; + if (k + 1 > info->stages) info->stages = k + 1; + } else + info->stagebooks[j * 8 + k] = 0xff; + } + } + + if (oggpack_eop()) goto errout; + + return 0; +errout: + return 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* also responsible for range checking */ +int32_t VorbisDecoder::mapping_info_unpack(vorbis_info_mapping* info) { + int32_t i; + + if (bitReader(1)) + info->submaps = bitReader(4) + 1; + else + info->submaps = 1; + + if (bitReader(1)) { + info->coupling_steps = bitReader(8) + 1; + info->coupling.alloc(info->coupling_steps * sizeof(coupling_step_t)); + + for (i = 0; i < info->coupling_steps; i++) { + int32_t testM = info->coupling[i].mag = bitReader(ilog(m_vorbisChannels)); + int32_t testA = info->coupling[i].ang = bitReader(ilog(m_vorbisChannels)); + + if (testM < 0 || testA < 0 || testM == testA || testM >= m_vorbisChannels || testA >= m_vorbisChannels) goto err_out; + } + } + + if (bitReader(2) > 0) goto err_out; + /* 2,3:reserved */ + + if (info->submaps > 1) { + info->chmuxlist.alloc(sizeof(uint8_t) * m_vorbisChannels); + for (i = 0; i < m_vorbisChannels; i++) { + info->chmuxlist[i] = bitReader(4); + if (info->chmuxlist[i] >= info->submaps) goto err_out; + } + } + + info->submaplist.alloc(sizeof(submap_t) * info->submaps); + for (i = 0; i < info->submaps; i++) { + int32_t temp = bitReader(8); + (void)temp; + info->submaplist[i].floor = bitReader(8); + if (info->submaplist[i].floor >= m_nrOfFloors) goto err_out; + info->submaplist[i].residue = bitReader(8); + if (info->submaplist[i].residue >= m_nrOfResidues) goto err_out; + } + + return 0; + +err_out: + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// ⏫⏫⏫ O G G I M P L A B O V E ⏫⏫⏫ +// ⏬⏬⏬ V O R B I S I M P L B E L O W ⏬⏬⏬ +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +ps_ptr VorbisDecoder::vorbis_dsp_create() { + ps_ptr v; + v.calloc_array(1); + v->work.calloc_array(m_vorbisChannels); + v->mdctright.calloc_array(m_vorbisChannels); + + for (uint8_t i = 0; i < m_vorbisChannels; ++i) { + const size_t work_size = (m_blocksizes[1] >> 1) * sizeof(int32_t); + v->work.at(i).calloc(work_size); + + const size_t mdct_size = (m_blocksizes[1] >> 2) * sizeof(int32_t); + v->mdctright.at(i).calloc(mdct_size); + } + + // Initialize state + v->lW = 0; + v->W = 0; + v->out_begin = -1; + v->out_end = -1; + + return v; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::vorbis_dsp_destroy(ps_ptr& v) { + if (!v.valid()) return; + + for (uint8_t i = 0; i < m_vorbisChannels; ++i) { + v->work.at(i).reset(); + v->mdctright.at(i).reset(); + } + v->mdctright.reset(); + v->work.reset(); + v.reset(); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::vorbis_book_clear(ps_ptr& v) { + if (!v.valid()) return; + int s = 0; + for (int i = 0; i < m_nrOfCodebooks; i++) { + if (v[i].q_val.valid()) { + s += v[i].q_val.size(); + v[i].q_val.reset(); + } + if (v[i].dec_table.valid()) { + s += v[i].dec_table.size(); + v[i].dec_table.reset(); + } + } + if (v->dec_table.valid()) { + s += v->dec_table.size(); + v->dec_table.reset(); + } + if (v->q_val.valid()) { + s += v->q_val.size(); + v->q_val.reset(); + } + s += v.size(); + v.reset(); + m_nrOfCodebooks = 0; + // VORBIS_LOG_INFO("free codebook_t {} bytes", s); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::vorbis_dsp_synthesis(uint8_t* inbuf, uint16_t len, int16_t* outbuf) { + + int32_t mode, i; + + /* Check the packet type */ + if (bitReader(1) != 0) { + /* Oops. This is not an audio data packet */ + return OV_ENOTAUDIO; + } + + /* read our mode and pre/post windowsize */ + mode = bitReader(ilog(m_nrOfModes)); + if (mode == -1 || mode >= m_nrOfModes) return OV_EBADPACKET; + + /* shift information we still need from last window */ + m_dsp_state->lW = m_dsp_state->W; + m_dsp_state->W = m_mode_param[mode].blockflag; + for (i = 0; i < m_vorbisChannels; i++) { mdct_shift_right(m_blocksizes[m_dsp_state->lW], m_dsp_state->work[i].get(), m_dsp_state->mdctright[i].get()); } + if (m_dsp_state->W) { + int32_t temp; + bitReader(1); + temp = bitReader(1); + if (temp == -1) return OV_EBADPACKET; + } + + /* packet decode and portions of synthesis that rely on only this block */ + { + mapping_inverse(m_map_param.get() + m_mode_param[mode].mapping); + + if (m_dsp_state->out_begin == -1) { + m_dsp_state->out_begin = 0; + m_dsp_state->out_end = 0; + } else { + m_dsp_state->out_begin = 0; + m_dsp_state->out_end = m_blocksizes[m_dsp_state->lW] / 4 + m_blocksizes[m_dsp_state->W] / 4; + } + } + + return (0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_shift_right(int32_t n, int32_t* in, int32_t* right) { + int32_t i; + n >>= 2; + in += 1; + + for (i = 0; i < n; i++) right[i] = in[i << 1]; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::mapping_inverse(vorbis_info_mapping* info) { + + int32_t i, j; + int32_t n = m_blocksizes[m_dsp_state->W]; + + ps_ptr pcmbundle; + pcmbundle.calloc_array(m_vorbisChannels); + ps_ptr zerobundle; + zerobundle.alloc(sizeof(int32_t) * m_vorbisChannels); + ps_ptr nonzero; + nonzero.alloc(sizeof(int32_t) * m_vorbisChannels); + ps_ptr> floormemo; + floormemo.calloc_array(m_vorbisChannels); + + /* recover the spectral envelope; store it in the PCM vector for now */ + for (i = 0; i < m_vorbisChannels; i++) { + + int32_t submap = 0; + int32_t floorno; + + if (info->submaps > 1) submap = info->chmuxlist[i]; + floorno = info->submaplist[submap].floor; + + if (m_floor_type[floorno]) { + /* floor 1 */ + floormemo[i].alloc(sizeof(*floormemo[i]) * floor1_memosize(m_floor_param[floorno])); + floormemo[i] = floor1_inverse1(m_floor_param[floorno], floormemo[i].get()); + } else { + /* floor 0 */ + floormemo[i].alloc(sizeof(*floormemo[i]) * floor0_memosize(m_floor_param[floorno])); + floormemo[i] = floor0_inverse1(m_floor_param[floorno], floormemo[i].get()); + } + + if (floormemo[i].get()) + nonzero[i] = 1; + else + nonzero[i] = 0; + memset(m_dsp_state->work[i].get(), 0, sizeof(*m_dsp_state->work[i]) * n / 2); + } + + /* channel coupling can 'dirty' the nonzero listing */ + for (i = 0; i < info->coupling_steps; i++) { + if (nonzero[info->coupling[i].mag] || nonzero[info->coupling[i].ang]) { + nonzero[info->coupling[i].mag] = 1; + nonzero[info->coupling[i].ang] = 1; + } + } + + /* recover the residue into our working vectors */ + for (i = 0; i < info->submaps; i++) { + uint8_t ch_in_bundle = 0; + for (j = 0; j < m_vorbisChannels; j++) { + if (!info->chmuxlist.get() || info->chmuxlist[j] == i) { + if (nonzero[j]) + zerobundle[ch_in_bundle] = 1; + else + zerobundle[ch_in_bundle] = 0; + pcmbundle[ch_in_bundle++] = m_dsp_state->work[j].get(); + } + } + res_inverse(m_residue_param.get() + info->submaplist[i].residue, pcmbundle.get(), zerobundle.get(), ch_in_bundle); + } + + // for(j=0;jchannels;j++) + //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); + + /* channel coupling */ + for (i = info->coupling_steps - 1; i >= 0; i--) { + int32_t* pcmM = m_dsp_state->work[info->coupling[i].mag].get(); + int32_t* pcmA = m_dsp_state->work[info->coupling[i].ang].get(); + + for (j = 0; j < n / 2; j++) { + int32_t mag = pcmM[j]; + int32_t ang = pcmA[j]; + + if (mag > 0) + if (ang > 0) { + pcmM[j] = mag; + pcmA[j] = mag - ang; + } else { + pcmA[j] = mag; + pcmM[j] = mag + ang; + } + else if (ang > 0) { + pcmM[j] = mag; + pcmA[j] = mag + ang; + } else { + pcmA[j] = mag; + pcmM[j] = mag - ang; + } + } + } + + // for(j=0;jchannels;j++) + //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); + + /* compute and apply spectral envelope */ + + for (i = 0; i < m_vorbisChannels; i++) { + int32_t* pcm = m_dsp_state->work[i].get(); + int32_t submap = 0; + int32_t floorno; + + if (info->submaps > 1) submap = info->chmuxlist[i]; + floorno = info->submaplist[submap].floor; + + if (m_floor_type[floorno]) { + /* floor 1 */ + floor1_inverse2(m_floor_param[floorno], floormemo[i].get(), pcm); + } else { + /* floor 0 */ + floor0_inverse2(m_floor_param[floorno], floormemo[i].get(), pcm); + } + floormemo[i].reset(); + } + + // for(j=0;jchannels;j++) + //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); + + /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ + /* only MDCT right now.... */ + for (i = 0; i < m_vorbisChannels; i++) { mdct_backward(n, m_dsp_state->work[i].get()); } + + // for(j=0;jchannels;j++) + //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); + + /* all done! */ + return (0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::floor0_memosize(ps_ptr& i) { + return i.get()->order + 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::floor1_memosize(ps_ptr& i) { + return i.get()->posts; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t* VorbisDecoder::floor0_inverse1(ps_ptr& i, int32_t* lsp) { + vorbis_info_floor* info = (vorbis_info_floor*)i.get(); + int32_t j; + + int32_t ampraw = bitReader(info->ampbits); + + if (ampraw > 0) { /* also handles the -1 out of data case */ + int32_t maxval = (1 << info->ampbits) - 1; + int32_t amp = ((ampraw * info->ampdB) << 4) / maxval; + int32_t booknum = bitReader(_ilog(info->numbooks)); + + if (booknum != -1 && booknum < info->numbooks) { /* be paranoid */ + codebook_t* b = m_codebooks.get() + info->books[booknum]; + int32_t last = 0; + + if (vorbis_book_decodev_set(b, lsp, info->order, -24) == -1) goto eop; + for (j = 0; j < info->order;) { + for (uint8_t k = 0; j < info->order && k < b->dim; k++, j++) lsp[j] += last; + last = lsp[j - 1]; + } + + lsp[info->order] = amp; + return (lsp); + } + } +eop: + return (NULL); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t* VorbisDecoder::floor1_inverse1(ps_ptr& in, int32_t* fit_value) { + vorbis_info_floor* info = (vorbis_info_floor*)in.get(); + + int32_t quant_look[4] = {256, 128, 86, 64}; + int32_t i, j, k; + int32_t quant_q = quant_look[info->mult - 1]; + codebook_t* books = m_codebooks.get(); + + /* unpack wrapped/predicted values from stream */ + if (bitReader(1) == 1) { + fit_value[0] = bitReader(ilog(quant_q - 1)); + fit_value[1] = bitReader(ilog(quant_q - 1)); + + /* partition by partition */ + for (i = 0, j = 2; i < info->partitions; i++) { + int32_t classv = info->partitionclass[i]; + int32_t cdim = info->_class[classv].class_dim; + int32_t csubbits = info->_class[classv].class_subs; + int32_t csub = 1 << csubbits; + int32_t cval = 0; + + /* decode the partition's first stage cascade value */ + if (csubbits) { + cval = vorbis_book_decode(books + info->_class[classv].class_book); + if (cval == -1) goto eop; + } + + for (k = 0; k < cdim; k++) { + int32_t book = info->_class[classv].class_subbook[cval & (csub - 1)]; + cval >>= csubbits; + if (book != 0xff) { + if ((fit_value[j + k] = vorbis_book_decode(books + book)) == -1) goto eop; + } else { + fit_value[j + k] = 0; + } + } + j += cdim; + } + + /* unwrap positive values and reconsitute via linear interpolation */ + for (i = 2; i < info->posts; i++) { + int32_t predicted = render_point(info->postlist[info->loneighbor[i - 2]], info->postlist[info->hineighbor[i - 2]], fit_value[info->loneighbor[i - 2]], fit_value[info->hineighbor[i - 2]], + info->postlist[i]); + int32_t hiroom = quant_q - predicted; + int32_t loroom = predicted; + int32_t room = (hiroom < loroom ? hiroom : loroom) << 1; + int32_t val = fit_value[i]; + + if (val) { + if (val >= room) { + if (hiroom > loroom) { + val = val - loroom; + } else { + val = -1 - (val - hiroom); + } + } else { + if (val & 1) { + val = -((val + 1) >> 1); + } else { + val >>= 1; + } + } + + fit_value[i] = val + predicted; + fit_value[info->loneighbor[i - 2]] &= 0x7fff; + fit_value[info->hineighbor[i - 2]] &= 0x7fff; + } else { + fit_value[i] = predicted | 0x8000; + } + } + + return (fit_value); + } else { + // VORBIS_LOG_ERROR("err in br"); + ; + } +eop: + return (NULL); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* returns the [original, not compacted] entry number or -1 on eof *********/ +int32_t VorbisDecoder::vorbis_book_decode(codebook_t* book) { + if (book->dec_type) return -1; + return decode_packed_entry_number(book); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::decode_packed_entry_number(codebook_t* book) { + uint32_t chase = 0; + int32_t read = book->dec_maxlength; + int32_t lok = bitReader_look(read), i; + + while (lok < 0 && read > 1) { lok = bitReader_look(--read); } + + if (lok < 0) { + bitReader_adv(1); /* force eop */ + return -1; + } + + /* chase the tree with the bits we got */ + if (book->dec_nodeb == 1) { + if (book->dec_leafw == 1) { + /* 8/8 */ + uint8_t* t = (uint8_t*)book->dec_table.get(); + for (i = 0; i < read; i++) { + chase = t[chase * 2 + ((lok >> i) & 1)]; + if (chase & 0x80UL) break; + } + chase &= 0x7fUL; + } else { + /* 8/16 */ + uint8_t* t = (uint8_t*)book->dec_table.get(); + for (i = 0; i < read; i++) { + int32_t bit = (lok >> i) & 1; + int32_t next = t[chase + bit]; + if (next & 0x80) { + chase = (next << 8) | t[chase + bit + 1 + (!bit || (t[chase] & 0x80))]; + break; + } + chase = next; + } + chase &= 0x7fffUL; + } + } else { + if (book->dec_nodeb == 2) { + if (book->dec_leafw == 1) { + /* 16/16 */ + int32_t idx; + for (i = 0; i < read; i++) { + idx = chase * 2 + ((lok >> i) & 1); + chase = ((uint16_t*)(book->dec_table.get()))[idx]; + if (chase & 0x8000UL) { break; } + } + chase &= 0x7fffUL; + } else { + /* 16/32 */ + uint16_t* t = (uint16_t*)book->dec_table.get(); + for (i = 0; i < read; i++) { + int32_t bit = (lok >> i) & 1; + int32_t next = t[chase + bit]; + if (next & 0x8000) { + chase = (next << 16) | t[chase + bit + 1 + (!bit || (t[chase] & 0x8000))]; + break; + } + chase = next; + } + chase &= 0x7fffffffUL; + } + } else { + for (i = 0; i < read; i++) { + chase = ((uint32_t*)(book->dec_table.get()))[chase * 2 + ((lok >> i) & 1)]; + if (chase & 0x80000000UL) break; + } + chase &= 0x7fffffffUL; + } + } + + if (i < read) { + bitReader_adv(i + 1); + return chase; + } + bitReader_adv(read + 1); + VORBIS_LOG_ERROR("read {}", read); + return (VORBIS_ERR); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::render_point(int32_t x0, int32_t x1, int32_t y0, int32_t y1, int32_t x) { + y0 &= 0x7fff; /* mask off flag */ + y1 &= 0x7fff; + + { + int32_t dy = y1 - y0; + int32_t adx = x1 - x0; + int32_t ady = abs(dy); + int32_t err = ady * (x - x0); + + int32_t off = err / adx; + if (dy < 0) return (y0 - off); + return (y0 + off); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* unlike the others, we guard against n not being an integer number * of internally rather than in the upper + layer (called only by * floor0) */ +int32_t VorbisDecoder::vorbis_book_decodev_set(codebook_t* book, int32_t* a, int32_t n, int32_t point) { + if (book->used_entries > 0) { + int32_t* v = (int32_t*)alloca(sizeof(*v) * book->dim); + int32_t i; + + for (i = 0; i < n;) { + if (decode_map(book, v, point)) return -1; + for (uint8_t j = 0; i < n && j < book->dim; j++) a[i++] = v[j]; + } + } else { + int32_t i; + + for (i = 0; i < n;) { a[i++] = 0; } + } + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::decode_map(codebook_t* s, int32_t* v, int32_t point) { + + uint32_t entry = decode_packed_entry_number(s); + + // if (oggpack_eop()) {return (-1);} + + /* according to decode type */ + switch (s->dec_type) { + case 1: { + /* packed vector of values */ + int32_t mask = (1 << s->q_bits) - 1; + for (uint8_t i = 0; i < s->dim; i++) { + v[i] = entry & mask; + entry >>= s->q_bits; + } + break; + } + case 2: { + /* packed vector of column offsets */ + int32_t mask = (1 << s->q_pack) - 1; + for (uint8_t i = 0; i < s->dim; i++) { + if (s->q_bits <= 8) + v[i] = ((uint8_t*)(s->q_val.get()))[entry & mask]; + else + v[i] = ((uint16_t*)(s->q_val.get()))[entry & mask]; + entry >>= s->q_pack; + } + break; + } + case 3: { + /* offset into array */ + void* ptr = (int32_t*)s->q_val.get() + entry * s->q_pack; + + if (s->q_bits <= 8) { + for (uint8_t i = 0; i < s->dim; i++) v[i] = ((uint8_t*)ptr)[i]; + } else { + for (uint8_t i = 0; i < s->dim; i++) v[i] = ((uint16_t*)ptr)[i]; + } + break; + } + default: return -1; + } + + /* we have the unpacked multiplicands; compute final vals */ + { + int32_t shiftM = point - s->q_delp; + int32_t add = point - s->q_minp; + if (add > 0) + add = s->q_min >> add; + else + add = s->q_min << -add; + + if (shiftM > 0) + for (uint8_t i = 0; i < s->dim; i++) v[i] = add + ((v[i] * s->q_del) >> shiftM); + else + for (uint8_t i = 0; i < s->dim; i++) v[i] = add + ((v[i] * s->q_del) << -shiftM); + + if (s->q_seq) + for (uint8_t i = 1; i < s->dim; i++) v[i] += v[i - 1]; + } + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::res_inverse(vorbis_info_residue* info, int32_t** in, int32_t* nonzero, uint8_t ch) { + int32_t j, k, s; + uint8_t m = 0, n = 0; + uint8_t used = 0; + codebook_t* phrasebook = m_codebooks.get() + info->groupbook; + uint32_t samples_per_partition = info->grouping; + uint8_t partitions_per_word = phrasebook->dim; + uint32_t pcmend = m_blocksizes[m_dsp_state->W]; + + if (info->type < 2) { + uint32_t max = pcmend >> 1; + uint32_t end = (info->end < max ? info->end : max); + uint32_t n1 = end - info->begin; + + if (n1 > 0) { + uint32_t partvals = n1 / samples_per_partition; + uint32_t partwords = (partvals + partitions_per_word - 1) / partitions_per_word; + + for (uint8_t i = 0; i < ch; i++) { + if (nonzero[i]) in[used++] = in[i]; + } + ch = used; + + if (used) { + char** partword = (char**)alloca(ch * sizeof(*partword)); + for (j = 0; j < ch; j++) { partword[j] = (char*)alloca(partwords * partitions_per_word * sizeof(*partword[j])); } + for (s = 0; s < info->stages; s++) { + for (uint32_t i = 0; i < partvals;) { + if (s == 0) { + /* fetch the partition word for each channel */ + partword[0][i + partitions_per_word - 1] = 1; + for (k = partitions_per_word - 2; k >= 0; k--) { partword[0][i + k] = partword[0][i + k + 1] * info->partitions; } + for (j = 1; j < ch; j++) { + for (k = partitions_per_word - 1; k >= 0; k--) { partword[j][i + k] = partword[j - 1][i + k]; } + } + for (n = 0; n < ch; n++) { + int32_t temp = vorbis_book_decode(phrasebook); + if (temp == -1) goto eopbreak; + /* this can be done quickly in assembly due to the quotient + always being at most six bits */ + for (m = 0; m < partitions_per_word; m++) { + char div = partword[n][i + m]; + partword[n][i + m] = temp / div; + temp -= partword[n][i + m] * div; + } + } + } + + /* now we decode residual values for the partitions */ + for (k = 0; k < partitions_per_word && i < partvals; k++, i++) { + for (j = 0; j < ch; j++) { + uint32_t offset = info->begin + i * samples_per_partition; + if (info->stagemasks[(int32_t)partword[j][i]] & (1 << s)) { + codebook_t* stagebook = m_codebooks.get() + info->stagebooks[(partword[j][i] << 3) + s]; + if (info->type) { + if (vorbis_book_decodev_add(stagebook, in[j] + offset, samples_per_partition, -8) == -1) goto eopbreak; + } else { + if (vorbis_book_decodevs_add(stagebook, in[j] + offset, samples_per_partition, -8) == -1) goto eopbreak; + } + } + } + } + } + } + } + } + } else { + uint32_t max = (pcmend * ch) >> 1; + uint32_t end = (info->end < max ? info->end : max); + uint32_t n = end - info->begin; + + if (n > 0) { + uint32_t partvals = n / samples_per_partition; + uint32_t partwords = (partvals + partitions_per_word - 1) / partitions_per_word; + + char* partword = (char*)alloca(partwords * partitions_per_word * sizeof(*partword)); + int32_t beginoff = info->begin / ch; + + uint8_t i = 0; + for (i = 0; i < ch; i++) + if (nonzero[i]) break; + if (i == ch) return (0); /* no nonzero vectors */ + + samples_per_partition /= ch; + + for (s = 0; s < info->stages; s++) { + for (uint32_t i = 0; i < partvals;) { + if (s == 0) { + int32_t temp; + partword[i + partitions_per_word - 1] = 1; + for (k = partitions_per_word - 2; k >= 0; k--) partword[i + k] = partword[i + k + 1] * info->partitions; + + /* fetch the partition word */ + temp = vorbis_book_decode(phrasebook); + if (temp == -1) goto eopbreak; + + /* this can be done quickly in assembly due to the quotient always being at most six bits */ + for (k = 0; k < partitions_per_word; k++) { + char div = partword[i + k]; + partword[i + k] = (char)temp / div; + temp -= partword[i + k] * div; + } + } + + /* now we decode residual values for the partitions */ + for (k = 0; k < partitions_per_word && i < partvals; k++, i++) + if (info->stagemasks[(int32_t)partword[i]] & (1 << s)) { + codebook_t* stagebook = m_codebooks.get() + info->stagebooks[(partword[i] << 3) + s]; + if (vorbis_book_decodevv_add(stagebook, in, i * samples_per_partition + beginoff, ch, samples_per_partition, -8) == -1) goto eopbreak; + } + } + } + } + } +eopbreak: + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* decode vector / dim granularity guarding is done in the upper layer */ +int32_t VorbisDecoder::vorbis_book_decodev_add(codebook_t* book, int32_t* a, int32_t n, int32_t point) { + if (book->used_entries > 0) { + int32_t* v = (int32_t*)alloca(sizeof(*v) * book->dim); + uint32_t i; + + for (i = 0; i < n;) { + if (decode_map(book, v, point)) return -1; + for (uint8_t j = 0; i < n && j < book->dim; j++) a[i++] += v[j]; + } + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* returns 0 on OK or -1 on eof */ +/* decode vector / dim granularity guarding is done in the upper layer */ +int32_t VorbisDecoder::vorbis_book_decodevs_add(codebook_t* book, int32_t* a, int32_t n, int32_t point) { + if (book->used_entries > 0) { + int32_t step = n / book->dim; + int32_t* v = (int32_t*)alloca(sizeof(*v) * book->dim); + int32_t j; + + for (j = 0; j < step; j++) { + if (decode_map(book, v, point)) return -1; + for (uint8_t i = 0, o = j; i < book->dim; i++, o += step) a[o] += v[i]; + } + } + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::floor0_inverse2(ps_ptr& i, int32_t* lsp, int32_t* out) { + vorbis_info_floor* info = (vorbis_info_floor*)i.get(); + + if (lsp) { + int32_t amp = lsp[info->order]; + + /* take the coefficients back to a spectral envelope curve */ + vorbis_lsp_to_curve(out, m_blocksizes[m_dsp_state->W] / 2, info->barkmap, lsp, info->order, amp, info->ampdB, info->rate >> 1); + return (1); + } + memset(out, 0, sizeof(*out) * m_blocksizes[m_dsp_state->W] / 2); + return (0); +} + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::floor1_inverse2(ps_ptr& in, int32_t* fit_value, int32_t* out) { + vorbis_info_floor* info = (vorbis_info_floor*)in.get(); + + int32_t n = m_blocksizes[m_dsp_state->W] / 2; + int32_t j; + + if (fit_value) { + /* render the lines */ + int32_t hx = 0; + int32_t lx = 0; + int32_t ly = fit_value[0] * info->mult; + + for (j = 1; j < info->posts; j++) { + int32_t current = info->forward_index[j]; + int32_t hy = fit_value[current] & 0x7fff; + if (hy == fit_value[current]) { + hy *= info->mult; + hx = info->postlist[current]; + + render_line(n, lx, hx, ly, hy, out); + + lx = hx; + ly = hy; + } + } + for (j = hx; j < n; j++) out[j] *= ly; /* be certain */ + return (1); + } + memset(out, 0, sizeof(*out) * n); + return (0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::render_line(int32_t n, int32_t x0, int32_t x1, int32_t y0, int32_t y1, int32_t* d) { + int32_t dy = y1 - y0; + int32_t adx = x1 - x0; + int32_t ady = abs(dy); + int32_t base = dy / adx; + int32_t sy = (dy < 0 ? base - 1 : base + 1); + int32_t x = x0; + int32_t y = y0; + int32_t err = 0; + + if (n > x1) n = x1; + ady -= abs(base * adx); + + if (x < n) { d[x] = MULT31_SHIFT15(d[x], FLOOR_fromdB_LOOKUP[y]); } + + while (++x < n) { + err = err + ady; + if (err >= adx) { + err -= adx; + y += sy; + } else { + y += base; + } + d[x] = MULT31_SHIFT15(d[x], FLOOR_fromdB_LOOKUP[y]); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::vorbis_lsp_to_curve(int32_t* curve, int32_t n, int32_t ln, int32_t* lsp, int32_t m, int32_t amp, int32_t ampoffset, int32_t nyq) { + /* 0 <= m < 256 */ + + /* set up for using all int32_t later */ + int32_t i; + int32_t ampoffseti = ampoffset * 4096; + int32_t ampi = amp; + int32_t* ilsp = (int32_t*)alloca(m * sizeof(*ilsp)); + uint32_t imap = (1UL << 31) / ln; + uint32_t tBnyq1 = toBARK(nyq) << 1; + + /* Besenham for frequency scale to avoid a division */ + int32_t f = 0; + int32_t fdx = n; + int32_t fbase = nyq / fdx; + int32_t ferr = 0; + int32_t fdy = nyq - fbase * fdx; + int32_t map = 0; + + uint32_t nextbark = MULT31(imap >> 1, tBnyq1); + + int32_t nextf = barklook[nextbark >> 14] + (((nextbark & 0x3fff) * (barklook[(nextbark >> 14) + 1] - barklook[nextbark >> 14])) >> 14); + + /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/ + for (i = 0; i < m; i++) { + int32_t val = MULT32(lsp[i], 0x517cc2); + /* safeguard against a malicious stream */ + if (val < 0 || (val >> COS_LOOKUP_I_SHIFT) >= COS_LOOKUP_I_SZ) { + memset(curve, 0, sizeof(*curve) * n); + return; + } + + ilsp[i] = vorbis_coslook_i(val); + } + + i = 0; + while (i < n) { + int32_t j; + uint32_t pi = 46341; /* 2**-.5 in 0.16 */ + uint32_t qi = 46341; + int32_t qexp = 0, shift; + int32_t wi; + + wi = vorbis_coslook2_i((map * imap) >> 15); + + qi *= labs(ilsp[0] - wi); + pi *= labs(ilsp[1] - wi); + + for (j = 3; j < m; j += 2) { + if (!(shift = MLOOP_1[(pi | qi) >> 25])) + if (!(shift = MLOOP_2[(pi | qi) >> 19])) shift = MLOOP_3[(pi | qi) >> 16]; + + qi = (qi >> shift) * labs(ilsp[j - 1] - wi); + pi = (pi >> shift) * labs(ilsp[j] - wi); + qexp += shift; + } + if (!(shift = MLOOP_1[(pi | qi) >> 25])) + if (!(shift = MLOOP_2[(pi | qi) >> 19])) shift = MLOOP_3[(pi | qi) >> 16]; + + /* pi,qi normalized collectively, both tracked using qexp */ + + if (m & 1) { + /* odd order filter; slightly assymetric */ + /* the last coefficient */ + qi = (qi >> shift) * labs(ilsp[j - 1] - wi); + pi = (pi >> shift) << 14; + qexp += shift; + + if (!(shift = MLOOP_1[(pi | qi) >> 25])) + if (!(shift = MLOOP_2[(pi | qi) >> 19])) shift = MLOOP_3[(pi | qi) >> 16]; + + pi >>= shift; + qi >>= shift; + qexp += shift - 14 * ((m + 1) >> 1); + + pi = ((pi * pi) >> 16); + qi = ((qi * qi) >> 16); + qexp = qexp * 2 + m; + + pi *= (1 << 14) - ((wi * wi) >> 14); + qi += pi >> 14; + } else { + /* even order filter; still symmetric */ + /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't worth tracking step by step */ + + pi >>= shift; + qi >>= shift; + qexp += shift - 7 * m; + + pi = ((pi * pi) >> 16); + qi = ((qi * qi) >> 16); + qexp = qexp * 2 + m; + + pi *= (1 << 14) - wi; + qi *= (1 << 14) + wi; + qi = (qi + pi) >> 14; + } + + /* we've let the normalization drift because it wasn't important; however, for the lookup, things must be + normalized again. We need at most one right shift or a number of left shifts */ + + if (qi & 0xffff0000) { /* checks for 1.VorbisDecoderVorbisDecoderVorbisDecoderVorbisDecoderVorbisDecoderx */ + qi >>= 1; + qexp++; + } else + while (qi && !(qi & 0x8000)) { /* checks for 0.0VorbisDecoderVorbisDecoderVorbisDecoderVorbisDecoderVorbisDecoder::or less*/ + qi <<= 1; + qexp--; + } + + amp = vorbis_fromdBlook_i(ampi * /* n.4 */ + vorbis_invsqlook_i(qi, qexp) - + /* m.8, m+n<=8 */ + ampoffseti); /* 8.12[0] */ + + curve[i] = MULT31_SHIFT15(curve[i], amp); + + while (++i < n) { + /* line plot to get new f */ + ferr += fdy; + if (ferr >= fdx) { + ferr -= fdx; + f++; + } + f += fbase; + + if (f >= nextf) break; + + curve[i] = MULT31_SHIFT15(curve[i], amp); + } + + while (1) { + map++; + + if (map + 1 < ln) { + nextbark = MULT31((map + 1) * (imap >> 1), tBnyq1); + + nextf = barklook[nextbark >> 14] + (((nextbark & 0x3fff) * (barklook[(nextbark >> 14) + 1] - barklook[nextbark >> 14])) >> 14); + if (f <= nextf) break; + } else { + nextf = 9999999; + break; + } + } + if (map >= ln) { + map = ln - 1; /* guard against the approximation */ + nextf = 9999999; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* used in init only; interpolate the int32_t way */ +int32_t VorbisDecoder::toBARK(int32_t n) { + int32_t i; + for (i = 0; i < 54; i++) + if (n >= barklook[i] && n < barklook[i + 1]) break; + + if (i == 54) { + return 54 << 14; + } else { + return (i << 14) + (((n - barklook[i]) * ((1UL << 31) / (barklook[i + 1] - barklook[i]))) >> 17); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* interpolated lookup based cos function, domain 0 to PI only */ +/* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ +int32_t VorbisDecoder::vorbis_coslook_i(int32_t a) { + int32_t i = a >> COS_LOOKUP_I_SHIFT; + int32_t d = a & COS_LOOKUP_I_MASK; + return COS_LOOKUP_I[i] - ((d * (COS_LOOKUP_I[i] - COS_LOOKUP_I[i + 1])) >> COS_LOOKUP_I_SHIFT); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* interpolated half-wave lookup based cos function */ +/* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */ +int32_t VorbisDecoder::vorbis_coslook2_i(int32_t a) { + int32_t i = a >> COS_LOOKUP_I_SHIFT; + int32_t d = a & COS_LOOKUP_I_MASK; + return ((COS_LOOKUP_I[i] << COS_LOOKUP_I_SHIFT) - d * (COS_LOOKUP_I[i] - COS_LOOKUP_I[i + 1])) >> (COS_LOOKUP_I_SHIFT - LSP_FRACBITS + 14); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* interpolated lookup based fromdB function, domain -140dB to 0dB only */ +/* a is in n.12 format */ + +int32_t VorbisDecoder::vorbis_fromdBlook_i(int32_t a) { + if (a > 0) return 0x7fffffff; + if (a < -573440) return 0; // replacement for if(a < (-140 << 12)) return 0; + return FLOOR_fromdB_LOOKUP[((a + (140 << 12)) * 467) >> 20]; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::vorbis_invsqlook_i(int32_t a, int32_t e) { + int32_t i = (a & 0x7fff) >> (INVSQ_LOOKUP_I_SHIFT - 1); + int32_t d = a & INVSQ_LOOKUP_I_MASK; /* 0.10 */ + int32_t val = INVSQ_LOOKUP_I[i] - /* 1.16 */ + ((INVSQ_LOOKUP_IDel[i] * d) >> INVSQ_LOOKUP_I_SHIFT); /* result 1.16 */ + val *= ADJUST_SQRT2[e & 1]; + e = (e >> 1) + 21; + return (val >> e); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* partial; doesn't perform last-step deinterleave/unrolling. That can be done more efficiently during pcm output */ +void VorbisDecoder::mdct_backward(int32_t n, int32_t* in) { + int32_t shift; + int32_t step; + + for (shift = 4; !(n & (1 << shift)); shift++); + shift = 13 - shift; + step = 2 << shift; + + presymmetry(in, n >> 1, step); + mdct_butterflies(in, n >> 1, shift); + mdct_bitreverse(in, n, shift); + mdct_step7(in, n, step); + mdct_step8(in, n, step); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::presymmetry(int32_t* in, int32_t n2, int32_t step) { + int32_t* aX; + int32_t* bX; + const int32_t* T; + int32_t n4 = n2 >> 1; + + aX = in + n2 - 3; + T = sincos_lookup0; + + do { + int32_t r0 = aX[0]; + int32_t r2 = aX[2]; + XPROD31(r0, r2, T[0], T[1], &aX[0], &aX[2]); + T += step; + aX -= 4; + } while (aX >= in + n4); + do { + int32_t r0 = aX[0]; + int32_t r2 = aX[2]; + XPROD31(r0, r2, T[1], T[0], &aX[0], &aX[2]); + T -= step; + aX -= 4; + } while (aX >= in); + + aX = in + n2 - 4; + bX = in; + T = sincos_lookup0; + do { + int32_t ri0 = aX[0]; + int32_t ri2 = aX[2]; + int32_t ro0 = bX[0]; + int32_t ro2 = bX[2]; + + XNPROD31(ro2, ro0, T[1], T[0], &aX[0], &aX[2]); + T += step; + XNPROD31(ri2, ri0, T[0], T[1], &bX[0], &bX[2]); + + aX -= 4; + bX += 4; + } while (aX >= in + n4); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_butterflies(int32_t* x, int32_t points, int32_t shift) { + int32_t stages = 8 - shift; + int32_t i, j; + + for (i = 0; --stages > 0; i++) { + for (j = 0; j < (1 << i); j++) mdct_butterfly_generic(x + (points >> i) * j, points >> i, 4 << (i + shift)); + } + + for (j = 0; j < points; j += 32) mdct_butterfly_32(x + j); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* N/stage point generic N stage butterfly (in place, 2 register) */ +void VorbisDecoder::mdct_butterfly_generic(int32_t* x, int32_t points, int32_t step) { + const int32_t* T = sincos_lookup0; + int32_t* x1 = x + points - 4; + int32_t* x2 = x + (points >> 1) - 4; + int32_t r0, r1, r2, r3; + + do { + r0 = x1[0] - x1[1]; + x1[0] += x1[1]; + r1 = x1[3] - x1[2]; + x1[2] += x1[3]; + r2 = x2[1] - x2[0]; + x1[1] = x2[1] + x2[0]; + r3 = x2[3] - x2[2]; + x1[3] = x2[3] + x2[2]; + XPROD31(r1, r0, T[0], T[1], &x2[0], &x2[2]); + XPROD31(r2, r3, T[0], T[1], &x2[1], &x2[3]); + T += step; + x1 -= 4; + x2 -= 4; + } while (T < sincos_lookup0 + 1024); + do { + r0 = x1[0] - x1[1]; + x1[0] += x1[1]; + r1 = x1[2] - x1[3]; + x1[2] += x1[3]; + r2 = x2[0] - x2[1]; + x1[1] = x2[1] + x2[0]; + r3 = x2[3] - x2[2]; + x1[3] = x2[3] + x2[2]; + XNPROD31(r0, r1, T[0], T[1], &x2[0], &x2[2]); + XNPROD31(r3, r2, T[0], T[1], &x2[1], &x2[3]); + T -= step; + x1 -= 4; + x2 -= 4; + } while (T > sincos_lookup0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 32 point butterfly (in place, 4 register) */ +void VorbisDecoder::mdct_butterfly_32(int32_t* x) { + int32_t r0, r1, r2, r3; + + r0 = x[16] - x[17]; + x[16] += x[17]; + r1 = x[18] - x[19]; + x[18] += x[19]; + r2 = x[1] - x[0]; + x[17] = x[1] + x[0]; + r3 = x[3] - x[2]; + x[19] = x[3] + x[2]; + XNPROD31(r0, r1, cPI3_8, cPI1_8, &x[0], &x[2]); + XPROD31(r2, r3, cPI1_8, cPI3_8, &x[1], &x[3]); + + r0 = x[20] - x[21]; + x[20] += x[21]; + r1 = x[22] - x[23]; + x[22] += x[23]; + r2 = x[5] - x[4]; + x[21] = x[5] + x[4]; + r3 = x[7] - x[6]; + x[23] = x[7] + x[6]; + x[4] = MULT31((r0 - r1), cPI2_8); + x[5] = MULT31((r3 + r2), cPI2_8); + x[6] = MULT31((r0 + r1), cPI2_8); + x[7] = MULT31((r3 - r2), cPI2_8); + + r0 = x[24] - x[25]; + x[24] += x[25]; + r1 = x[26] - x[27]; + x[26] += x[27]; + r2 = x[9] - x[8]; + x[25] = x[9] + x[8]; + r3 = x[11] - x[10]; + x[27] = x[11] + x[10]; + XNPROD31(r0, r1, cPI1_8, cPI3_8, &x[8], &x[10]); + XPROD31(r2, r3, cPI3_8, cPI1_8, &x[9], &x[11]); + + r0 = x[28] - x[29]; + x[28] += x[29]; + r1 = x[30] - x[31]; + x[30] += x[31]; + r2 = x[12] - x[13]; + x[29] = x[13] + x[12]; + r3 = x[15] - x[14]; + x[31] = x[15] + x[14]; + x[12] = r0; + x[13] = r3; + x[14] = r1; + x[15] = r2; + + mdct_butterfly_16(x); + mdct_butterfly_16(x + 16); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 16 point butterfly (in place, 4 register) */ +void VorbisDecoder::mdct_butterfly_16(int32_t* x) { + int32_t r0, r1, r2, r3; + + r0 = x[8] - x[9]; + x[8] += x[9]; + r1 = x[10] - x[11]; + x[10] += x[11]; + r2 = x[1] - x[0]; + x[9] = x[1] + x[0]; + r3 = x[3] - x[2]; + x[11] = x[3] + x[2]; + x[0] = MULT31((r0 - r1), cPI2_8); + x[1] = MULT31((r2 + r3), cPI2_8); + x[2] = MULT31((r0 + r1), cPI2_8); + x[3] = MULT31((r3 - r2), cPI2_8); + + r2 = x[12] - x[13]; + x[12] += x[13]; + r3 = x[14] - x[15]; + x[14] += x[15]; + r0 = x[4] - x[5]; + x[13] = x[5] + x[4]; + r1 = x[7] - x[6]; + x[15] = x[7] + x[6]; + x[4] = r2; + x[5] = r1; + x[6] = r3; + x[7] = r0; + + mdct_butterfly_8(x); + mdct_butterfly_8(x + 8); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* 8 point butterfly (in place) */ +void VorbisDecoder::mdct_butterfly_8(int32_t* x) { + int32_t r0 = x[0] + x[1]; + int32_t r1 = x[0] - x[1]; + int32_t r2 = x[2] + x[3]; + int32_t r3 = x[2] - x[3]; + int32_t r4 = x[4] + x[5]; + int32_t r5 = x[4] - x[5]; + int32_t r6 = x[6] + x[7]; + int32_t r7 = x[6] - x[7]; + + x[0] = r5 + r3; + x[1] = r7 - r1; + x[2] = r5 - r3; + x[3] = r7 + r1; + x[4] = r4 - r0; + x[5] = r6 - r2; + x[6] = r4 + r0; + x[7] = r6 + r2; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_bitreverse(int32_t* x, int32_t n, int32_t shift) { + int32_t bit = 0; + int32_t* w = x + (n >> 1); + + do { + int32_t b = bitrev12(bit++); + int32_t* xx = x + (b >> shift); + int32_t r; + + w -= 2; + + if (w > xx) { + r = xx[0]; + xx[0] = w[0]; + w[0] = r; + + r = xx[1]; + xx[1] = w[1]; + w[1] = r; + } + } while (w > x); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::bitrev12(int32_t x) { + uint8_t bitrev[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; + return bitrev[x >> 8] | (bitrev[(x & 0x0f0) >> 4] << 4) | (((int32_t)bitrev[x & 0x00f]) << 8); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_step7(int32_t* x, int32_t n, int32_t step) { + int32_t* w0 = x; + int32_t* w1 = x + (n >> 1); + const int32_t* T = (step >= 4) ? (sincos_lookup0 + (step >> 1)) : sincos_lookup1; + const int32_t* Ttop = T + 1024; + int32_t r0, r1, r2, r3; + + do { + w1 -= 2; + + r0 = w0[0] + w1[0]; + r1 = w1[1] - w0[1]; + r2 = MULT32(r0, T[1]) + MULT32(r1, T[0]); + r3 = MULT32(r1, T[1]) - MULT32(r0, T[0]); + T += step; + + r0 = (w0[1] + w1[1]) >> 1; + r1 = (w0[0] - w1[0]) >> 1; + w0[0] = r0 + r2; + w0[1] = r1 + r3; + w1[0] = r0 - r2; + w1[1] = r3 - r1; + + w0 += 2; + } while (T < Ttop); + do { + w1 -= 2; + + r0 = w0[0] + w1[0]; + r1 = w1[1] - w0[1]; + T -= step; + r2 = MULT32(r0, T[0]) + MULT32(r1, T[1]); + r3 = MULT32(r1, T[0]) - MULT32(r0, T[1]); + + r0 = (w0[1] + w1[1]) >> 1; + r1 = (w0[0] - w1[0]) >> 1; + w0[0] = r0 + r2; + w0[1] = r1 + r3; + w1[0] = r0 - r2; + w1[1] = r3 - r1; + + w0 += 2; + } while (w0 < w1); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_step8(int32_t* x, int32_t n, int32_t step) { + const int32_t* T; + const int32_t* V; + int32_t* iX = x + (n >> 1); + step >>= 2; + + switch (step) { + default: + T = (step >= 4) ? (sincos_lookup0 + (step >> 1)) : sincos_lookup1; + do { + int32_t r0 = x[0]; + int32_t r1 = -x[1]; + XPROD31(r0, r1, T[0], T[1], x, x + 1); + T += step; + x += 2; + } while (x < iX); + break; + + case 1: { + /* linear interpolation between table values: offset=0.5, step=1 */ + int32_t t0, t1, v0, v1, r0, r1; + T = sincos_lookup0; + V = sincos_lookup1; + t0 = (*T++) >> 1; + t1 = (*T++) >> 1; + do { + r0 = x[0]; + r1 = -x[1]; + t0 += (v0 = (*V++) >> 1); + t1 += (v1 = (*V++) >> 1); + XPROD31(r0, r1, t0, t1, x, x + 1); + + r0 = x[2]; + r1 = -x[3]; + v0 += (t0 = (*T++) >> 1); + v1 += (t1 = (*T++) >> 1); + XPROD31(r0, r1, v0, v1, x + 2, x + 3); + + x += 4; + } while (x < iX); + break; + } + + case 0: { + /* linear interpolation between table values: offset=0.25, step=0.5 */ + int32_t t0, t1, v0, v1, q0, q1, r0, r1; + T = sincos_lookup0; + V = sincos_lookup1; + t0 = *T++; + t1 = *T++; + do { + v0 = *V++; + v1 = *V++; + t0 += (q0 = (v0 - t0) >> 2); + t1 += (q1 = (v1 - t1) >> 2); + r0 = x[0]; + r1 = -x[1]; + XPROD31(r0, r1, t0, t1, x, x + 1); + t0 = v0 - q0; + t1 = v1 - q1; + r0 = x[2]; + r1 = -x[3]; + XPROD31(r0, r1, t0, t1, x + 2, x + 3); + + t0 = *T++; + t1 = *T++; + v0 += (q0 = (t0 - v0) >> 2); + v1 += (q1 = (t1 - v1) >> 2); + r0 = x[4]; + r1 = -x[5]; + XPROD31(r0, r1, v0, v1, x + 4, x + 5); + v0 = t0 - q0; + v1 = t1 - q1; + r0 = x[6]; + r1 = -x[7]; + XPROD31(r0, r1, v0, v1, x + 5, x + 6); + + x += 8; + } while (x < iX); + break; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* decode vector / dim granularity guarding is done in the upper layer */ +int32_t VorbisDecoder::vorbis_book_decodevv_add(codebook_t* book, int32_t** a, int32_t offset, uint8_t ch, int32_t n, int32_t point) { + if (book->used_entries > 0) { + int32_t* v = (int32_t*)alloca(sizeof(*v) * book->dim); + int32_t i; + uint8_t chptr = 0; + int32_t m = offset + n; + + for (i = offset; i < m;) { + if (decode_map(book, v, point)) return -1; + for (uint8_t j = 0; i < m && j < book->dim; j++) { + a[chptr++][i] += v[j]; + if (chptr == ch) { + chptr = 0; + i++; + } + } + } + } + + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +/* pcm==0 indicates we just want the pending samples, no more */ +int32_t VorbisDecoder::vorbis_dsp_pcmout(int16_t* outBuff, int32_t outBuffSize) { + if (m_dsp_state->out_begin > -1 && m_dsp_state->out_begin < m_dsp_state->out_end) { + int32_t n = m_dsp_state->out_end - m_dsp_state->out_begin; + + if (outBuff) { + int32_t i; + if (n > outBuffSize) { + n = outBuffSize; + VORBIS_LOG_ERROR("outBufferSize too small, must be min {} (int16_t) words", n); + } + for (i = 0; i < m_vorbisChannels; i++) { + mdct_unroll_lap(m_blocksizes[0], m_blocksizes[1], m_dsp_state->lW, m_dsp_state->W, m_dsp_state->work[i].get(), m_dsp_state->mdctright[i].get(), _vorbis_window(m_blocksizes[0] >> 1), + _vorbis_window(m_blocksizes[1] >> 1), outBuff + i, m_vorbisChannels, m_dsp_state->out_begin, m_dsp_state->out_begin + n); + } + } + return (n); + } + return (0); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t* VorbisDecoder::_vorbis_window(int32_t left) { + switch (left) { + case 32: return (int32_t*)vwin64; + case 64: return (int32_t*)vwin128; + case 128: return (int32_t*)vwin256; + case 256: return (int32_t*)vwin512; + case 512: return (int32_t*)vwin1024; + case 1024: return (int32_t*)vwin2048; + case 2048: return (int32_t*)vwin4096; + case 4096: return (int32_t*)vwin8192; + default: return (0); + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::mdct_unroll_lap(int32_t n0, int32_t n1, int32_t lW, int32_t W, int32_t* in, int32_t* right, const int32_t* w0, const int32_t* w1, int16_t* out, int32_t step, + int32_t start, /* samples, this frame */ + int32_t end /* samples, this frame */) { + int32_t* l = in + (W && lW ? n1 >> 1 : n0 >> 1); + int32_t* r = right + (lW ? n1 >> 2 : n0 >> 2); + int32_t* post; + const int32_t* wR = (W && lW ? w1 + (n1 >> 1) : w0 + (n0 >> 1)); + const int32_t* wL = (W && lW ? w1 : w0); + + int32_t preLap = (lW && !W ? (n1 >> 2) - (n0 >> 2) : 0); + int32_t halfLap = (lW && W ? (n1 >> 2) : (n0 >> 2)); + int32_t postLap = (!lW && W ? (n1 >> 2) - (n0 >> 2) : 0); + int32_t n, off; + + /* preceeding direct-copy lapping from previous frame, if any */ + if (preLap) { + n = (end < preLap ? end : preLap); + off = (start < preLap ? start : preLap); + post = r - n; + r -= off; + start -= off; + end -= n; + while (r > post) { + *out = CLIP_TO_15((*--r) >> 9); + out += step; + } + } + + /* cross-lap; two halves due to wrap-around */ + n = (end < halfLap ? end : halfLap); + off = (start < halfLap ? start : halfLap); + post = r - n; + r -= off; + l -= off * 2; + start -= off; + wR -= off; + wL += off; + end -= n; + while (r > post) { + l -= 2; + *out = CLIP_TO_15((MULT31(*--r, *--wR) + MULT31(*l, *wL++)) >> 9); + out += step; + } + + n = (end < halfLap ? end : halfLap); + off = (start < halfLap ? start : halfLap); + post = r + n; + r += off; + l += off * 2; + start -= off; + end -= n; + wR -= off; + wL += off; + while (r < post) { + *out = CLIP_TO_15((MULT31(*r++, *--wR) - MULT31(*l, *wL++)) >> 9); + out += step; + l += 2; + } + + /* preceeding direct-copy lapping from previous frame, if any */ + if (postLap) { + n = (end < postLap ? end : postLap); + off = (start < postLap ? start : postLap); + post = l + n * 2; + l += off * 2; + while (l < post) { + *out = CLIP_TO_15((-*l) >> 9); + out += step; + l += 2; + } + } +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::MULT32(int32_t x, int32_t y) { + union magic magic; + magic.whole = (int64_t)x * y; + return magic.halves.hi; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::MULT31_SHIFT15(int32_t x, int32_t y) { + union magic magic; + magic.whole = (int64_t)x * y; + return ((uint32_t)(magic.halves.lo) >> 15) | ((magic.halves.hi) << 17); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::MULT31(int32_t x, int32_t y) { + return MULT32(x, y) << 1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::XPROD31(int32_t a, int32_t b, int32_t t, int32_t v, int32_t* x, int32_t* y) { + *x = MULT31(a, t) + MULT31(b, v); + *y = MULT31(b, t) - MULT31(a, v); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void VorbisDecoder::XNPROD31(int32_t a, int32_t b, int32_t t, int32_t v, int32_t* x, int32_t* y) { + *x = MULT31(a, t) - MULT31(b, v); + *y = MULT31(b, t) + MULT31(a, v); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::CLIP_TO_15(int32_t x) { + int32_t ret = x; + ret -= ((x <= 32767) - 1) & (x - 32767); + ret -= ((x >= -32768) - 1) & (x + 32768); + return (ret); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact) { + int32_t result = -1; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int32_t i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int32_t j = 0; j < strlen(str) + exact; j++) { + if (*(base + i + j) != *(str + j)) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t VorbisDecoder::specialIndexOf_icase(uint8_t* base, const char* str, int32_t baselen, bool exact) { + int32_t result = -1; // seek for str in buffer or in header up to baselen, not nullterninated + if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end + for (int32_t i = 0; i < baselen - strlen(str); i++) { + result = i; + for (int32_t j = 0; j < strlen(str) + exact; j++) { + if (tolower(*(base + i + j)) != tolower(*(str + j))) { + result = -1; + break; + } + } + if (result >= 0) break; + } + return result; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t VorbisDecoder::little_endian(uint8_t* data) { + return (uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[3]) << 24)); +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.h b/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.h new file mode 100644 index 0000000..e682b2e --- /dev/null +++ b/libraries/ESP32-audioI2S/src/vorbis_decoder/vorbis_decoder.h @@ -0,0 +1,418 @@ + +#pragma once +// #pragma GCC optimize ("O3") +// #pragma GCC diagnostic ignored "-Wnarrowing" + +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation https://xiph.org/ * + * * + ********************************************************************/ +/* + * vorbis_decoder.h + * based on Xiph.Org Foundation vorbis decoder + * adapted for the ESP32 by schreibfaul1 + * + * Created on: 13.02.2023 + * Updated on: 19.06.2025 + */ + +#include "../Audio.h" +#include "../psram_unique_ptr.hpp" + +class VorbisDecoder : public Decoder { + + public: + VorbisDecoder(Audio& audioRef) : Decoder(audioRef), audio(audioRef) {} + ~VorbisDecoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; + const char* arg2() override; + virtual int32_t val1() override; + virtual int32_t val2() override; + + enum : int8_t { VORBIS_CONTINUE = 110, VORBIS_PARSE_OGG_DONE = 100, VORBIS_NONE = 0, VORBIS_ERR = -1 }; + enum ParseResult { VORBIS_COMMENT_INVALID = -1, VORBIS_COMMENT_NEED_MORE = 100, VORBIS_COMMENT_DONE = 110 }; + + private: + Audio& audio; + +#define VI_FLOORB 2 +#define VIF_POSIT 63 + +#define LSP_FRACBITS 14 + +#define OV_EREAD -128 +#define OV_EFAULT -129 +#define OV_EIMPL -130 +#define OV_EINVAL -131 +#define OV_ENOTVORBIS -132 +#define OV_EBADHEADER -133 +#define OV_EVERSION -134 +#define OV_ENOTAUDIO -135 +#define OV_EBADPACKET -136 +#define OV_EBADLINK -137 +#define OV_ENOSEEK -138 + +#define INVSQ_LOOKUP_I_SHIFT 10 +#define INVSQ_LOOKUP_I_MASK 1023 +#define COS_LOOKUP_I_SHIFT 9 +#define COS_LOOKUP_I_MASK 511 +#define COS_LOOKUP_I_SZ 128 + +#define cPI3_8 (0x30fbc54d) +#define cPI2_8 (0x5a82799a) +#define cPI1_8 (0x7641af3d) + + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + const uint32_t mask[33] = {0x00000000, 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}; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + const uint16_t barklook[54] = {0, 51, 102, 154, 206, 258, 311, 365, 420, 477, 535, 594, 656, 719, 785, 854, 926, 1002, + 1082, 1166, 1256, 1352, 1454, 1564, 1683, 1812, 1953, 2107, 2276, 2463, 2670, 2900, 3155, 3440, 3756, 4106, + 4493, 4919, 5387, 5901, 6466, 7094, 7798, 8599, 9528, 10623, 11935, 13524, 15453, 17775, 20517, 23667, 27183, 31004}; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + const uint8_t MLOOP_1[64] = { + 0, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + }; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + const uint8_t MLOOP_2[64] = { + 0, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + }; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + const uint8_t MLOOP_3[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + /* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in 16.16 format returns in m.8 format */ + int32_t ADJUST_SQRT2[2] = {8192, 5792}; + // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + typedef struct { + char class_dim; /* 1 to 8 */ + char class_subs; /* 0,1,2,3 (bits: 1<> work; + ps_ptr> mdctright; + int32_t lW = 0; // last window + int32_t W = 0; // window + int32_t out_begin = -1; + int32_t out_end = -1; + }; + + struct vorbis_info_mapping { + int32_t submaps{}; + ps_ptr chmuxlist{}; + ps_ptr submaplist{}; + int32_t coupling_steps{}; + ps_ptr coupling{}; + + void reset() { + *this = vorbis_info_mapping{}; // sauber neu initialisieren + } + }; + + struct vorbis_info_residue { + int32_t type{}; + ps_ptr stagemasks{}; + ps_ptr stagebooks{}; + /* block-partitioned VQ coded straight residue */ + uint32_t begin{}; + uint32_t end{}; + /* first stage (lossless partitioning) */ + uint32_t grouping{}; /* group n vectors per partition */ + char partitions{}; /* possible codebooks for a partition */ + uint8_t groupbook{}; /* huffbook for partitioning */ + char stages{}; + + void reset() { + *this = vorbis_info_residue{}; // reinitialize cleanly + } + }; + + struct vorbis_info_floor { + int32_t order{}; + int32_t rate{}; + int32_t barkmap{}; + int32_t ampbits{}; + int32_t ampdB{}; + int32_t numbooks{}; /* <= 16 */ + char books[16]{}; + ps_ptr _class{}; /* [VIF_CLASS] */ + ps_ptr partitionclass{}; /* [VIF_PARTS]; 0 to 15 */ + ps_ptr postlist{}; /* [VIF_POSIT+2]; first two implicit */ + ps_ptr forward_index{}; /* [VIF_POSIT+2]; */ + ps_ptr hineighbor{}; /* [VIF_POSIT]; */ + ps_ptr loneighbor{}; /* [VIF_POSIT]; */ + int32_t partitions{}; /* 0 to 31 */ + int32_t posts{}; + int32_t mult{}; /* 1 2 3 or 4 */ + }; + + typedef struct _codebook { + uint8_t dim{}; /* codebook dimensions (elements per vector) */ + int16_t entries{}; /* codebook entries */ + uint16_t used_entries{}; /* populated codebook entries */ + uint32_t dec_maxlength{}; + ps_ptr dec_table{}; + uint32_t dec_nodeb{}; + uint32_t dec_leafw{}; + uint32_t dec_type{}; /* 0 = entry number + 1 = packed vector of values + 2 = packed vector of column offsets, maptype 1 + 3 = scalar offset into value array, maptype 2 */ + int32_t q_min{}; + int32_t q_minp{}; + int32_t q_del{}; + int32_t q_delp{}; + int32_t q_seq{}; + int32_t q_bits{}; + uint8_t q_pack{}; + ps_ptr q_val{}; + } codebook_t; + + typedef struct _comment { + uint32_t pointer{}; + uint32_t list_length{}; + bool oob{}; // out of bounds (block overflow) + uint32_t save_len{}; + uint32_t comment_size{}; + uint32_t start_pos{}; // comment start file position + uint32_t end_pos{}; // comment end file position + uint8_t length_bytes[4]{}; // 🆕 Addition for split 4-byte length fields + uint8_t partial_length{}; // how many of the 4 bytes have already been read + uint32_t bytes_available{}; + + ps_ptr stream_title{}; + ps_ptr comment_content{}; + std::vector item_vec; + std::vector pic_vec; + + void reset() { *this = _comment{}; } + } comment_t; + comment_t m_comment; + + typedef struct _ogg_items { + std::deque segment_table{}; + uint32_t bytes_consumed_from_other{}; + uint8_t* data_ptr{}; + uint32_t lastSegmentTableLen{}; + ps_ptr lastSegmentTable{}; + void reset() { *this = _ogg_items{}; } + } ogg_items_t; + ogg_items_t m_ogg_items; + + // global vars + bool m_f_newSteamTitle = false; // streamTitle + bool m_f_newMetadataBlockPicture = false; + bool m_f_oggFirstPage = false; + bool m_f_oggContinuedPage = false; + bool m_f_oggLastPage = false; + bool m_f_parseOggDone = true; + bool m_f_isValid = false; + bool m_f_comment_done = false; + uint16_t m_identificatonHeaderLength = 0; + uint16_t m_vorbisCommentHeaderLength = 0; + uint8_t m_pageNr = 0; + uint16_t m_oggHeaderSize = 0; + uint8_t m_vorbisChannels = 0; + uint16_t m_vorbisSamplerate = 0; + uint32_t m_vorbisBitRate = 0; + uint32_t m_vorbis_segment_length = 0; + uint32_t m_vorbisCurrentFilePos = 0; + uint32_t m_vorbisAudioDataStart = 0; + + int32_t m_vorbisValidSamples = 0; + int32_t m_commentBlockSegmentSize = 0; + uint8_t m_vorbisOldMode = 0; + uint32_t m_blocksizes[2]; + uint32_t m_vorbisBlockPicPos = 0; + uint32_t m_vorbisBlockPicLen = 0; + int32_t m_vorbisRemainBlockPicLen = 0; + int32_t m_commentLength = 0; + + uint8_t m_nrOfCodebooks = 0; + uint8_t m_nrOfFloors = 0; + uint8_t m_nrOfResidues = 0; + uint8_t m_nrOfMaps = 0; + uint8_t m_nrOfModes = 0; + + uint16_t m_oggPage3Len = 0; // length of the current audio segment + int8_t m_vorbisError = 0; + float m_vorbisCompressionRatio = 0; + + ps_ptr m_codebooks; + ps_ptr> m_floor_param{}; + ps_ptr m_floor_type; + ps_ptr m_residue_param; + ps_ptr m_map_param; + ps_ptr m_mode_param; + ps_ptr m_dsp_state; + ps_ptr m_out16; + + std::vector m_vorbisBlockPicItem; + + //---------------------------------------------------------------------------------------------------------------------- + + // ogg impl + + ps_ptr floor0_info_unpack(); + void setDefaults(); + void clearGlobalConfigurations(); + int32_t parse_OGG(uint8_t* inbuf, int32_t* bytesLeft); + int32_t vorbisDecodePage1(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength); + int32_t vorbisDecodePage2(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, uint32_t current_file_pos); + int32_t vorbisDecodePage3(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength); + int32_t vorbisDecodePage4(uint8_t* inbuf, int32_t* bytesLeft, uint32_t segmentLength, int16_t* outbuf); + int32_t parseVorbisComment(uint8_t* inbuf, int16_t nBytes, uint32_t current_file_pos); + int32_t parseVorbisCodebook(); + int32_t parseVorbisFirstPacket(uint8_t* inbuf, int16_t nBytes); + int32_t vorbis_book_unpack(codebook_t* s); + uint32_t decpack(int32_t entry, int32_t used_entry, uint8_t quantvals, codebook_t* b, int32_t maptype); + int32_t oggpack_eop(); + ps_ptr floor1_info_unpack(); + void vorbis_mergesort(uint8_t* index, uint16_t* vals, uint16_t n); + int32_t res_unpack(vorbis_info_residue* info); + int32_t mapping_info_unpack(vorbis_info_mapping* info); + + // vorbis decoder impl + int32_t vorbis_dsp_synthesis(uint8_t* inbuf, uint16_t len, int16_t* outbuf); + ps_ptr vorbis_dsp_create(); + void vorbis_dsp_destroy(ps_ptr& v); + void vorbis_book_clear(ps_ptr& v); + void mdct_shift_right(int32_t n, int32_t* in, int32_t* right); + int32_t mapping_inverse(vorbis_info_mapping* info); + int32_t floor0_memosize(ps_ptr& i); + int32_t floor1_memosize(ps_ptr& i); + int32_t* floor0_inverse1(ps_ptr& i, int32_t* lsp); + int32_t* floor1_inverse1(ps_ptr& in, int32_t* fit_value); + int32_t vorbis_book_decode(codebook_t* book); + int32_t decode_packed_entry_number(codebook_t* book); + int32_t render_point(int32_t x0, int32_t x1, int32_t y0, int32_t y1, int32_t x); + int32_t vorbis_book_decodev_set(codebook_t* book, int32_t* a, int32_t n, int32_t point); + int32_t decode_map(codebook_t* s, int32_t* v, int32_t point); + int32_t res_inverse(vorbis_info_residue* info, int32_t** in, int32_t* nonzero, uint8_t ch); + int32_t vorbis_book_decodev_add(codebook_t* book, int32_t* a, int32_t n, int32_t point); + int32_t vorbis_book_decodevs_add(codebook_t* book, int32_t* a, int32_t n, int32_t point); + int32_t floor0_inverse2(ps_ptr& i, int32_t* lsp, int32_t* out); + int32_t floor1_inverse2(ps_ptr& in, int32_t* fit_value, int32_t* out); + void render_line(int32_t n, int32_t x0, int32_t x1, int32_t y0, int32_t y1, int32_t* d); + void vorbis_lsp_to_curve(int32_t* curve, int32_t n, int32_t ln, int32_t* lsp, int32_t m, int32_t amp, int32_t ampoffset, int32_t nyq); + int32_t toBARK(int32_t n); + int32_t vorbis_coslook_i(int32_t a); + int32_t vorbis_coslook2_i(int32_t a); + int32_t vorbis_fromdBlook_i(int32_t a); + int32_t vorbis_invsqlook_i(int32_t a, int32_t e); + void mdct_backward(int32_t n, int32_t* in); + void presymmetry(int32_t* in, int32_t n2, int32_t step); + void mdct_butterflies(int32_t* x, int32_t points, int32_t shift); + void mdct_butterfly_generic(int32_t* x, int32_t points, int32_t step); + void mdct_butterfly_32(int32_t* x); + void mdct_butterfly_16(int32_t* x); + void mdct_butterfly_8(int32_t* x); + void mdct_bitreverse(int32_t* x, int32_t n, int32_t shift); + int32_t bitrev12(int32_t x); + void mdct_step7(int32_t* x, int32_t n, int32_t step); + void mdct_step8(int32_t* x, int32_t n, int32_t step); + int32_t vorbis_book_decodevv_add(codebook_t* book, int32_t** a, int32_t offset, uint8_t ch, int32_t n, int32_t point); + int32_t vorbis_dsp_pcmout(int16_t* outBuff, int32_t outBuffSize); + void mdct_unroll_lap(int32_t n0, int32_t n1, int32_t lW, int32_t W, int32_t* in, int32_t* right, const int32_t* w0, const int32_t* w1, int16_t* out, int32_t step, + int32_t start, /* samples, this frame */ + int32_t end /* samples, this frame */); + + // some helper functions + int32_t special_index_of(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + void bitReader_setData(uint8_t* buff, uint32_t buffSize); + int32_t bitReader(uint16_t bits); + int32_t bitReader_look(uint16_t nBits); + int8_t bitReader_adv(uint16_t bits); + uint8_t _ilog(uint32_t v); + int32_t ilog(uint32_t v); + int32_t _float32_unpack(int32_t val, int32_t* point); + int32_t _determine_node_bytes(uint32_t used, uint8_t leafwidth); + int32_t _determine_leaf_words(int32_t nodeb, int32_t leafwidth); + int32_t _make_decode_table(codebook_t* s, int32_t* lengthlist, uint8_t quantvals, int32_t maptype); + int32_t _make_words(int32_t* l, uint16_t n, uint32_t* r, uint8_t quantvals, codebook_t* b, int32_t maptype); + uint8_t _book_maptype1_quantvals(codebook_t* b); + int32_t* _vorbis_window(int32_t left); + + int32_t MULT32(int32_t x, int32_t y); + int32_t MULT31_SHIFT15(int32_t x, int32_t y); + int32_t MULT31(int32_t x, int32_t y); + void XPROD31(int32_t a, int32_t b, int32_t t, int32_t v, int32_t* x, int32_t* y); + void XNPROD31(int32_t a, int32_t b, int32_t t, int32_t v, int32_t* x, int32_t* y); + int32_t CLIP_TO_15(int32_t x); + int32_t specialIndexOf(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + int32_t specialIndexOf_icase(uint8_t* base, const char* str, int32_t baselen, bool exact = false); + uint32_t little_endian(uint8_t* data); + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +// Macro for comfortable calls +#define VORBIS_LOG_ERROR(fmt, ...) Audio::AUDIO_LOG_IMPL(1, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define VORBIS_LOG_WARN(fmt, ...) Audio::AUDIO_LOG_IMPL(2, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define VORBIS_LOG_INFO(fmt, ...) Audio::AUDIO_LOG_IMPL(3, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define VORBIS_LOG_DEBUG(fmt, ...) Audio::AUDIO_LOG_IMPL(4, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +#define VORBIS_LOG_VERBOSE(fmt, ...) Audio::AUDIO_LOG_IMPL(5, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) +}; +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.cpp b/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.cpp new file mode 100644 index 0000000..7806f36 --- /dev/null +++ b/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.cpp @@ -0,0 +1,192 @@ +#include "wav_decoder.h" + +// created 21.09.2025 +// updated 14.02.2026 + +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool WavDecoder::init() { + m_valid = true; + return true; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void WavDecoder::clear() { + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void WavDecoder::reset() { + m_valid = false; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +bool WavDecoder::isValid() { + return m_valid; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t WavDecoder::findSyncWord(uint8_t* buf, int32_t nBytes) { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t WavDecoder::getChannels() { + return m_channels; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t WavDecoder::getSampleRate() { + return m_sampleRate; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t WavDecoder::getOutputSamples() { + return m_validSamples; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint8_t WavDecoder::getBitsPerSample() { + return m_bits_per_sample; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t WavDecoder::getBitRate() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t WavDecoder::getAudioDataStart() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +uint32_t WavDecoder::getAudioFileDuration() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* WavDecoder::getStreamTitle() { + return ""; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* WavDecoder::whoIsIt() { + return "WAV"; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t WavDecoder::decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) { + + uint16_t frame = *bytesLeft; + const uint8_t* p = inbuf; + + // ------------ 8-BIT PCM unsigned ------------ + if (m_bits_per_sample == 8) { + if (frame > 4096) frame = 4096; + if (getChannels() == 1) { + // MONO + for (int i = 0; i < frame; i++) { + uint8_t p0 = p[0]; + outbuf[i * 2] = (static_cast(p0) - 128) << 24; + outbuf[i * 2 + 1] = (static_cast(p0) - 128) << 24; + p++; + } + m_validSamples = frame; + } + if (getChannels() == 2) { + // STEREO (interleaved L/R) + for (int i = 0; i < frame / 2; i++) { + uint8_t l = p[0]; + uint8_t r = p[1]; + outbuf[i * 2] = (static_cast(l) - 128) << 24; + outbuf[i * 2 + 1] = ((static_cast(r) - 128) << 24); + p += 2; + } + m_validSamples = (frame / 2); + } + *bytesLeft -= frame; + return 0; + } + // ------------ 16-BIT PCM ------------ + if (m_bits_per_sample == 16) { + if (frame > 4096) frame = 4096; + if (m_channels == 1) { + for (int i = 0; i < frame / 2; i++) { + outbuf[i * 2] = (p[1] << 24) | (p[0] << 16); + outbuf[i * 2 + 1] = (p[1] << 24) | (p[0] << 16); + p += 2; + } + m_validSamples = frame / 2; + } + if (m_channels == 2) { + for (int i = 0; i < frame / 4; i++) { + outbuf[i * 2] = (p[1] << 24) | (p[0]) << 16; + outbuf[i * 2 + 1] = (p[3] << 24) | (p[2] << 16); + p += 4; + } + m_validSamples = frame / 4; + } + *bytesLeft -= frame; + return 0; + } + // ------------ 24-BIT PCM ------------ + if (m_bits_per_sample == 24) { + if (frame > 4096 * 3) frame = 4096 * 3; + if (m_channels == 1) { + for (int i = 0; i < frame / 3; i++) { + outbuf[i * 2] = (p[2] << 24) | (p[1] << 16) | (p[0] << 8); + outbuf[i * 2 + 1] = (p[2] << 24) | (p[1] << 16) | (p[0] << 8); + p += 3; + } + m_validSamples = frame / 3; + } + if (m_channels == 2) { + for (int i = 0; i < frame / 6; i++) { + outbuf[i * 2] = (p[2] << 24) | (p[1] << 16) | (p[0] << 8); + outbuf[i * 2 + 1] = (p[5] << 24) | (p[4] << 16) | (p[3] << 8); + p += 6; + } + m_validSamples = frame / 6; + } + *bytesLeft -= frame; + return 0; + } + // ------------ 32-BIT PCM ------------ + if (m_bits_per_sample == 32) { + if (frame > 4096 * 4) frame = 4096 * 4; + if (m_channels == 1) { + for (int i = 0; i < frame / 4; i++) { + outbuf[i * 2] = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0]); + outbuf[i * 2 + 1] = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0]); + p += 4; + } + m_validSamples = frame / 4; + } + if (m_channels == 2) { + for (int i = 0; i < frame / 8; i++) { + outbuf[i * 2] = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0]); + outbuf[i * 2 + 1] = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | (p[4]); + p += 8; + } + m_validSamples = frame / 8; + } + *bytesLeft -= frame; + return 0; + } + return -1; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +void WavDecoder::setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) { + m_channels = channels; + m_sampleRate = sampleRate; + m_bits_per_sample = BPS; + return; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +std::vector WavDecoder::getMetadataBlockPicture() { + std::vector res = {}; + return res; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* WavDecoder::arg1() { + return ""; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +const char* WavDecoder::arg2() { + return ""; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t WavDecoder::val1() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— +int32_t WavDecoder::val2() { + return 0; +} +// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— diff --git a/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.h b/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.h new file mode 100644 index 0000000..6bc88fb --- /dev/null +++ b/libraries/ESP32-audioI2S/src/wav_decoder/wav_decoder.h @@ -0,0 +1,38 @@ +#pragma once +#include "../Audio.h" + +class WavDecoder : public Decoder { + + public: + WavDecoder(Audio& audioRef) : Decoder(audioRef), audio(audioRef) {} + ~WavDecoder() { reset(); } + bool init() override; + void clear() override; + void reset() override; + bool isValid() override; + int32_t findSyncWord(uint8_t* buf, int32_t nBytes) override; + uint8_t getChannels() override; + uint32_t getSampleRate() override; + uint32_t getOutputSamples(); + uint8_t getBitsPerSample() override; + uint32_t getBitRate() override; + uint32_t getAudioDataStart() override; + uint32_t getAudioFileDuration() override; + const char* getStreamTitle() override; + const char* whoIsIt() override; + int32_t decode(uint8_t* inbuf, int32_t* bytesLeft, int32_t* outbuf) override; + void setRawBlockParams(uint8_t channels, uint32_t sampleRate, uint8_t BPS, uint32_t tsis, uint32_t AuDaLength) override; + std::vector getMetadataBlockPicture() override; + const char* arg1() override; + const char* arg2() override; + virtual int32_t val1() override; + virtual int32_t val2() override; + + private: + Audio& audio; + bool m_valid = false; + uint8_t m_channels = 0; + uint8_t m_bits_per_sample = 0; + uint32_t m_sampleRate = 0; + uint32_t m_validSamples = 0; +}; \ No newline at end of file diff --git a/libraries/PNGdec/LICENSE b/libraries/PNGdec/LICENSE new file mode 100644 index 0000000..716f427 --- /dev/null +++ b/libraries/PNGdec/LICENSE @@ -0,0 +1,204 @@ +Copyright 2020 BitBank Software, Inc. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/libraries/PNGdec/README.md b/libraries/PNGdec/README.md new file mode 100644 index 0000000..669b6ba --- /dev/null +++ b/libraries/PNGdec/README.md @@ -0,0 +1,47 @@ +PNGdec +------ +Copyright (c) 2021 BitBank Software, Inc.
+Written by Larry Bank
+bitbank@pobox.com
+ +What is it? +------------ +An 'embedded-friendly' (aka Arduino) PNG image decoding library
+
+ +Why did you write it? +--------------------- +Starting in the late 80's I wrote my own imaging codecs for the existing standards (CCITT G3/G4 was the first). I soon added GIF, JPEG and not long after that, the PNG specification was ratified. All of this code was "clean room" - written just from the specification. I used my imaging library in many projects and products over the years and recently decided that some of my codecs could get a new lease on life as open source, embedded-friendly libraries for microcontrollers.
+
+ +What's special about it?
+------------------------ +The PNG image specification was written at a time when computers had megabytes of RAM and conserving memory wasn't a big priority. The memory allocated for decoding the compressed data (zlib) and for holding the uncompressed image can be quite a bit more than is available on modern microcontrollers (usually measured in K bytes). Three goals for this project are: easy to compile+use on all embedded systems, use a minimal amount of RAM and be self-contained. One of the dependencies I like to remove when working on embedded software is malloc/free. When compiling on a system with a tiny amount of RAM, heap memory management might not even exist.
+ +Feature summary:
+----------------
+- Runs on any MCU with at least 48K of free RAM
+- No external dependencies (including malloc/free)
+- Decode an image line by line with a callback function
+- Decode an image to a user supplied buffer (no callback needed)
+- Supports all standard options except interlacing (too much RAM needed)
+- Function provided to turn any pixel format into RGB565 for LCD displays
+- Optionally disable zlib's internal CRC check - improves speed by 10-30% +- Arduino-style C++ library class with simple API
+- Can by built as straight C as well
+
+ +How fast is it?
+---------------
+The examples folder contains a sketch to measure the performance of decoding a 240x200 image of varying bit depths. Here's the results when run on a few common MCUs:
+ +
+

+ +

+ +Documentation:
+---------------
+Detailed information about the API is in the [Wiki](https://github.com/bitbank2/PNGdec/wiki)
+See the examples folder for easy starting points
+
diff --git a/libraries/PNGdec/examples/1bpp_transparent_oled/1bpp_transparent_oled.ino b/libraries/PNGdec/examples/1bpp_transparent_oled/1bpp_transparent_oled.ino new file mode 100644 index 0000000..5f99ee0 --- /dev/null +++ b/libraries/PNGdec/examples/1bpp_transparent_oled/1bpp_transparent_oled.ino @@ -0,0 +1,86 @@ +// +// 1-bpp PNG example - drawing transparent images on an SSD1306 OLED +// written by Larry Bank +// May 31, 2021 +// + +#include +#include +// really 2-bpp to get a transparent color in the palette +#include "octocat_1bpp.h" + +#define USE_HW_I2C 1 +#define INVERT 0 +#define FLIP180 0 +#define OLED_ADDR -1 +OBDISP obd; +PNG png; +static uint8_t ucBackBuffer[1024]; + +// +// Draw 1-bpp pixels onto the back buffer while respecting the transparent mask +// This needs to be done in the sketch and not the library because it's very +// specific to the memory layout of the SSD1306 +// +void DrawPixelsMasked(int y, uint8_t *pPixels, uint8_t *pMask, int width) +{ +int x, iBit; +uint8_t *d, ucPix, ucAlpha, ucMask; +// The display has the bytes oriented vertically while the bitmap has them packed horizontally + d = &ucBackBuffer[(y >> 3) * 128 + 25]; // pointer to display memory (center it horizontally too) + ucMask = 1 << (y & 7); // bit position of display memory (LSB on top) + for (x=0; xy, pDraw->pPixels, ucMask, pDraw->iWidth); + } +} /* PNGDraw() */ + +void setup() { + Serial.begin(115200); + obdI2CInit(&obd, OLED_128x64, OLED_ADDR, FLIP180, INVERT, USE_HW_I2C, -1, -1, -1, 400000L); + obdSetBackBuffer(&obd, ucBackBuffer); + obdFill(&obd, 0, 1); +} /* setup() */ + +void loop() { +int i, rc; +char szTemp[256]; + + // create a 'gray' background pattern on the OLED + for (i=0; i<1024; i+=2) { + ucBackBuffer[i] = 0x55; + ucBackBuffer[i+1] = 0xaa; + } + obdDumpBuffer(&obd, NULL); // display gray background + delay(2000); + rc = png.openRAM((uint8_t *)octocat_1bpp, sizeof(octocat_1bpp), PNGDraw); + if (rc == PNG_SUCCESS) { + sprintf(szTemp, "image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType()); + Serial.print(szTemp); + rc = png.decode(NULL, 0); // no private structure and skip CRC checking + obdDumpBuffer(&obd, NULL); // show the image + png.close(); + } // png opened successfully + delay(2000); // rinse, repeat +} /* loop() */ diff --git a/libraries/PNGdec/examples/1bpp_transparent_oled/octocat_1bpp.h b/libraries/PNGdec/examples/1bpp_transparent_oled/octocat_1bpp.h new file mode 100644 index 0000000..2f7d743 --- /dev/null +++ b/libraries/PNGdec/examples/1bpp_transparent_oled/octocat_1bpp.h @@ -0,0 +1,35 @@ +// +// octocat_1bpp +// Data size = 373 bytes +// +// PNG, Compression=Flate, Size: 77 x 64, 2-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t octocat_1bpp[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x40,0x02,0x03,0x00,0x00,0x00,0x22,0xf9,0x12, + 0xfd,0x00,0x00,0x00,0x09,0x50,0x4c,0x54,0x45,0x00,0xf0,0x7a,0x00,0x00,0x00,0xff, + 0xff,0xff,0x34,0xae,0x54,0xfd,0x00,0x00,0x00,0x01,0x74,0x52,0x4e,0x53,0x00,0x40, + 0xe6,0xd8,0x66,0x00,0x00,0x01,0x1a,0x49,0x44,0x41,0x54,0x38,0xcb,0xb5,0xd3,0x31, + 0x6e,0xc3,0x30,0x0c,0x00,0x40,0x3a,0x80,0x96,0xcc,0xf5,0x13,0xba,0xf4,0x15,0xe9, + 0x90,0xdd,0x05,0x24,0x01,0xd6,0xd4,0x25,0x05,0xea,0x57,0xf8,0x13,0xce,0xdc,0x45, + 0x41,0xc4,0x57,0x56,0xb4,0x25,0x87,0x94,0x9c,0x66,0x68,0xcb,0x45,0xc0,0x81,0x22, + 0x21,0x93,0x06,0xb8,0x1b,0x4f,0xe9,0xd4,0x1c,0x4d,0x37,0x1f,0x4a,0xa2,0xe1,0xc7, + 0x8a,0xaf,0xc6,0x98,0xa3,0xc0,0xc6,0xe4,0x78,0x84,0xf0,0x0f,0x78,0x6b,0x74,0xb8, + 0xa1,0x5a,0xb1,0x7b,0x80,0xed,0x8a,0xfa,0x0f,0xd1,0x21,0x45,0x90,0x88,0x4b,0x6c, + 0xe2,0xc4,0xd1,0x26,0xf4,0x1c,0xdd,0x36,0x5e,0xee,0x61,0x18,0x0a,0xa4,0x56,0xd3, + 0x10,0x24,0x52,0x2b,0x2f,0x32,0x95,0xc3,0x33,0x21,0x16,0x98,0xba,0xb3,0x4f,0xd7, + 0xd0,0xe5,0x4b,0x81,0xb0,0xbe,0x88,0x8d,0x03,0xda,0xfc,0x76,0x3e,0xcd,0x54,0x34, + 0x88,0xad,0x6b,0x4c,0xd5,0x27,0x7f,0x12,0x2f,0xc6,0xae,0xd3,0x3a,0xf0,0x36,0x60, + 0x97,0x25,0x11,0xb6,0x53,0x87,0x79,0x49,0x3a,0x89,0x63,0x8d,0xd0,0xbc,0xcf,0x4b, + 0xa2,0xe5,0x2f,0x63,0xe2,0x98,0xde,0x4a,0xb4,0x1f,0xa7,0x1a,0xe3,0x36,0x1c,0x2b, + 0x54,0x84,0xba,0x40,0x68,0xd5,0x06,0xc2,0xaf,0xb1,0xb7,0x15,0x3e,0x9f,0x7a,0x67, + 0x47,0x69,0x2f,0x9e,0x10,0x85,0xee,0x71,0xc1,0xab,0x48,0x4c,0xc8,0x53,0x77,0x71, + 0xb8,0xbe,0x77,0x13,0xe2,0x17,0xc7,0x60,0x23,0xfa,0x81,0xdf,0xdf,0xd3,0xd4,0x3e, + 0x69,0x76,0x57,0x71,0x3d,0xee,0xa1,0xa9,0xf1,0x1c,0x97,0x4e,0xd4,0x04,0xcc,0x31, + 0x82,0x2c,0x3a,0x87,0x78,0xd1,0x46,0xe2,0x52,0x55,0x56,0xcc,0x15,0xe0,0xc7,0xf8, + 0x06,0xa3,0x85,0xe6,0x10,0x4b,0x49,0x02,0x6a,0x00,0x00,0x00,0x00,0x49,0x45,0x4e, + 0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/m5stickc_plus_test/m5logosmall.h b/libraries/PNGdec/examples/m5stickc_plus_test/m5logosmall.h new file mode 100644 index 0000000..7f76687 --- /dev/null +++ b/libraries/PNGdec/examples/m5stickc_plus_test/m5logosmall.h @@ -0,0 +1,234 @@ +// +// m5logosmall +// Data size = 3561 bytes +// +// PNG, Compression=Flate, Size: 240 x 135, 24-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t m5logosmall[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x87,0x08,0x02,0x00,0x00,0x00,0xa7,0x10,0x43, + 0xbc,0x00,0x00,0x0d,0xb0,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x5d,0x4d,0x48,0x1b, + 0xeb,0x1a,0x9e,0x73,0x71,0xe5,0xe6,0xde,0x50,0x7b,0xb2,0x39,0x0d,0xc5,0x03,0x2e, + 0x8c,0xb8,0x8a,0x8b,0x2c,0xc4,0xde,0xcd,0x9d,0x3b,0x28,0xe2,0x42,0x17,0x81,0x23, + 0x58,0x54,0x0a,0x0a,0x5d,0xf4,0x2e,0xac,0x20,0x45,0x0e,0x82,0x15,0xee,0xe9,0x42, + 0xa8,0x70,0x50,0xa9,0x60,0xef,0xcd,0x42,0xa1,0x52,0xa4,0xc3,0x1c,0xba,0x68,0x70, + 0x91,0x45,0xb2,0x92,0x93,0x42,0x85,0x06,0xab,0x5d,0x34,0x55,0x9b,0x5d,0x76,0x97, + 0xde,0xc5,0x7b,0xfc,0xce,0x34,0x99,0xf9,0xe6,0x9b,0xbf,0x64,0x32,0xf3,0x3c,0x64, + 0x11,0x93,0xc9,0x38,0x3f,0xcf,0xf7,0xce,0xf3,0xfe,0x7c,0xef,0xf7,0xdd,0xd7,0xaf, + 0x5f,0x25,0x00,0x08,0x0b,0x3a,0x70,0x09,0x9a,0x80,0xb3,0x4a,0x95,0xbd,0x4f,0xc4, + 0x63,0xb8,0x20,0x20,0x74,0xbb,0x42,0x2d,0x9e,0x1c,0xff,0xfe,0x76,0xb5,0x50,0xa3, + 0x3f,0xd3,0xdd,0x5d,0x77,0x6e,0xd4,0x32,0xca,0x10,0x68,0xed,0x13,0xbe,0x83,0xe4, + 0xf0,0xc9,0x24,0x67,0xd5,0xdc,0x9b,0xab,0xce,0x7c,0xf9,0xd2,0x70,0x83,0x74,0x77, + 0xd7,0xfd,0xa1,0xdb,0xc9,0x5b,0x37,0xc1,0x6c,0x10,0xba,0xbd,0xa9,0x0c,0x5a,0x83, + 0xd0,0x6d,0xa9,0x2e,0xc4,0x41,0x3a,0xa4,0xbf,0xaf,0x57,0x49,0xf5,0xe0,0x32,0x82, + 0xd0,0xad,0x37,0xc9,0xa5,0xf3,0x8b,0xf5,0xdc,0xa9,0xa1,0x49,0x66,0x64,0x4d,0xde, + 0xba,0x29,0x49,0x12,0x67,0x4b,0x18,0x6c,0x10,0x3a,0xd0,0xea,0x82,0xe3,0xff,0xf1, + 0x6d,0x39,0x1c,0x47,0x10,0x3a,0x70,0x42,0x39,0x7b,0x37,0x65,0x69,0x68,0x69,0x27, + 0x1c,0x89,0xb2,0x38,0xd0,0x09,0x5a,0x83,0xd0,0x2d,0x53,0x17,0x4c,0x33,0xd8,0x95, + 0xc2,0x6a,0xf1,0x84,0xbf,0xcf,0x5f,0x7f,0x1a,0x90,0x10,0xc0,0x06,0xa1,0xbd,0xc5, + 0xda,0xce,0x01,0xc7,0x24,0xbb,0xb7,0xa6,0x96,0xb4,0x86,0xbc,0x06,0xa1,0x5b,0x29, + 0x94,0xdb,0xe2,0xdf,0x81,0xd0,0x11,0x82,0xa5,0xeb,0x66,0x69,0x32,0x29,0xe3,0xed, + 0x80,0x7c,0x96,0xda,0x66,0x71,0xa0,0x13,0x61,0x3e,0x10,0xda,0x9b,0xa7,0xbf,0x08, + 0x99,0xce,0x2a,0xd5,0xb9,0xe9,0x49,0x7a,0x3f,0x38,0x3e,0xb3,0x30,0x35,0xe6,0xc6, + 0x60,0xf3,0x07,0x15,0x68,0x0d,0x42,0x3b,0xb4,0x8b,0x22,0xb1,0x0b,0xb5,0x78,0xf2, + 0x74,0xf9,0x81,0xa6,0x69,0xec,0x13,0x59,0x96,0x0f,0x0f,0x0f,0xdd,0xeb,0x10,0x84, + 0xf9,0x40,0x68,0x2f,0x0d,0xa1,0xa5,0xba,0xc8,0xaa,0xb9,0xa5,0xd9,0x09,0xfd,0x87, + 0xb2,0x2c,0x0f,0x8e,0xcf,0x78,0x45,0x35,0x41,0x1d,0x12,0x71,0xc7,0x31,0xea,0x84, + 0x16,0x89,0x2d,0x58,0xaa,0x8b,0xac,0x9a,0x3b,0xda,0xdf,0x62,0x56,0x59,0x96,0x65, + 0x49,0x92,0xe6,0x97,0x9f,0xf8,0x24,0x06,0x2c,0x8f,0x39,0xca,0x06,0x3b,0xa2,0x84, + 0x16,0xb1,0x76,0x96,0x9c,0x20,0xaf,0xb1,0xce,0x2a,0xaf,0x6c,0xee,0x35,0x87,0x4c, + 0xd0,0x21,0x20,0xb4,0x67,0xea,0xa2,0x74,0x7e,0xd1,0x28,0x94,0x3d,0x54,0x17,0x1e, + 0x8e,0xcc,0xa8,0x05,0xb0,0x23,0x44,0x68,0xf7,0x99,0x8b,0x46,0x75,0x41,0x54,0xf6, + 0x4f,0x5d,0xd8,0x62,0xf6,0xbd,0xe7,0x05,0xd0,0x3a,0x12,0x84,0xe6,0x47,0x94,0x49, + 0x5d,0x48,0xdc,0x80,0xb1,0xa1,0xba,0x90,0x65,0x79,0x63,0x7b,0xd7,0x0d,0x45,0xc8, + 0xbe,0x1e,0xff,0xfe,0x96,0x7d,0xe2,0xd2,0xab,0xa3,0x1d,0x66,0x9e,0x15,0xcd,0x36, + 0x58,0x1c,0xe8,0x74,0x1c,0x43,0x04,0xa1,0x03,0xa1,0x2e,0xf8,0xf9,0x6a,0x7e,0x44, + 0x99,0x3d,0xd0,0x5f,0x3f,0x1c,0xae,0x13,0xca,0x6e,0xf2,0x1a,0x86,0x96,0xbe,0x6e, + 0xa8,0xfc,0xef,0xef,0xf7,0x1d,0xdb,0x54,0xbe,0x0e,0x39,0x7e,0xa4,0x84,0xd8,0x4e, + 0x87,0x93,0xd0,0x22,0x0e,0x13,0xdf,0x50,0x99,0xa9,0x0b,0x97,0x42,0xb9,0x31,0x4a, + 0xcd,0xa2,0x22,0x04,0xc3,0xaf,0x1c,0x4b,0x1a,0x7a,0xb0,0xbc,0xb9,0xea,0x64,0x9f, + 0x84,0x3e,0x11,0x13,0x36,0x42,0x7b,0x92,0xaf,0x6e,0x0e,0x95,0xd9,0x3e,0xeb,0xb6, + 0x24,0x11,0xe2,0xad,0x52,0x77,0x9c,0x84,0x07,0xa1,0x5b,0x66,0x92,0x3d,0x29,0x7e, + 0x50,0x8b,0x27,0xa3,0xe9,0x64,0x9d,0x8d,0x74,0xc9,0x24,0xc7,0x7e,0x24,0x79,0xb1, + 0x7a,0xb5,0xd3,0xb4,0x98,0x20,0x08,0x1d,0x50,0x07,0xdf,0x6e,0x38,0x96,0x6a,0x30, + 0x3c,0xb1,0xcd,0x5e,0x85,0x44,0xea,0x4c,0xbb,0x7b,0x4f,0xd4,0x6c,0xe4,0x84,0x63, + 0x5e,0x63,0x18,0x08,0xad,0xfc,0xf2,0x5b,0x23,0x9b,0x1d,0x07,0xaa,0x0c,0xc3,0xcc, + 0xb6,0x1c,0x41,0xb3,0x90,0xc8,0xfc,0xf2,0x13,0xc7,0x11,0x8c,0xb5,0x9d,0x03,0xb6, + 0x43,0x0f,0x39,0xdd,0xa8,0xd0,0xda,0xdd,0x65,0x0c,0x73,0xa3,0x19,0x9a,0x97,0x6a, + 0x17,0x89,0x78,0x2c,0x11,0x8f,0x29,0x87,0x87,0x74,0xb3,0x99,0x89,0x25,0x3e,0xf1, + 0x79,0x69,0x58,0xd1,0xe1,0x32,0x24,0x42,0x58,0x98,0x1a,0x93,0xa4,0x3d,0xda,0xb3, + 0xa6,0x69,0x59,0x35,0xe7,0x26,0xfa,0xc6,0x89,0xee,0x95,0xce,0x2f,0x40,0xe8,0x16, + 0xe3,0xfe,0xd0,0xed,0x46,0x0b,0x9d,0x2f,0x5f,0xf6,0xff,0xac,0xba,0x49,0x28,0x28, + 0xa9,0x1e,0x25,0xd5,0x93,0x51,0x86,0xf4,0xca,0x41,0xd3,0x34,0x4d,0x4b,0x36,0xea, + 0x10,0x0f,0xb5,0x8a,0x19,0xfa,0xfb,0x7a,0xbd,0x8a,0xff,0x08,0xb6,0x0d,0x01,0xa1, + 0x5b,0x24,0x39,0x52,0x3d,0xc7,0xb7,0x6e,0x1a,0xde,0xa7,0x7c,0xf9,0x32,0x5f,0xbe, + 0x74,0x53,0xd8,0x90,0x88,0xc7,0x16,0xa6,0xc6,0x32,0xca,0x90,0x3e,0x20,0xad,0x69, + 0x9a,0xa6,0x69,0x47,0xb2,0x3c,0x38,0x3e,0x23,0x49,0x92,0xe7,0x21,0x11,0x43,0xe8, + 0xf3,0x2f,0x8e,0x85,0xf2,0xf5,0xf5,0xa9,0x49,0x21,0x45,0xa8,0xc2,0x76,0x3e,0x4d, + 0x62,0xb5,0xd4,0xc7,0xbe,0x52,0x99,0x22,0x6e,0x75,0x4a,0xe6,0xfd,0xc7,0xcf,0xe2, + 0x6e,0xae,0xe5,0x35,0xd1,0x7f,0x95,0xbd,0x9b,0x6a,0x6b,0xbf,0x30,0x9c,0x89,0x15, + 0x91,0x68,0xb4,0x9b,0xdb,0x66,0x58,0x32,0xea,0xc6,0xe7,0x13,0x77,0x4f,0xc5,0xe3, + 0x24,0x96,0xd3,0x13,0x99,0x18,0xfb,0xdb,0xfc,0x7f,0x41,0xe8,0xf6,0x30,0xd8,0xbe, + 0x16,0x58,0xb2,0x4a,0x0c,0xcf,0xcb,0xea,0x5d,0x26,0x77,0xec,0x66,0x97,0x40,0xe8, + 0x50,0xe9,0x90,0x40,0xf5,0x73,0x71,0x33,0xf3,0xc5,0x71,0x76,0x09,0x84,0x6e,0x57, + 0x1d,0x12,0xe4,0xba,0x61,0xb3,0x32,0x0f,0x11,0x81,0x21,0xd2,0x5f,0x8f,0x33,0x1e, + 0xc2,0x44,0xe8,0x08,0x35,0x3c,0xa7,0x30,0x9c,0x99,0x0e,0x61,0xf1,0x90,0x26,0xd3, + 0xda,0xac,0xf2,0x4e,0x30,0xcb,0xed,0xbe,0x76,0x05,0x51,0x8e,0x80,0xea,0x0a,0xc9, + 0x4e,0xf1,0x8d,0x48,0x65,0xa9,0xdf,0x3a,0xc4,0x57,0x75,0x61,0x8b,0xca,0x90,0x1c, + 0x81,0x63,0x33,0xd5,0x72,0x50,0x1b,0x38,0x5b,0x2c,0x74,0x3f,0x49,0xd6,0xb1,0xba, + 0x90,0xbe,0x2d,0x16,0x15,0x57,0x17,0x9e,0xb7,0x56,0x82,0xe4,0x08,0x16,0x58,0x65, + 0x52,0xbe,0x7c,0x69,0x37,0x73,0x4b,0x3a,0xc4,0xec,0xc1,0xfd,0x87,0x0e,0xc9,0x9d, + 0x7a,0xf8,0xe0,0x1e,0x19,0x19,0x71,0x56,0x25,0xf2,0xed,0x41,0xd6,0x4c,0xa8,0x3c, + 0x10,0xf1,0x5a,0xbc,0x30,0x10,0xda,0x7d,0x16,0xf7,0x3a,0xcb,0x5d,0xe5,0xa4,0x1b, + 0x25,0xb1,0x46,0x33,0x22,0xd2,0xc8,0x8f,0xd8,0x05,0xfa,0x38,0x46,0xce,0x29,0xb4, + 0x04,0x65,0xb9,0x17,0xcc,0x1b,0x8d,0x52,0x35,0x8f,0x9b,0xbe,0x72,0x89,0x78,0x6c, + 0x63,0x7b,0xb7,0x74,0x7e,0x41,0xa3,0xc8,0x4d,0xec,0x42,0x42,0x2b,0x30,0x10,0x5a, + 0x10,0x44,0x6b,0x33,0x1d,0xb2,0x5a,0xa8,0x49,0x85,0xa2,0x63,0x1d,0x42,0xd5,0x7c, + 0xcd,0x17,0xca,0x20,0x74,0xd4,0x21,0xa8,0x43,0xbc,0x8d,0x87,0x58,0x0a,0x65,0x74, + 0x89,0x06,0xa1,0x3d,0xd0,0x21,0x19,0x73,0x93,0xb9,0x5a,0xa8,0xad,0x16,0x54,0xbf, + 0x1b,0x9e,0x63,0x79,0x0a,0x10,0xda,0x17,0x79,0x6d,0x46,0x3b,0xa2,0xb5,0x03,0x0b, + 0x1a,0x84,0x88,0x38,0x08,0x1d,0x75,0x1d,0x62,0xc6,0x42,0xf1,0x78,0x08,0x2b,0x0a, + 0x85,0xba,0x00,0xa1,0xdb,0x40,0x87,0x64,0x9e,0x15,0xcd,0x5c,0x37,0xc4,0x2e,0x40, + 0xe8,0xa0,0xd3,0xda,0x90,0xa0,0xf9,0xf2,0x65,0xbe,0x2c,0x91,0xbc,0x96,0x24,0xa9, + 0xbf,0xaf,0x97,0xa6,0x9c,0x40,0x5d,0x80,0xd0,0x41,0xa7,0x75,0x22,0x1e,0xe3,0xa4, + 0x1b,0xff,0xf8,0xa4,0xc0,0x66,0xa4,0x9a,0x25,0xf9,0x40,0x65,0x10,0x3a,0x78,0xf2, + 0xda,0x2c,0xcc,0x07,0x75,0x01,0x42,0x87,0x50,0x87,0x40,0x5d,0x80,0xd0,0x61,0xd0, + 0x21,0xcc,0x60,0x43,0x5d,0x80,0xd0,0x61,0xd0,0x21,0x0b,0xb8,0x10,0xcd,0xc2,0x5f, + 0x70,0x09,0x00,0x10,0x1a,0x00,0x40,0x68,0x00,0x00,0xa1,0x01,0x00,0x84,0x06,0x40, + 0x68,0x00,0x00,0xa1,0x01,0x00,0x84,0x06,0x00,0x10,0x1a,0x00,0xa2,0x49,0xe8,0xf5, + 0xdc,0xa9,0xbe,0x55,0x00,0x60,0x09,0xb5,0x78,0x02,0x42,0x07,0x0b,0xe9,0xee,0x2e, + 0xf6,0x3e,0x5f,0xbe,0xcc,0xaa,0x39,0x70,0x5a,0x9c,0xcd,0x9c,0x75,0x94,0xdb,0x11, + 0x61,0xa8,0xe5,0xb8,0x73,0xa3,0x96,0x2f,0xff,0xf9,0xa7,0x7e,0x7a,0x1f,0x2a,0x33, + 0xcd,0x60,0xd6,0x7b,0xc4,0xd9,0x4a,0x4b,0xc1,0x41,0x48,0x7a,0xdb,0xf5,0xff,0xac, + 0x1a,0x7e,0x85,0xae,0x42,0x8d,0xd7,0x8a,0x53,0xae,0x1d,0x82,0xa5,0xed,0xc3,0xd3, + 0x7d,0xd4,0xd7,0x66,0xfd,0x21,0xb8,0x3e,0xb4,0xd8,0x80,0x7f,0xcb,0x74,0x80,0xd0, + 0xcd,0x36,0x3f,0x52,0x24,0xcb,0xea,0xa3,0x36,0x27,0x37,0x84,0x1d,0xfc,0xbd,0xed, + 0x9d,0xdc,0xd6,0x0e,0x9f,0x7e,0x6e,0x41,0x44,0x9e,0x5a,0x61,0x5e,0x92,0x22,0x9a, + 0x77,0x34,0xe2,0xe3,0x19,0x8b,0x06,0x85,0xea,0x99,0x6b,0x16,0xbb,0x60,0x67,0x6a, + 0xb7,0x21,0x3c,0x08,0x0d,0xbb,0xd5,0xb2,0x67,0x91,0x99,0xc3,0x17,0x29,0xe7,0x21, + 0x42,0xab,0x60,0x09,0x3a,0x8e,0xee,0xbb,0x9a,0x07,0x2d,0x76,0x81,0x45,0x83,0x40, + 0xeb,0xa0,0xeb,0x90,0x76,0x3f,0x7e,0x10,0x1a,0x16,0x4e,0x94,0xca,0x11,0xef,0xf8, + 0x11,0x69,0x42,0xb7,0x11,0x4b,0x10,0x8b,0x04,0xa1,0xbd,0x27,0x8d,0x9b,0xd5,0x55, + 0xa0,0x2e,0x40,0xe8,0x80,0x06,0x0d,0x9a,0x66,0x0b,0x2d,0x0f,0x03,0x4d,0x98,0x40, + 0x68,0xcf,0x4c,0xa3,0x7f,0x7c,0x82,0xba,0x00,0xa1,0x5b,0x2f,0x5e,0x3d,0x79,0xe2, + 0x8b,0x48,0xf9,0xe6,0x6b,0x1e,0x10,0x3a,0x9c,0xb4,0x96,0x74,0x4b,0xd6,0x7a,0x6e, + 0x35,0x2d,0x33,0x23,0x6d,0x14,0x1d,0x07,0xa1,0xa3,0x1b,0x0f,0x81,0xba,0x00,0xa1, + 0x03,0xe4,0x38,0xba,0x21,0x22,0x62,0x17,0x20,0x74,0x70,0x0d,0x36,0x3f,0x10,0xd1, + 0xdf,0xd7,0x2b,0x5d,0x4f,0x6d,0xa2,0x45,0x91,0x91,0xac,0x06,0xa1,0xdb,0x5b,0x87, + 0x88,0x00,0x54,0x06,0xa1,0xdb,0x4c,0x87,0x98,0x01,0xcb,0x53,0x80,0xd0,0x6d,0xac, + 0x43,0x60,0x92,0x41,0xe8,0x76,0xa5,0x35,0x55,0x3e,0x49,0x92,0xf4,0xe6,0xaa,0x93, + 0x7d,0x7e,0xe7,0x46,0x4d,0x92,0x24,0x84,0x93,0x41,0x68,0x00,0xb0,0x06,0x7a,0xdb, + 0x01,0x20,0x34,0x00,0x80,0xd0,0x00,0x00,0x42,0x03,0x00,0x08,0x0d,0x80,0xd0,0x00, + 0x00,0x42,0x03,0x00,0x08,0x0d,0x00,0x20,0x34,0x00,0x80,0xd0,0x00,0x08,0x0d,0x00, + 0x20,0x34,0x00,0x80,0xd0,0x00,0x00,0x42,0x03,0x00,0x08,0x0d,0x80,0xd0,0x00,0x00, + 0x42,0x03,0x00,0x08,0x4d,0x70,0xb6,0x92,0x71,0xf3,0xd7,0x3f,0x3e,0xab,0x54,0xcf, + 0x2a,0x55,0xb5,0x78,0x42,0x6f,0x5a,0x72,0xa1,0xdc,0x2f,0xcd,0xad,0x3f,0x0b,0x5b, + 0x3f,0x09,0xe0,0x1d,0x69,0x44,0xeb,0xa7,0x60,0xd1,0x72,0xd3,0x76,0xd7,0xb3,0xa1, + 0x5f,0x59,0xae,0x7c,0x4a,0x2d,0xb6,0x38,0x1b,0x88,0xcc,0xed,0xa3,0x49,0xaf,0x47, + 0xfb,0x5b,0x9a,0xa6,0xe9,0x3f,0x97,0x65,0x79,0x70,0x7c,0x86,0xb3,0x87,0xb5,0x9d, + 0x83,0xa3,0xfd,0x2d,0xc1,0x33,0x1a,0x1c,0x9f,0xe1,0x9f,0xcb,0x59,0xa5,0x3a,0x37, + 0x3d,0xa9,0x69,0xda,0xca,0xe6,0x9e,0x83,0xf5,0x5e,0x0d,0xcf,0xc2,0xf2,0x14,0x08, + 0x23,0x23,0x23,0x92,0x24,0xcd,0x2f,0x3f,0xe1,0x6c,0xb6,0xb6,0x73,0xb0,0x34,0x3b, + 0xe1,0xec,0xd8,0x3c,0x44,0xeb,0xd7,0xfa,0x26,0xc2,0xe5,0xcb,0x97,0xa5,0xf3,0x0b, + 0xf1,0x0e,0x5a,0xb4,0xe4,0xfa,0x6a,0xa1,0x96,0x51,0xaa,0x9c,0xee,0x44,0xeb,0xb9, + 0xd3,0x7c,0x99,0x37,0xfb,0x3a,0x7d,0x75,0xca,0xbf,0x97,0x6a,0xf1,0xe4,0xe9,0xf2, + 0x83,0x3a,0x2a,0x13,0x34,0x4d,0xa3,0xcf,0x5f,0xe6,0x4b,0x86,0x3b,0x69,0x1c,0x03, + 0x7c,0xf0,0x9b,0x19,0x64,0xd5,0x1c,0xed,0x6d,0x69,0x76,0xa2,0xbf,0xaf,0x64,0x6b, + 0x8e,0xad,0x5a,0x3c,0x19,0x4d,0x27,0xf5,0x3c,0x66,0xc7,0x4f,0xfb,0x94,0x65,0x79, + 0x63,0x7b,0xd7,0xf0,0xbf,0x9f,0x55,0xaa,0xb4,0xcd,0xe0,0xf8,0x5b,0xce,0xd0,0x5d, + 0x9a,0x9d,0x08,0xc2,0xd3,0x3e,0x40,0x8b,0xd7,0xaf,0xe7,0x4e,0x05,0xe7,0xf4,0x67, + 0xd5,0x9c,0xad,0x3d,0x53,0xd3,0x4e,0xc3,0xaf,0xf8,0x6b,0xb5,0x9f,0x55,0xaa,0x8c, + 0xcd,0x64,0xcc,0x32,0xca,0x10,0x3b,0x06,0x4b,0xeb,0xbb,0xb1,0xbd,0xdb,0x78,0xa8, + 0x74,0xe3,0x57,0x36,0xf7,0x6c,0xb1,0xb9,0xd1,0x0a,0x88,0x13,0x9a,0xb1,0x99,0x9d, + 0x02,0xfb,0x47,0x6c,0xb8,0x6a,0x9a,0x36,0x37,0x3d,0x79,0x78,0x78,0xe8,0xe0,0xc6, + 0x31,0x36,0xcb,0xb2,0xdc,0xfa,0xa5,0xc2,0xbf,0xb6,0x1a,0x8f,0x9f,0xbd,0xf8,0xeb, + 0xdc,0x7f,0xe8,0xf5,0xf8,0xd9,0x0b,0xcb,0xed,0x3f,0x7c,0xfa,0xf2,0xcf,0x7f,0x6b, + 0xec,0x27,0x1f,0x3e,0x7d,0xe1,0x6c,0x69,0xb9,0x8d,0xe5,0xb1,0x75,0x74,0x74,0x74, + 0x74,0x74,0x98,0x1d,0xd8,0x87,0x4f,0x5f,0x6c,0xed,0xfc,0x55,0xe1,0x1d,0xed,0xf0, + 0x55,0xe1,0x9d,0xad,0x23,0xf9,0xf0,0xe9,0xcb,0xf0,0xf0,0x70,0xc7,0x35,0x86,0x87, + 0x87,0xc5,0x7f,0xc8,0x7e,0x65,0x76,0xa8,0xaf,0x0a,0xef,0x1e,0x3f,0x7b,0x61,0xf6, + 0x2d,0xdb,0x83,0xe1,0x45,0x60,0x67,0x34,0x3c,0x3c,0xec,0xf8,0x3a,0x7b,0x88,0x60, + 0x45,0x39,0xde,0x5c,0x75,0x5a,0x3a,0x16,0x59,0x35,0xe7,0xa6,0xe3,0x96,0x2d,0xd1, + 0x49,0x36,0x98,0x63,0x78,0x12,0xf1,0x58,0x73,0xda,0xc4,0x94,0xce,0x2f,0xe8,0x41, + 0x41,0xa6,0x5d,0xd3,0x34,0x41,0xef,0x90,0xba,0xe9,0x91,0x2e,0x32,0x3b,0x54,0x25, + 0xd5,0xb3,0x30,0x35,0xe6,0xe0,0x44,0xce,0x2a,0x55,0x66,0xfb,0xcd,0x14,0x4b,0xa4, + 0xc3,0x76,0xf9,0xf2,0x25,0x5f,0x4e,0x9c,0x55,0xaa,0x96,0x1d,0x89,0x3c,0xc4,0xb5, + 0x76,0x9c,0x69,0xf9,0x95,0x79,0xba,0xfc,0x80,0x78,0xc3,0x34,0x0f,0xdf,0xd9,0xad, + 0x73,0x51,0x64,0x59,0xe6,0x8b,0x2b,0x67,0x03,0x7e,0x6e,0x7a,0x32,0x50,0x6c,0x0e, + 0x16,0xa1,0x17,0x07,0x3a,0xc9,0xcf,0xe3,0x18,0x69,0xa2,0x7b,0xba,0xbb,0x2b,0xdd, + 0xdd,0x25,0xb8,0x5b,0xf1,0x2d,0x03,0x0b,0x76,0x41,0x06,0xc7,0x67,0x12,0xf1,0x18, + 0x19,0xe9,0xa3,0xfd,0x2d,0x91,0x30,0x19,0x13,0xfa,0xde,0x12,0x8e,0x85,0x5c,0x28, + 0xfa,0x11,0x9c,0x6e,0x66,0x41,0x21,0x74,0xba,0xbb,0x8b,0xf9,0x6d,0x66,0x46,0x9a, + 0x99,0xe7,0x3b,0x37,0x6a,0xd4,0x50,0xcb,0x6f,0x50,0x34,0x40,0x3c,0xf4,0xe6,0xb7, + 0xde,0xd0,0xbb,0xb6,0x22,0xf1,0x13,0x5d,0x80,0x62,0xc6,0x27,0x36,0xaf,0x6c,0xee, + 0x05,0xaa,0xa7,0x59,0x80,0x2c,0x74,0xf2,0xd6,0x4d,0x32,0xd2,0x66,0x4a,0x9a,0x99, + 0xe7,0x8c,0x32,0x64,0x16,0xb5,0xf0,0x49,0x78,0xb4,0x36,0x65,0xb0,0x9e,0x3b,0xa5, + 0xd1,0x45,0xd4,0xc9,0x28,0x43,0x34,0xd2,0xec,0x46,0x7b,0xbc,0x82,0x9e,0xcd,0xad, + 0x0f,0x6b,0x04,0x59,0x43,0x93,0x40,0x34,0x54,0xd2,0x67,0x95,0x2a,0xb5,0x3c,0xbc, + 0x73,0xa3,0xe6,0xcc,0x7d,0x51,0x8b,0x27,0xec,0x25,0x42,0xd0,0x44,0x3c,0xc6,0x0c, + 0xdb,0xdc,0xf4,0xa4,0xfb,0x14,0x9d,0x63,0x73,0xf8,0xfa,0xe1,0xb0,0xde,0xca,0xb2, + 0xd3,0x5f,0x9a,0x9d,0x68,0xfe,0x48,0x5b,0xdb,0x39,0x08,0x2c,0x9b,0xa5,0x40,0xc5, + 0xa1,0xe9,0x56,0x2d,0x0e,0x74,0xae,0x16,0x6a,0x6f,0xae,0x3a,0x33,0x95,0x6f,0x32, + 0x26,0x59,0x35,0x47,0x29,0x12,0xe6,0x15,0x89,0x3b,0xf8,0x86,0x8b,0xfd,0x88,0x74, + 0x65,0xce,0x28,0x43,0x47,0xb2,0x7c,0x9d,0x7f,0x48,0xae,0x6c,0xee,0xf5,0xf7,0xf5, + 0x36,0xb9,0x01,0x2e,0x1b,0xdb,0xfa,0x87,0xd2,0xfc,0xf2,0x13,0x4d,0x4b,0xd2,0x39, + 0x36,0xf3,0x60,0xd4,0xe2,0x09,0x8b,0xa3,0x8b,0xdf,0x88,0xe8,0x5a,0x68,0x33,0x23, + 0xcd,0xd4,0xf3,0xe2,0x40,0xa7,0xdd,0xfb,0x97,0x2f,0x5f,0x12,0x9b,0xc9,0x95,0x64, + 0x0e,0xe5,0x6a,0xa1,0x76,0xef,0x79,0x81,0x6f,0xe1,0x12,0xf1,0xd8,0xc6,0xf6,0x2e, + 0x4b,0x82,0x2c,0xcd,0x4e,0x8c,0xa6,0x93,0x73,0xd3,0x93,0x23,0x23,0x23,0x4d,0x36, + 0xd8,0x75,0x61,0x0a,0xf6,0x5e,0x30,0xd6,0xe1,0x09,0x8e,0xf6,0xb7,0x28,0xd8,0xe2, + 0x87,0x97,0x19,0x5a,0x42,0x93,0x91,0xae,0x53,0xd2,0x8c,0xdc,0xb6,0xac,0x02,0xbb, + 0xeb,0x8b,0x03,0x9d,0xc7,0x8f,0x14,0xf5,0x5f,0xff,0xa0,0xd7,0xaf,0x3f,0x0d,0x64, + 0xef,0xa6,0x88,0xeb,0xf7,0x9e,0x17,0x2c,0x8f,0x67,0x61,0x6a,0xec,0xfd,0xc7,0xcf, + 0x2b,0x9b,0x7b,0xfa,0x8c,0xf1,0x68,0x3a,0x39,0x32,0x32,0xb2,0xb6,0x73,0xe0,0xb7, + 0xde,0x20,0x97,0x94,0xe2,0x1b,0xad,0x75,0x58,0x59,0x9e,0xbc,0x55,0x6a,0xa7,0x2d, + 0x09,0xad,0x37,0xd2,0xa4,0x19,0x1c,0x9b,0xe7,0x44,0x3c,0x76,0xfc,0x48,0x39,0x7e, + 0xa4,0xd4,0x65,0x0d,0x12,0xf1,0x98,0x92,0xea,0x61,0x9c,0x16,0xb1,0xb5,0x44,0xeb, + 0x8d,0xed,0xdd,0x97,0xf9,0x92,0x9e,0xd9,0x4b,0xb3,0x13,0xca,0x2f,0xbf,0xf9,0x77, + 0x6b,0x0d,0xe3,0x1b,0x7a,0x7d,0x2f,0x9e,0x61,0xf1,0x0a,0xec,0xf4,0xe7,0xa6,0x27, + 0x03,0xc8,0xe9,0x20,0x12,0x9a,0x19,0xe9,0xf5,0xdc,0x29,0xd5,0x88,0xb1,0xe0,0x86, + 0x83,0x5d,0x71,0xd2,0x63,0xec,0xbf,0x88,0xef,0x8d,0x92,0x6a,0x87,0x87,0x87,0x2f, + 0xf3,0x25,0xba,0xaf,0xaf,0x1f,0x0e,0xfb,0x17,0x6d,0x60,0xf9,0x94,0xc6,0xd0,0x98, + 0xdd,0x0c,0x8b,0x27,0x78,0x99,0x2f,0x2d,0x4c,0x8d,0xb1,0xb1,0xd4,0xaa,0x30,0x4b, + 0x9b,0x11,0x5a,0x6f,0xa4,0xef,0x3d,0x2f,0xb8,0x09,0x6e,0xf0,0x41,0x66,0x2f,0x5f, + 0xbe,0x74,0x60,0x69,0x94,0x54,0xcf,0xc6,0xf6,0x2e,0x71,0x7a,0x69,0x76,0xc2,0x0f, + 0x33,0xc9,0x8f,0x22,0x27,0xe2,0x31,0xa6,0x3a,0x9a,0x63,0x29,0xd9,0xb8,0x5a,0x98, + 0x1a,0xf3,0xf5,0xc4,0x43,0x48,0x68,0x66,0xa4,0x99,0x4b,0x17,0x40,0x9f,0x5a,0x1f, + 0xd7,0xf3,0xc3,0x4c,0xb2,0x28,0x8d,0x74,0x5d,0x62,0x5f,0xf7,0x62,0xd2,0x56,0xbf, + 0xa5,0x7f,0xd0,0x8f,0x2b,0x36,0x98,0x9f,0x2e,0x3f,0x08,0x94,0xf0,0x08,0xee,0x14, + 0xac,0x8c,0x32,0xc4,0xb2,0xd6,0x0e,0x82,0x1b,0xcd,0x7c,0x92,0xf8,0xaa,0x37,0xc8, + 0x10,0xfe,0xf8,0xc3,0xf7,0x8d,0x2f,0xe6,0xa2,0x99,0x0d,0x27,0xff,0x2e,0x5a,0x22, + 0x1e,0x9b,0x5f,0x7e,0x42,0xc3,0x89,0x2a,0x3a,0x40,0x68,0xeb,0x4b,0x46,0xf9,0x6d, + 0x67,0xea,0xb9,0xdd,0xc1,0xf4,0x86,0x08,0x38,0x31,0x07,0xff,0x82,0x21,0x4a,0xaa, + 0x87,0x95,0xfe,0xf9,0x1d,0xed,0x09,0x03,0xa1,0xc9,0xfe,0x65,0xef,0xa6,0x6c,0x4d, + 0xcd,0xb2,0x05,0x72,0x07,0xd3,0xdd,0x5d,0x8e,0xf7,0xef,0xdf,0xb3,0x9e,0xf9,0x5b, + 0x2b,0x9b,0x7b,0xef,0x3f,0x7e,0x36,0x7b,0xb1,0x18,0xb9,0xd9,0x91,0x30,0x9d,0xe0, + 0x87,0x30,0x08,0xa0,0x98,0x0e,0x34,0xa1,0x29,0xaa,0xe0,0x13,0x9b,0xcf,0x2a,0x55, + 0x52,0xe7,0x6e,0xea,0x9c,0x98,0x2a,0xf0,0xfc,0x19,0xc2,0x4a,0xb1,0x29,0x9d,0x69, + 0xf6,0x12,0x8c,0x75,0xf8,0xa7,0xb3,0x99,0x98,0x1e,0x4d,0x27,0x83,0x20,0xa6,0xc3, + 0xdc,0xc6,0x80,0xca,0x36,0xcc,0xd8,0x4c,0x29,0x15,0xbe,0x9e,0x51,0x8b,0x27,0x6b, + 0x3b,0x07,0x66,0xf7,0x49,0x5f,0xd5,0xe0,0x79,0x71,0xa6,0xa0,0x0e,0xd6,0xc7,0x3a, + 0xcc,0x8c,0x28,0xbd,0x19,0x4d,0x27,0x0d,0xaf,0xc6,0x59,0xa5,0xba,0xb6,0x73,0xe0, + 0x38,0xf7,0xc9,0xc4,0xb4,0x24,0x49,0x41,0x10,0xd3,0x1d,0x61,0x65,0x33,0x9b,0x48, + 0x9b,0xce,0x9d,0xd2,0x0a,0xc4,0xfa,0xa7,0x39,0x9b,0x25,0x70,0x7f,0xe8,0x36,0x67, + 0x8e,0x2d,0x4d,0xc7,0x58,0xd2,0xcd,0x8e,0x66,0xe6,0x90,0x4d,0x80,0xd5,0x17,0xdd, + 0x7b,0xa8,0x37,0x58,0xa9,0xb1,0x48,0xf0,0x81,0x72,0x78,0x6a,0xf1,0xc4,0xb0,0x92, + 0xf3,0x65,0xbe,0x44,0x13,0x07,0x47,0xd3,0x7f,0x96,0xa3,0x90,0x4a,0xd1,0x9f,0x08, + 0x67,0x0e,0xac,0x88,0x98,0x5e,0x9a,0x9d,0x20,0x31,0x1d,0xf5,0x59,0xdf,0xfe,0x81, + 0xea,0x9c,0xf4,0xb5,0x1c,0xfa,0x12,0x25,0x5a,0x6a,0x9b,0x73,0x0b,0xa9,0x94,0x9e, + 0x6a,0x71,0xf4,0x59,0xdf,0x3a,0x97,0xcb,0x8f,0xc9,0x1a,0x4c,0x6f,0x88,0x4c,0x33, + 0xc9,0x28,0x43,0x4b,0xd7,0xc3,0xcc,0xf0,0x74,0x94,0x54,0x4f,0x72,0x7b,0x97,0x6a, + 0x3e,0xcd,0xe6,0x66,0xbb,0x1c,0x96,0x0b,0x53,0x63,0x47,0xfb,0xb2,0xa6,0x69,0x47, + 0xfb,0x5b,0xb6,0x66,0xfb,0x86,0x90,0xd0,0xfd,0x7d,0xbd,0x52,0xa1,0xc8,0xb1,0x94, + 0x86,0x48,0xde,0xba,0x99,0xee,0xee,0xe2,0x64,0x5b,0x28,0x59,0x9d,0x51,0xfe,0x58, + 0x70,0x9b,0xad,0xb6,0x4d,0xa1,0x40,0xc1,0x55,0xe3,0x17,0xa6,0xc6,0xfa,0xfb,0x4a, + 0x64,0xc6,0x24,0x5d,0x4d,0xbd,0x60,0x3b,0x0b,0xc3,0xc3,0x16,0x61,0x2a,0x19,0xdd, + 0xc6,0xfa,0x0d,0xfe,0xc0,0xe3,0xd4,0x88,0x53,0x95,0x55,0x9d,0x49,0x96,0x8c,0xe6, + 0x81,0x73,0x54,0x0d,0x9f,0xf1,0x1b,0xdb,0xbb,0x3f,0xfe,0xf0,0x7d,0xcb,0xe9,0x84, + 0xb5,0xbe,0x6d,0x2b,0x99,0x60,0x46,0xc4,0x71,0x7d,0x40,0x68,0x20,0x84,0x40,0xb3, + 0x46,0x20,0x54,0xf8,0x3f,0x96,0xc0,0x66,0x1b,0x5c,0xbd,0x1b,0xb3,0x00,0x00,0x00, + 0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/png_benchmark/octocat_32bpp.h b/libraries/PNGdec/examples/png_benchmark/octocat_32bpp.h new file mode 100644 index 0000000..25faa19 --- /dev/null +++ b/libraries/PNGdec/examples/png_benchmark/octocat_32bpp.h @@ -0,0 +1,807 @@ +// +// octocat_32bpp +// Data size = 12735 bytes +// +// PNG, Compression=Flate, Size: 240 x 200, 32-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t octocat_32bpp[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0xc8,0x08,0x06,0x00,0x00,0x00,0xd6,0x7c,0x6c, + 0x52,0x00,0x00,0x00,0x06,0x62,0x4b,0x47,0x44,0x00,0xff,0x00,0xff,0x00,0xff,0xa0, + 0xbd,0xa7,0x93,0x00,0x00,0x20,0x00,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x9d,0x77, + 0x78,0x1c,0xd5,0xb9,0xff,0x3f,0x33,0xb3,0x4d,0xab,0xb6,0x6a,0xb6,0xaa,0x67,0x6d, + 0xd9,0x72,0x05,0x0c,0xd8,0x18,0xb0,0x0d,0xa6,0x07,0x08,0x25,0x09,0x10,0x12,0xd2, + 0x08,0x4a,0xc2,0x25,0x9d,0x24,0xa4,0x91,0x9b,0x9b,0x5f,0xca,0x4d,0x42,0x92,0x9b, + 0xe4,0x92,0x0b,0x09,0xe2,0x86,0x70,0x93,0x00,0xa1,0x27,0x10,0x6a,0x42,0x2f,0xc1, + 0x80,0x01,0x03,0x96,0xe5,0xb6,0xe3,0x22,0xab,0x6b,0xd5,0x56,0xdb,0x66,0xe6,0xf7, + 0xc7,0x8c,0x64,0xc9,0x96,0xad,0x5d,0xd5,0x2d,0xe7,0xfb,0x3c,0xf3,0x48,0x5a,0xed, + 0x94,0x73,0xe6,0xfd,0x9e,0xf7,0x9c,0xf7,0xbc,0x05,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x92,0x80,0x94,0xed,0x1d,0xe0,0x57,0x55,0x2f,0xe0,0xb4, + 0xfb,0x42,0x97,0x24,0x29,0xba,0x2b,0x10,0x88,0x08,0xd1,0x98,0x5d,0xcc,0xf7,0xfb, + 0x5d,0xa6,0x69,0xba,0x00,0x87,0xfd,0x51,0x5c,0x51,0x94,0xd0,0x8e,0x9d,0x3b,0x0d, + 0xd1,0x3b,0x82,0xc0,0x43,0xe4,0x3d,0x0b,0xb8,0x17,0xc8,0x1f,0x12,0x12,0xa0,0x03, + 0xd8,0x03,0xbc,0x09,0xbc,0x0c,0x3c,0x1b,0xd0,0xb4,0x6d,0x42,0x54,0xa6,0xfd,0x5d, + 0x54,0x03,0x6b,0xed,0x63,0x25,0x30,0x1f,0x28,0x03,0xdc,0xf6,0x57,0x06,0x81,0xff, + 0x08,0x68,0xda,0x4f,0x45,0x6f,0x09,0x02,0x0f,0x09,0xcd,0xdd,0xc0,0x25,0xe3,0x7c, + 0x4d,0x07,0x76,0x01,0xf7,0x03,0x77,0x06,0x34,0xed,0x75,0x21,0x36,0x53,0xd6,0xff, + 0xf3,0x81,0x0f,0xd9,0xef,0x60,0x39,0xe0,0x1a,0xe7,0x94,0x00,0xb0,0x20,0xa0,0x69, + 0xa6,0xe8,0xbd,0x2c,0x27,0xb0,0x5f,0x55,0xf3,0x6d,0x6d,0xeb,0x4a,0xf2,0xd4,0x77, + 0x80,0xdf,0x01,0xb7,0x07,0x34,0x2d,0x28,0x44,0x28,0xe9,0x7e,0xf7,0x00,0xef,0x03, + 0xae,0x06,0x4e,0x99,0xc0,0x25,0xd6,0x06,0x34,0xed,0x45,0xd1,0x93,0x16,0xe4,0x2c, + 0x6e,0xfb,0x85,0x13,0x20,0x2f,0xb6,0xa6,0xf8,0x15,0xb0,0xc7,0xaf,0xaa,0x37,0xfa, + 0x55,0x75,0xa1,0x10,0xa3,0x84,0x88,0x5b,0xe6,0x57,0xd5,0xef,0x00,0x3b,0x81,0x3f, + 0x4f,0x90,0xbc,0x24,0x30,0x63,0x12,0x1a,0x38,0x4b,0x04,0xea,0x2f,0xc0,0xa5,0x53, + 0x70,0xa9,0x28,0x70,0x0f,0xf0,0xff,0x02,0x9a,0xb6,0x55,0x88,0xd4,0xa1,0xc4,0x05, + 0xbe,0x0e,0x7c,0x7a,0x84,0xad,0x61,0x32,0xd8,0x0a,0x2c,0x0f,0x68,0x9a,0x2e,0x7a, + 0x37,0x4b,0x09,0xec,0x57,0x55,0x07,0xb0,0x1f,0x28,0x9d,0xc2,0xcb,0xea,0xc0,0x1f, + 0x80,0xef,0x06,0x34,0x6d,0xaf,0x20,0xae,0x5a,0x00,0x7c,0x15,0xb8,0x16,0xc8,0x9d, + 0xe2,0xcb,0x2f,0x08,0x68,0xda,0x2e,0x41,0xdf,0xec,0x9d,0x42,0x1f,0x35,0xc5,0xe4, + 0x05,0x50,0x80,0x4f,0x02,0x4d,0x7e,0x55,0xfd,0x81,0xbd,0xc6,0xce,0xca,0xc1,0xd1, + 0xaf,0xaa,0x9f,0x01,0xb6,0x01,0xdf,0x99,0x06,0xf2,0x02,0x9c,0x2e,0xa8,0x6b,0xc1, + 0x91,0xa5,0xed,0x3e,0x79,0x1a,0xaf,0x9d,0x03,0x7c,0x1b,0xf8,0x84,0x5f,0x55,0xaf, + 0x0b,0x68,0xda,0x9f,0xa7,0x91,0x2c,0x25,0x40,0x89,0x3d,0x35,0xcd,0xb3,0x0f,0x8f, + 0xfd,0x5e,0x1d,0xf6,0xa0,0x12,0xb3,0x67,0x07,0x31,0x60,0x00,0x08,0x01,0x7d,0x40, + 0x37,0xd0,0x15,0xd0,0xb4,0xfe,0x29,0x7c,0x9e,0xf5,0xc0,0x7f,0x03,0xc7,0x4c,0xf3, + 0xfb,0x3b,0x09,0xb8,0x55,0xd0,0x37,0x7b,0x09,0xbc,0x7a,0x06,0xee,0x51,0x05,0xfc, + 0xc9,0xaf,0xaa,0x57,0x01,0x57,0x27,0xb3,0x97,0xec,0x57,0x55,0x09,0x6b,0xff,0xb3, + 0x1a,0x58,0x0a,0x2c,0x02,0xfc,0x40,0x0d,0xa0,0xda,0x9f,0x17,0x8f,0x98,0x41,0x25, + 0xbb,0x14,0x1a,0xda,0x86,0x31,0xfd,0xaa,0x1a,0x03,0x9a,0x81,0xbd,0x58,0xfb,0xdf, + 0x3b,0x81,0x1d,0x40,0x13,0xb0,0x05,0xe8,0x0b,0x68,0x5a,0x3c,0x81,0x81,0xe4,0x67, + 0xc0,0xc7,0x67,0x68,0x59,0x76,0x82,0xa0,0x6e,0x76,0xaf,0x81,0x5f,0x07,0x8e,0x9d, + 0xc1,0x5b,0x86,0x81,0xef,0x01,0x3f,0x0f,0x68,0x5a,0x6c,0x8c,0xe7,0x29,0x05,0x96, + 0xd9,0x82,0x79,0x1c,0xb0,0xc2,0x26,0xad,0x27,0x05,0xba,0x6b,0xaf,0x4d,0xe6,0xd7, + 0x81,0x8d,0xf6,0xcf,0x5d,0x43,0x46,0x24,0xbf,0xaa,0x5e,0x0e,0xfc,0x1a,0xcb,0xe9, + 0x62,0xa6,0xa0,0x03,0x6e,0x61,0xc8,0xca,0x42,0x02,0xfb,0x55,0x35,0xc7,0xd6,0x34, + 0x25,0xb3,0x70,0xfb,0x57,0x81,0x2b,0x81,0x16,0x60,0x83,0x7d,0x9c,0x0a,0xd4,0xda, + 0x53,0xef,0x74,0x80,0x89,0x65,0x00,0xfc,0x97,0x3d,0xc0,0x9c,0x3b,0x4b,0xcf,0xb1, + 0x34,0xa0,0x69,0x8d,0x62,0x0a,0x9d,0x7d,0xc8,0x9b,0x25,0xf2,0x02,0xac,0x02,0x36, + 0xd9,0x03,0xa7,0x92,0xc6,0x83,0x7e,0x25,0x96,0x33,0xc6,0x6c,0x62,0x01,0x20,0x08, + 0x9c,0x85,0x6d,0xae,0x14,0x7d,0x9e,0x11,0xa8,0x11,0x5d,0x90,0x9d,0xdb,0x48,0x73, + 0xc4,0x6b,0xcf,0x08,0x94,0x88,0x2e,0xc8,0x4e,0x02,0x17,0x8a,0xd7,0x9e,0x11,0xf0, + 0x89,0x2e,0xc8,0x4e,0x02,0xbb,0xc5,0x6b,0x17,0xef,0x51,0x10,0x38,0x7d,0xa1,0x88, + 0xd7,0x2e,0xde,0xa3,0x20,0x70,0xfa,0x42,0x64,0xdb,0xc8,0x0c,0x44,0x45,0x17,0x64, + 0x27,0x81,0x07,0xc4,0x6b,0xcf,0x08,0xf4,0x8b,0x2e,0xc8,0x4e,0x02,0xb7,0x89,0xd7, + 0x9e,0x11,0xe8,0x14,0x5d,0x90,0x9d,0x04,0x6e,0x16,0xaf,0x3d,0x23,0xb0,0x5f,0x74, + 0x41,0x76,0x12,0x38,0x28,0xa6,0x5f,0x19,0x81,0x1d,0xa2,0x0b,0xb2,0x77,0x0d,0xbc, + 0x5b,0xbc,0xfa,0xb4,0x47,0xa3,0xe8,0x82,0x2c,0x24,0xb0,0x9d,0xd1,0x70,0xb3,0x78, + 0xf5,0x69,0x8d,0xed,0x01,0x4d,0x13,0xc6,0x48,0xb2,0x37,0x23,0x87,0xc8,0x6a,0x28, + 0xde,0x9f,0x20,0x70,0x1a,0xe3,0x69,0x0e,0x04,0xb5,0x0b,0xa4,0x1f,0xfe,0x21,0xba, + 0x20,0x8b,0x09,0x1c,0xd0,0xb4,0xb7,0xb0,0x62,0x82,0x05,0x04,0x04,0x81,0xd3,0x14, + 0x77,0x89,0xd7,0x9f,0xb6,0xb8,0xd5,0xaf,0xaa,0xe7,0x8b,0x6e,0xc8,0x6e,0x02,0x17, + 0x89,0xd7,0x9f,0xb6,0x70,0x00,0x77,0xf9,0x55,0x75,0x8d,0x20,0x70,0x16,0xc2,0xaf, + 0xaa,0xd7,0x01,0xf5,0x82,0x07,0x69,0x8d,0x5c,0xe0,0x41,0xbb,0x28,0x5a,0xd6,0x22, + 0x1b,0x73,0x62,0x9d,0x07,0xfc,0x2d,0xcb,0x67,0x1f,0x99,0x84,0x8d,0xc0,0xba,0x80, + 0xa6,0x65,0x65,0x70,0x83,0x92,0x65,0xe4,0xf5,0x03,0x8f,0x93,0x3e,0x09,0xe4,0x04, + 0xc6,0x47,0x15,0x50,0x14,0xec,0xe9,0x79,0x44,0x10,0x38,0xb3,0xc9,0xeb,0x00,0xfe, + 0x0e,0x88,0x62,0x64,0x99,0x87,0x55,0x3e,0x9f,0x6f,0x63,0xb0,0xa7,0x67,0xbb,0x58, + 0x03,0x67,0x2e,0xae,0x03,0xd6,0x08,0x59,0xcf,0x58,0x39,0xbe,0x39,0x1b,0xcb,0xd9, + 0x64,0x85,0x06,0xf6,0xab,0xea,0x62,0xe0,0x4e,0x44,0x46,0xc8,0x4c,0x46,0x21,0xe0, + 0x09,0xf6,0xf4,0x3c,0x26,0x34,0x70,0xe6,0xe1,0x46,0x44,0x0e,0xa5,0x6c,0xc0,0xe7, + 0xfd,0xaa,0xba,0x44,0x10,0x38,0xb3,0xb4,0xef,0xf9,0xc0,0x99,0x42,0xb6,0xb3,0x02, + 0x0e,0xe0,0xa7,0xd9,0xd4,0x60,0x29,0xc3,0xc9,0x2b,0x03,0x6f,0x60,0x95,0x13,0x15, + 0xc8,0x0e,0x18,0xc0,0x89,0x01,0x4d,0xdb,0x28,0x34,0x70,0xfa,0xe3,0x22,0x41,0xde, + 0xac,0x83,0x0c,0x7c,0x5d,0x68,0xe0,0xf4,0xd7,0xbe,0x12,0xf0,0x3c,0xd3,0x5b,0x0b, + 0x58,0x20,0x35,0x11,0x07,0x16,0x05,0x34,0x2d,0x20,0x34,0x70,0xfa,0xe2,0x38,0x41, + 0xde,0xac,0x5e,0x0b,0x67,0x85,0xab,0x6c,0x26,0x13,0x58,0xf8,0x3a,0x67,0x37,0xae, + 0xb4,0x67,0x61,0x82,0xc0,0x69,0x38,0x7d,0x76,0x02,0x1f,0x12,0x32,0x9c,0xd5,0xa8, + 0xc4,0xaa,0xbd,0x2c,0x08,0x9c,0x86,0x38,0x0b,0x51,0xc4,0x4c,0x00,0xde,0x2f,0x08, + 0x9c,0x9e,0xb8,0x58,0xc8,0xae,0x00,0x70,0x9e,0x20,0x70,0x7a,0xe2,0x6c,0x21,0xbb, + 0x02,0x80,0xdf,0xaf,0xaa,0xb5,0x82,0xc0,0xe9,0xb5,0xfe,0xad,0x05,0xaa,0x85,0xec, + 0x0a,0x60,0xf9,0xfa,0x9f,0x20,0x08,0x9c,0x5e,0x38,0x1e,0x51,0x7a,0x52,0xe0,0x00, + 0x4e,0x16,0x04,0x4e,0x2f,0xac,0x12,0x32,0x2b,0x30,0x02,0xc7,0x08,0x02,0xa7,0x17, + 0x56,0x08,0x99,0x15,0x18,0x81,0x5a,0xbf,0xaa,0xba,0x32,0xb5,0x71,0x19,0x15,0x1f, + 0x6b,0x07,0x2f,0xa4,0x9c,0xd1,0x22,0x1a,0xd7,0x09,0xc5,0x74,0x62,0x86,0x89,0x53, + 0x91,0x29,0xcc,0x71,0xe3,0x71,0x3a,0x88,0xc6,0xe3,0x74,0x87,0x22,0xc4,0x74,0x03, + 0x09,0x70,0xc8,0x12,0x4e,0x59,0xc2,0xe5,0x50,0x70,0x28,0xf2,0xac,0xfb,0xb9,0x9a, + 0x40,0x5c,0x37,0x88,0xc4,0x75,0xa2,0xba,0x81,0x6e,0x82,0x2c,0x4b,0x94,0x78,0x3d, + 0x14,0xe6,0x7a,0xf0,0xb8,0x9c,0x98,0xa6,0x49,0xdf,0x60,0x84,0xfd,0xc1,0x7e,0xe2, + 0xba,0x81,0xc7,0x21,0xe3,0x75,0x39,0x90,0xa5,0x94,0xf1,0xa1,0xa8,0x00,0xbc,0x64, + 0x68,0x41,0xf0,0x4c,0x0b,0x70,0xf7,0x00,0x73,0x66,0x53,0xe0,0x9d,0x8a,0x8c,0x7f, + 0x6e,0x09,0x6b,0x96,0x2e,0xa0,0xa2,0xb4,0x88,0xa2,0x7c,0x2f,0x79,0xde,0x1c,0x0a, + 0x72,0xbd,0x38,0x14,0x19,0xcc,0x31,0x0a,0x42,0xd8,0xc2,0x1e,0xd7,0x0d,0x22,0xb1, + 0x18,0xa1,0xc1,0x08,0x83,0x91,0x28,0xa6,0x69,0x12,0x8d,0xc7,0xe9,0x0b,0x85,0xe9, + 0x1d,0x08,0x11,0x8f,0xeb,0xc4,0x74,0x83,0xe0,0x40,0x88,0xd6,0xae,0x5e,0x5a,0x3b, + 0x83,0x0c,0x46,0xa3,0x98,0x26,0x18,0xa6,0x89,0x6e,0x98,0xe8,0x86,0x31,0xfc,0xf7, + 0xd0,0xa5,0x65,0x49,0x42,0x96,0x24,0x1c,0x8a,0x8c,0x2c,0x49,0x48,0x12,0xb8,0x1c, + 0x4e,0xca,0x4b,0x0a,0x99,0x5b,0x5c,0x48,0x51,0x9e,0xd7,0x1e,0x34,0x14,0x0a,0xf2, + 0xbc,0xe4,0x7b,0x3d,0xb8,0x1c,0x16,0x09,0x73,0x3c,0x6e,0x72,0x73,0xdc,0xb8,0x9d, + 0x4e,0x64,0x59,0x1a,0xfb,0xf9,0x47,0xb4,0x63,0x30,0x12,0xa3,0xbb,0xb7,0x8f,0x50, + 0x24,0xca,0xbe,0xb6,0x4e,0x1a,0xf7,0xb4,0xb0,0x69,0xdb,0x6e,0xfa,0x07,0x23,0x48, + 0xb3,0x43,0x6a,0xc9,0x26,0x71,0x30,0x13,0x09,0x9c,0x51,0xae,0x66,0x7e,0x55,0x2d, + 0x66,0x16,0x0a,0x3f,0x47,0xe3,0x3a,0x6b,0x97,0x2d,0xe0,0x94,0x95,0x4b,0x58,0x50, + 0x39,0x87,0xa2,0xfc,0xdc,0x61,0x02,0x01,0x98,0xc3,0x64,0x1a,0xdd,0xdd,0xe6,0x41, + 0x64,0x48,0x54,0xc0,0x25,0x9b,0x2c,0x92,0x7d,0x8e,0x09,0xe8,0x86,0x41,0x4c,0xd7, + 0xd1,0x75,0x03,0xd3,0x26,0x33,0x98,0xc8,0x92,0x8c,0x2c,0x4b,0x28,0xb2,0x8c,0x43, + 0x51,0x50,0x14,0x19,0xd9,0xbe,0xb7,0x69,0x0f,0x3b,0x66,0x82,0x45,0x66,0x46,0x3e, + 0xaf,0x24,0x49,0x63,0xb6,0xe7,0xe0,0xb6,0x4a,0x92,0x44,0x38,0x1a,0x63,0x77,0x6b, + 0x07,0xaf,0x6e,0xd9,0xc9,0xc3,0xff,0x7a,0x9b,0x59,0xa8,0x6a,0x73,0x66,0x40,0xd3, + 0x32,0xb2,0x1c,0x4b,0xa6,0x69,0xe0,0x19,0xf5,0xbe,0x32,0x0c,0x93,0x75,0x47,0xd5, + 0x72,0xe1,0xba,0xe3,0xa9,0x2a,0x2d,0x1e,0x52,0xa4,0xb8,0x3d,0x6e,0xbc,0xde,0x1c, + 0x72,0x3c,0x1e,0x5c,0x2e,0x27,0x4e,0xa7,0x13,0x45,0x51,0x90,0x64,0x69,0xd4,0x88, + 0x69,0x9a,0x60,0x9a,0x06,0xba,0x61,0xa0,0xeb,0x06,0xba,0xae,0xa3,0xeb,0x3a,0xf1, + 0xb8,0x4e,0x3c,0x1e,0xb7,0x0f,0xeb,0xf7,0x58,0x2c,0x8e,0x1e,0x8f,0x5b,0x1a,0xd6, + 0x26,0xb1,0x39,0x74,0x11,0xfb,0x6f,0x97,0xa2,0x80,0x72,0x64,0x03,0xbc,0x69,0x18, + 0xe8,0x63,0x90,0x52,0x96,0x65,0x1c,0x0e,0x07,0x0e,0x87,0x03,0xa7,0xd3,0x81,0xc3, + 0xa1,0x0c,0xff,0xed,0xb0,0xb5,0xb3,0x32,0x7c,0xc8,0x36,0x41,0xa5,0x03,0x23,0x8a, + 0x09,0x26,0x26,0x86,0x61,0x10,0x8f,0xc5,0x89,0x46,0x63,0x84,0x23,0x11,0x42,0xa1, + 0x41,0xa4,0x81,0x10,0x8b,0xaa,0xcb,0xa9,0xab,0xa9,0xe0,0x3d,0x27,0x1e,0xc3,0xb3, + 0x6f,0x6c,0xe1,0x8e,0xa7,0x5e,0xc5,0x21,0xcf,0x98,0xfe,0x28,0x15,0x6b,0xe0,0xf4, + 0x80,0x6f,0xc6,0x46,0x0a,0xaf,0x87,0xab,0x2f,0x3e,0x9d,0x15,0xf3,0xab,0x91,0x24, + 0x89,0xbc,0xbc,0x5c,0x8a,0x8b,0x8b,0x28,0xc8,0xcf,0xc3,0xe1,0x98,0x9e,0x5d,0xac, + 0x21,0x0d,0x17,0x8f,0xeb,0xc3,0x64,0xd7,0x75,0x03,0xdd,0xd0,0x31,0x0c,0x03,0x43, + 0x37,0x2c,0xcd,0x3f,0x42,0xbb,0x4a,0x48,0x96,0xb6,0x96,0x2c,0x2d,0x2c,0x2b,0x32, + 0xb2,0x2c,0x0f,0x13,0xd1,0xa1,0x58,0x44,0x1d,0x4b,0xa3,0x4e,0x14,0x6e,0x97,0x8b, + 0xdc,0xdc,0xd1,0xcf,0xdd,0x3f,0x10,0xa2,0xbb,0xdb,0x9a,0xc5,0x5e,0xb4,0x7e,0x15, + 0xc7,0x2f,0x59,0xc0,0xef,0x1f,0x7e,0x86,0xad,0x7b,0xdb,0x32,0x6e,0x60,0x17,0x04, + 0x9e,0xdc,0x1a,0x78,0xda,0xb1,0xb4,0x66,0x2e,0xff,0xf6,0xbe,0x33,0x29,0x2e,0xc8, + 0xa3,0xb0,0xb0,0x80,0xf2,0xb9,0x65,0xe4,0xe4,0x4c,0xff,0xad,0x87,0x48,0xe6,0x72, + 0xc9,0x80,0x33,0x7d,0xd6,0x69,0x92,0x44,0x7e,0x5e,0x2e,0xf9,0x79,0xb9,0x54,0x54, + 0xcc,0xa5,0xad,0xad,0x03,0x49,0x92,0xf8,0xda,0x87,0xdf,0xcb,0x9d,0x4f,0xbe,0xc8, + 0x13,0xaf,0x6d,0x99,0xee,0xf5,0xb1,0xb0,0x42,0x8b,0xf6,0x58,0x58,0xb3,0xc4,0xcf, + 0x55,0x17,0x9c,0x46,0x41,0xae,0x97,0x79,0x35,0x95,0x14,0x14,0x64,0x5d,0x26,0xd3, + 0x49,0xc1,0xe9,0x70,0x50,0x55,0x59,0x4e,0x49,0x71,0x11,0xda,0xee,0xbd,0x7c,0xf4, + 0x3d,0xeb,0x29,0xf0,0xe6,0x70,0xdf,0xf3,0x9b,0x04,0x81,0x05,0x81,0xa7,0xd7,0x3a, + 0xb2,0x6a,0xd1,0x3c,0x3e,0x75,0xe1,0xe9,0x14,0x15,0xe6,0xb3,0x60,0xbe,0x8a,0xd3, + 0x29,0xb2,0xd4,0x4e,0x78,0xaa,0xe4,0x71,0xb3,0x68,0xe1,0x7c,0x76,0xef,0x69,0xe6, + 0x7d,0xa7,0xae,0xc6,0x04,0xee,0x9f,0x3e,0x12,0xeb,0x82,0xc0,0xe9,0x81,0xd8,0x74, + 0x5d,0x78,0x7e,0x79,0x09,0xf5,0x17,0x9e,0x46,0x49,0x91,0x8f,0x05,0xf3,0x6b,0x50, + 0x14,0xe1,0xad,0x39,0x59,0xc8,0xb2,0x8c,0x3a,0xaf,0x1a,0x45,0x91,0xb9,0x68,0xfd, + 0x2a,0x82,0xfd,0x03,0x3c,0xf5,0x46,0x93,0xe8,0x98,0x2c,0x26,0x70,0x7c,0x5a,0x2c, + 0x20,0xb9,0x1e,0xbe,0x78,0xe9,0x39,0xcc,0x2d,0x29,0x66,0xc1,0xfc,0x79,0x28,0xca, + 0x04,0x1c,0xd8,0x24,0x09,0xc9,0x65,0x95,0x64,0x32,0x23,0x83,0xcc,0xc2,0x56,0xca, + 0xf4,0x4e,0x7c,0x24,0x19,0xc9,0x69,0xb7,0x2f,0x1a,0x4a,0xa6,0x5b,0xa8,0xa9,0xae, + 0x04,0xe0,0xc3,0x67,0xad,0xa3,0xad,0xbb,0x8f,0x77,0xb4,0xfd,0x69,0x21,0x17,0x82, + 0xc0,0x53,0x8f,0xd0,0x54,0x5f,0xd0,0x30,0x4d,0xfe,0xed,0xa2,0x33,0xa8,0x9a,0x53, + 0xca,0xfc,0x09,0x90,0x57,0x29,0x98,0x83,0xb3,0xbc,0x16,0x25,0xbf,0x18,0x24,0xeb, + 0x5c,0xd3,0x34,0x30,0xfa,0x3a,0x89,0xb5,0xec,0x40,0xef,0x6d,0x4f,0xeb,0x0e,0x57, + 0x0a,0xe7,0xe2,0x9c,0xbb,0x60,0x54,0xfb,0x30,0x0d,0xf4,0xde,0x4e,0x62,0xad,0x89, + 0xb7,0xaf,0xba,0xaa,0x82,0x78,0x3c,0xce,0x55,0x17,0x6c,0xe0,0xab,0xff,0x73,0x17, + 0x86,0x61,0x08,0x02,0x27,0xd2,0xff,0x99,0xd4,0x18,0x9f,0xcf,0xe7,0x01,0xae,0x9d, + 0xca,0x6b,0x5e,0xbc,0x76,0x25,0x67,0xae,0x3e,0x8a,0x85,0xb5,0x7e,0x5c,0xae,0xc4, + 0x2d,0xbf,0x92,0xe2,0xc4,0x5d,0xbb,0x0a,0x57,0xf5,0x12,0x64,0x4f,0xae,0x25,0xdc, + 0xd2,0xd0,0x96,0x8e,0x8c,0xec,0xc9,0xc5,0x51,0x5a,0x83,0x9c,0x53,0x80,0xd1,0xdb, + 0x0e,0xa6,0x91,0x56,0x7d,0x7d,0xa4,0xf6,0x31,0xaa,0x7d,0xf9,0xe8,0xbd,0x6d,0xe3, + 0xb6,0x4f,0x92,0x24,0x0a,0x0a,0xf2,0xd1,0xa3,0x51,0x2a,0x8a,0xf2,0x79,0xe1,0xed, + 0x1d,0x53,0xe9,0x8e,0x79,0x77,0xb0,0xa7,0xe7,0xcd,0x8c,0x5c,0x86,0x08,0x0d,0x7c, + 0x84,0x01,0x21,0x37,0x87,0xf3,0x4e,0x3e,0x96,0x9a,0xea,0x4a,0xdc,0xee,0xc4,0x0d, + 0x99,0x92,0xc3,0x8d,0x67,0xe9,0x3a,0x1c,0x45,0xe5,0xe3,0x4f,0x81,0x8a,0x2b,0xf0, + 0x2c,0x59,0x8b,0xe4,0x48,0x1f,0x43,0xa9,0xe4,0x4c,0xa6,0x7d,0x95,0xe4,0x2c,0x59, + 0x97,0x50,0xfb,0x14,0x59,0xc6,0xef,0xaf,0xe1,0xf8,0x25,0x0b,0x38,0x69,0xd9,0xfc, + 0xa9,0x7c,0xe4,0x48,0xc6,0xda,0x11,0x32,0x70,0x0d,0x3c,0x65,0x2f,0xeb,0x63,0xe7, + 0xac,0xa5,0xba,0x62,0x0e,0x3e,0x5f,0x41,0x12,0xd2,0x2d,0xe3,0xa9,0x5b,0x83,0x9c, + 0x93,0xf8,0xf6,0x92,0xec,0x2d,0xc0,0xb3,0xe8,0xc4,0x61,0x9f,0xe8,0xd4,0x66,0xaf, + 0x8c,0x67,0xd1,0x89,0x49,0xb7,0xcf,0xbd,0x68,0xcd,0x81,0x29,0xf6,0x11,0xe0,0x71, + 0xbb,0xa9,0xa9,0xaa,0xe0,0xe2,0xf5,0xab,0x46,0xb9,0xa3,0x4e,0x12,0xfd,0x82,0xc0, + 0xe9,0x81,0x28,0xd0,0x3b,0x15,0x17,0xaa,0x2a,0x29,0x64,0xd5,0xd2,0x5a,0xaa,0x2a, + 0xcb,0x93,0x3a,0xcf,0x55,0xbd,0x0c,0x39,0xf7,0xf0,0x0e,0x61,0xa6,0x69,0x8c,0x19, + 0x10,0x20,0xe7,0xf9,0x70,0x55,0x2f,0x4f,0xf9,0x0e,0x76,0xcd,0x5b,0x81,0x9c,0x7b, + 0xa8,0x63,0x93,0x69,0x18,0x47,0x0c,0x74,0x50,0xf2,0x8a,0x70,0x56,0x25,0x56,0x77, + 0xac,0xa4,0xa4,0x88,0xa5,0x0b,0x6a,0x38,0xe3,0xd8,0x29,0xab,0x53,0xd6,0x9b,0xa9, + 0x04,0x76,0x64,0x20,0x81,0x83,0x40,0xd9,0x64,0x2f,0x74,0xe1,0xda,0x63,0xa9,0xa9, + 0x2a,0xc7,0xe1,0x48,0xbc,0x8b,0xe4,0x9c,0x02,0x9c,0x73,0xc7,0x9e,0xfa,0x75,0x06, + 0x76,0xb2,0xf3,0xb9,0x67,0xe8,0xde,0xd1,0x84,0x24,0xc9,0x14,0x2f,0x5e,0x4a,0xed, + 0x29,0xa7,0xe1,0xab,0xac,0x1a,0xfe,0x8e,0x73,0xae,0x9f,0x78,0xc7,0x6e,0x8c,0xc1, + 0xd4,0x94,0x37,0xd9,0xeb,0xc3,0x59,0xa6,0x8e,0xfa,0xac,0x7d,0xe7,0x76,0x76,0x3d, + 0xf7,0x34,0xc1,0x9d,0xdb,0x91,0x14,0x85,0xd2,0x25,0xcb,0xa9,0x3d,0xe5,0x34,0x0a, + 0xca,0x2b,0x0e,0x25,0x7f,0xf9,0x02,0xf4,0x8e,0xdd,0x18,0xe1,0xfe,0x71,0xd7,0xc3, + 0x15,0xe5,0x73,0x38,0xfd,0xf8,0xe5,0x3c,0xf5,0xc6,0xd6,0xa9,0x78,0xf4,0x9e,0x4c, + 0x25,0x70,0x46,0x19,0xb1,0x82,0x3d,0x3d,0xa6,0xcf,0xe7,0xbb,0x1c,0xa8,0x99,0xd4, + 0xa8,0xa6,0x28,0x5c,0x75,0xc1,0x69,0xd4,0x2d,0xf4,0x27,0xe1,0xe2,0x67,0xe2,0xf2, + 0x1f,0x8b,0x9c,0x93,0x77,0x88,0x66,0x7a,0xe7,0xe1,0xbf,0xf2,0xda,0x8d,0x3f,0xa3, + 0x67,0xc7,0x56,0xa2,0xdd,0x9d,0x44,0xba,0x3a,0x08,0x6e,0xdb,0x42,0xe0,0xa9,0xc7, + 0x51,0x0a,0x8b,0x29,0x99,0xbf,0x60,0x48,0x72,0x91,0x1c,0x6e,0xf4,0xee,0xe6,0x94, + 0xec,0x5f,0xb7,0xff,0x98,0xe1,0xf6,0x99,0x86,0xce,0x5b,0x0f,0xdc,0xcb,0xa6,0x9b, + 0x7f,0x49,0xef,0xce,0x6d,0xc3,0xed,0xea,0x6e,0x7a,0x97,0x5d,0xff,0x7c,0x1c,0x57, + 0xe9,0x1c,0x8a,0xe7,0xf9,0x0f,0x66,0x26,0x92,0xd3,0x8d,0xde,0xbd,0x8f,0xf1,0x02, + 0xe1,0x5c,0x2e,0x17,0x4e,0x09,0x5e,0x78,0xb3,0x91,0xde,0x50,0x78,0xb2,0x8f,0xfe, + 0xa3,0x60,0x4f,0x4f,0x46,0x6a,0xe1,0x4c,0xcc,0xc8,0xb1,0x7b,0xb2,0x17,0x58,0xbd, + 0x58,0x65,0xa1,0x5a,0x85,0x2c,0x27,0xde,0x3d,0x92,0x2b,0x17,0x87,0xef,0x50,0xc5, + 0xbf,0xe5,0xf1,0x47,0xd8,0x7a,0xe7,0x6d,0x63,0x4e,0x2f,0x4d,0x5d,0x67,0xf3,0xad, + 0xbf,0x61,0xc7,0x0b,0xcf,0x1e,0x18,0x3c,0x8a,0xe6,0x22,0x39,0x3d,0x29,0xd7,0xa9, + 0x92,0xcb,0x8b,0x52,0x78,0x20,0xd4,0xfa,0xed,0x87,0xfe,0xca,0xf6,0x7b,0xff,0x7c, + 0x98,0x76,0xc5,0x79,0xe3,0xb7,0xbf,0x22,0xf0,0xca,0x4b,0x87,0x0e,0x8e,0xbe,0xf2, + 0xe1,0xfd,0xe2,0xf1,0x50,0x56,0x56,0xc2,0xd9,0xab,0x27,0x9d,0x60,0xc5,0x10,0x6b, + 0xe0,0xf4,0xc2,0xae,0xc9,0x5e,0xe0,0xf8,0xc5,0x7e,0x7c,0xbe,0xe4,0x02,0x58,0x1c, + 0x25,0x55,0x87,0x18,0x69,0x3a,0x03,0x3b,0x69,0xfc,0xd3,0xad,0x54,0x6d,0x38,0x87, + 0xaa,0x0d,0x67,0x23,0x8d,0x35,0x20,0x48,0x12,0x6f,0xde,0x72,0x23,0xbd,0xad,0x2d, + 0xc3,0x46,0x22,0x47,0x49,0xea,0x25,0xd5,0x74,0x94,0x54,0x0f,0x1b,0xd9,0xda,0xb6, + 0x35,0xd1,0x74,0xd7,0x6d,0x98,0xa6,0x41,0xbe,0xbf,0x16,0x67,0x6e,0xde,0x98,0xe7, + 0x6c,0xfa,0xed,0xaf,0x19,0xe8,0xec,0x38,0x48,0xe2,0x64,0x1c,0xc5,0x55,0x09,0xdd, + 0xb3,0x20,0x3f,0x8f,0xc5,0xfe,0x2a,0xe2,0xfa,0xa4,0xb6,0xd8,0x7a,0xc8,0xd0,0x6c, + 0x1c,0x99,0x4a,0xe0,0x6d,0x93,0xbd,0xc0,0x22,0xb5,0x2a,0xa9,0x6d,0x23,0x30,0x51, + 0x0a,0xe7,0x1e,0xf2,0xe9,0xe6,0xbb,0xef,0x60,0xf5,0xb5,0xdf,0xe6,0xc4,0xfa,0xab, + 0x39,0xf1,0xaa,0xab,0x59,0xfd,0xe5,0x6f,0x1d,0x56,0x63,0xbd,0xfb,0xd0,0x03,0x07, + 0xd6,0x35,0x63,0x5c,0x6b,0xd6,0xd7,0x5a,0xbe,0x03,0xcf,0xb4,0xf9,0xae,0xff,0xc3, + 0x04,0x56,0x7f,0xf9,0xdb,0x9c,0xf5,0xbd,0x9f,0xf0,0x9e,0x5f,0xdc,0x8c,0x6f,0xc9, + 0xa1,0x55,0x5c,0x8d,0x68,0x84,0x2d,0x8f,0x3e,0x74,0x98,0x6b,0x8d,0x6f,0x61,0x96, + 0x24,0x89,0x25,0x0b,0xe6,0x11,0x8a,0x4f,0xca,0x95,0xb9,0x0b,0xb1,0x8d,0x94,0x56, + 0xd8,0x32,0x99,0x93,0xe3,0x86,0x81,0xbf,0xba,0x22,0xc9,0x5e,0x74,0x22,0x7b,0x47, + 0x6f,0xab,0x04,0xf7,0xed,0x25,0xd8,0xf4,0x0e,0x73,0xeb,0x16,0x0f,0x7f,0x56,0x5e, + 0xb7,0x18,0x87,0x37,0x77,0xcc,0x4b,0xec,0x7b,0xea,0x31,0x06,0x83,0xdd,0x96,0x80, + 0xe7,0xf9,0x52,0xab,0x47,0x25,0x09,0xc5,0xb6,0x3c,0x77,0x06,0x76,0x11,0x6c,0x7c, + 0x1b,0x87,0x27,0x87,0xea,0xa3,0x57,0x22,0xc9,0x32,0x2e,0xaf,0x97,0x79,0xeb,0x36, + 0x8c,0x79,0xaa,0xf6,0xe8,0x5f,0x89,0xf4,0xf5,0x8d,0xee,0x2e,0x6f,0x01,0xc8,0x89, + 0x19,0x07,0x8b,0x7d,0x05,0xac,0x5d,0xa2,0x4e,0xe6,0xe9,0x5b,0x02,0x9a,0xa6,0x0b, + 0x02,0xa7,0x0f,0x76,0x02,0x13,0xb6,0x7a,0xe8,0x86,0x49,0x59,0x51,0x72,0x04,0x92, + 0x5d,0x39,0x48,0xca,0x68,0x2f,0xad,0x96,0x2d,0xef,0xa0,0x87,0xc3,0x0c,0x74,0x75, + 0x0d,0x7f,0xd6,0xdf,0xd5,0x45,0x3c,0x3c,0x78,0x58,0x92,0xb4,0x34,0xda,0x63,0x8f, + 0xac,0x20,0x7b,0x52,0x27,0x4c,0x51,0xce,0x29,0x1c,0x5e,0x1e,0xec,0x7f,0x77,0x33, + 0x48,0x12,0xf1,0xc1,0x41,0x7a,0xdb,0x5a,0x0f,0x2c,0x17,0xb6,0x1f,0x3e,0x08,0xa1, + 0x75,0xdb,0x68,0x4b,0xb2,0xe4,0x70,0x25,0xbc,0xce,0xcf,0xcb,0xf5,0x52,0x9c,0xe7, + 0x9d,0x55,0x9b,0x48,0x2a,0x23,0xe3,0xe2,0xe1,0x02,0x9a,0xd6,0xe6,0x57,0xd5,0x56, + 0x60,0x42,0xc3,0x76,0x81,0xd7,0x93,0xe4,0xf4,0x19,0xa4,0x31,0x9c,0x1a,0xda,0x36, + 0xbf,0x01,0xc0,0x4b,0xbf,0xbe,0x81,0x25,0xef,0xfb,0x20,0x00,0x8d,0xf7,0xff,0xe5, + 0x88,0x7b,0xa5,0x9d,0xdb,0x9b,0x98,0x7f,0xe2,0xc9,0x07,0xae,0x19,0xee,0x4b,0x11, + 0x02,0x1f,0x68,0x5f,0xdb,0x1b,0xaf,0x5b,0xcf,0xa7,0x28,0x3c,0xf7,0xa3,0x7f,0x47, + 0x3d,0xeb,0x7c,0x7a,0xf7,0xee,0xa6,0xed,0x95,0xe7,0x0f,0xdf,0xae,0x9d,0x3b,0x98, + 0x77,0xdc,0xe8,0x74,0xdd,0xb2,0x27,0x0f,0x3d,0x32,0x30,0xfe,0xd4,0x5d,0x51,0x28, + 0x4e,0xc6,0x91,0x66,0xec,0x01,0x5d,0x10,0x38,0xcd,0xf0,0xaf,0xc9,0x10,0x38,0xd9, + 0x38,0xdf,0xa1,0x28,0xa3,0x91,0xe8,0xdb,0xbb,0x07,0x80,0xc1,0x96,0x7d,0x6c,0xba, + 0xe9,0x17,0x09,0x5d,0x27,0xb8,0xe3,0x80,0x16,0x4b,0x25,0x4b,0xf4,0x90,0x1b,0xa4, + 0xa9,0xeb,0x0c,0xb4,0x1e,0xd8,0xe2,0x8a,0xf5,0xf5,0xb0,0xfd,0xbe,0x3f,0x8f,0x6f, + 0x45,0xda,0xd1,0x94,0x50,0x9f,0x1d,0x6e,0x1d,0x5c,0x90,0x9f,0x37,0x99,0xc7,0xdf, + 0x9a,0xc9,0x04,0xce,0xd4,0xe2,0x66,0x2f,0x4e,0xf4,0xc4,0xde,0x81,0x70,0xd2,0xb1, + 0xbe,0x92,0x3c,0xfa,0xfb,0x7a,0x24,0x82,0x3e,0x38,0x90,0xf4,0xbd,0x23,0xfd,0x7d, + 0x23,0xae,0x99,0x42,0xaf,0xc6,0x5e,0xaf,0xc6,0x23,0x61,0x8c,0xc1,0xe4,0xdd,0xcd, + 0xc3,0x3d,0xc1,0x31,0xfa,0xcc,0x91,0x30,0x81,0xcd,0xc9,0x85,0x5e,0xbe,0x2b,0x08, + 0x9c,0x7e,0x78,0x7a,0xa2,0x27,0xf6,0x84,0xc2,0x30,0x49,0x1f,0x5c,0xd3,0x34,0x27, + 0x16,0x5d,0x64,0xa4,0x6a,0x8c,0xb0,0x39,0xdc,0x2e,0x73,0x02,0x7d,0x63,0x4e,0x32, + 0x34,0x30,0x36,0x71,0x2b,0x74,0x08,0xd8,0x21,0x08,0x9c,0x7e,0xeb,0xe0,0x37,0x81, + 0x8e,0x89,0x0a,0x6b,0x28,0x92,0xdc,0xb6,0xa1,0xa9,0x8f,0x0e,0x37,0x55,0x5c,0x2e, + 0x24,0x77,0xf2,0x53,0x60,0x47,0x4e,0xce,0x08,0xa1,0x4f,0x21,0xc3,0xa9,0xfd,0x2c, + 0x8a,0xd3,0x85,0xec,0x72,0x27,0x7d,0xba,0x2b,0x37,0x77,0x0c,0x52,0x27,0x16,0xa2, + 0x6b,0x9a,0x26,0xe1,0xc8,0x84,0xb7,0x71,0xf7,0x04,0x34,0x2d,0x28,0x08,0x9c,0x9e, + 0x78,0x64,0x22,0x27,0x39,0x15,0x99,0xbe,0x81,0xe4,0xa6,0x89,0x66,0x74,0xf0,0xa0, + 0xe9,0xa1,0x8c,0xb7,0x24,0xf9,0x02,0x11,0xf9,0x55,0x07,0x3c,0x40,0xcd,0x58,0xea, + 0x6c,0x5d,0x0e,0x3d,0x8b,0xe2,0x72,0xe1,0x2e,0x2a,0x49,0xbe,0x5d,0x35,0xfe,0x43, + 0xaf,0x19,0x49,0xac,0x8f,0x75,0xc3,0xa0,0xa5,0x73,0xc2,0x1c,0x7c,0x91,0x0c,0x47, + 0x26,0x13,0xf8,0x81,0x09,0x75,0x88,0x24,0x33,0x30,0x98,0x1c,0x79,0xcc,0x31,0xac, + 0xc5,0xa5,0x2b,0x92,0x2f,0x8a,0x57,0x52,0xb7,0xf4,0xc0,0x35,0x53,0x28,0xa0,0x61, + 0x64,0x70,0xc5,0x44,0xda,0x55,0xbc,0x60,0xe1,0xa1,0xd7,0x0c,0x27,0xe6,0xdd,0xa8, + 0xeb,0x06,0x3b,0xf6,0x4d,0x38,0x77,0xf4,0x73,0x99,0x4e,0xe0,0x59,0xb7,0x42,0xfb, + 0x55,0x55,0xb1,0x9f,0x43,0xb1,0x07,0x14,0x05,0x2b,0x0d,0x68,0x0e,0x56,0x51,0x2a, + 0x97,0x7d,0x38,0xed,0xff,0x1f,0xfc,0xcc,0x06,0x56,0xd6,0xc1,0x18,0x96,0xc7,0x4d, + 0x04,0x6b,0x1f,0x78,0xb3,0xbd,0x06,0x4a,0x6a,0x13,0x51,0x92,0xa0,0x33,0xd8,0xcb, + 0xfc,0xaa,0xc4,0xbd,0xa1,0x8c,0xe8,0x20,0x66,0x3c,0x86,0xe4,0x38,0xb0,0x17,0x3c, + 0x77,0xe9,0x32,0xb6,0x27,0xb7,0x70,0x66,0x8e,0xed,0xf4,0x61,0x1a,0xf1,0x84,0x05, + 0x7c,0x46,0x08,0x1c,0xee,0x03,0xc3,0x00,0x59,0xa6,0x7c,0xf9,0x51,0x04,0x1e,0xbe, + 0x6f,0x42,0xed,0x1a,0xa9,0xd1,0xcd,0x78,0x62,0x83,0xa4,0x6e,0x18,0xbc,0xb2,0x63, + 0x3f,0xfe,0xe2,0xdc,0x89,0x3c,0xfa,0x6b,0x7e,0x55,0x2d,0xb1,0x65,0x29,0x07,0x2b, + 0x6f,0xb8,0xdb,0x96,0xa1,0x21,0x99,0x3b,0x64,0xc9,0x6d,0x1f,0xf1,0x11,0xb2,0x14, + 0x06,0x06,0x6d,0x39,0x1b,0x3a,0xe2,0x80,0x1e,0xd0,0x34,0x33,0xe3,0x08,0xec,0x57, + 0x55,0x07,0x50,0x6c,0x1f,0xe5,0x07,0x1d,0x65,0x58,0x05,0xc8,0x4a,0x46,0x90,0x52, + 0x1a,0x71,0x30,0xa2,0xc3,0x06,0xed,0x4e,0x8c,0x8e,0xe8,0xd4,0x83,0x2d,0x22,0x92, + 0x7d,0x1d,0x87,0x4d,0x74,0xcf,0x88,0xa3,0x2b,0x59,0x02,0x03,0x34,0xb7,0x77,0x02, + 0x8b,0x92,0x90,0xf0,0x38,0xc6,0x60,0x2f,0x4a,0xfe,0x81,0xe9,0xe5,0x9c,0x85,0x75, + 0x78,0x4a,0xe7,0x12,0xee,0x68,0x4d,0xe8,0x12,0x05,0x8b,0x96,0x52,0x54,0x6d,0x4d, + 0xa1,0x8d,0xfe,0x14,0x5b,0xb6,0x99,0x26,0xfa,0x40,0x10,0x25,0xbf,0x98,0xf2,0xc5, + 0x4b,0x71,0x16,0xf8,0x88,0xf5,0x26,0xf6,0x8c,0xc5,0x47,0x1d,0x7b,0x48,0x68,0xa1, + 0x11,0xea,0x05,0x23,0x4e,0x22,0xa5,0xb9,0x3a,0xba,0x7b,0x29,0xf4,0x4c,0x28,0x68, + 0xae,0x0f,0xb8,0xdd,0x96,0x9b,0x41,0x7b,0x30,0x0f,0xdb,0xb2,0x14,0x1d,0x41,0xc4, + 0x43,0x56,0x51,0xb6,0x2c,0x39,0x0f,0x92,0x25,0xaf,0x4d,0x78,0xd3,0x3e,0x0c,0xc0, + 0xf4,0xab,0xaa,0x81,0x15,0xc2,0xda,0x01,0xb4,0x03,0x2d,0x40,0xab,0xfd,0x73,0xbf, + 0xfd,0x79,0x57,0x40,0xd3,0x06,0x52,0x8a,0xc0,0x76,0xcd,0xd5,0x85,0x40,0x9d,0xfd, + 0x73,0x3e,0x56,0x69,0xcf,0x5a,0xbb,0x81,0x9d,0x36,0x81,0x5a,0x46,0x1c,0xaf,0xda, + 0x8d,0xec,0xb0,0xff,0x17,0x1e,0x39,0xe2,0x4d,0xb5,0xcb,0x9b,0x5f,0x55,0x37,0x00, + 0x4f,0x25,0x7b,0xde,0xa6,0xc6,0x9d,0x5c,0x7c,0xda,0x49,0x49,0x64,0x84,0x90,0x88, + 0x77,0xb7,0x8e,0x22,0xb0,0xec,0x70,0xb0,0xfc,0xf2,0x8f,0xf2,0xda,0x7f,0xdf,0x30, + 0x6e,0xa6,0x0d,0xd3,0xd0,0x59,0x71,0xe9,0x87,0x0f,0x54,0x29,0x0c,0xb6,0xa4,0xdc, + 0x54,0x4d,0x0f,0xb6,0xa2,0xe4,0x17,0xa3,0xb8,0x5c,0x2c,0xbb,0xfc,0x63,0xbc,0xf9, + 0xdb,0x5f,0x8d,0xdf,0x2e,0x5d,0x67,0xf9,0xfb,0x3f,0x78,0xc8,0xe7,0x56,0xfb,0x12, + 0x0b,0xd3,0xec,0xec,0xe9,0xa5,0x30,0xc7,0x3d,0x91,0x47,0xfe,0x4d,0x40,0xd3,0xbe, + 0x39,0x0d,0xca,0x49,0x3a,0x88,0xe4,0x2e,0xa0,0x00,0xab,0xfe,0x52,0x99,0xad,0xa4, + 0x2a,0x80,0x95,0x40,0x95,0xad,0xa8,0x8a,0xfd,0xaa,0x5a,0x08,0xec,0xc3,0xb2,0x8a, + 0xef,0x04,0xb6,0xdb,0xc7,0xb6,0x80,0xa6,0x75,0x4c,0x0b,0x81,0x17,0xd6,0xd6,0x4a, + 0xf1,0x78,0xdc,0x03,0x54,0x03,0xc7,0x03,0x47,0x03,0xcb,0x6c,0xc2,0xe6,0x62,0x6d, + 0x92,0x6f,0xc5,0x0a,0x20,0x78,0x18,0x2b,0x12,0x28,0x10,0xd0,0xb4,0xc1,0x54,0x10, + 0xba,0x80,0xa6,0x3d,0xed,0x57,0xd5,0x46,0x20,0xa9,0xd4,0x0e,0xaf,0xbe,0xbb,0x9d, + 0x70,0x34,0x86,0x2b,0x09,0x87,0x0e,0xbd,0x6b,0x2f,0x54,0x2f,0x81,0x11,0xfb,0xb7, + 0xea,0xea,0x35,0xec,0x5e,0xbd,0x96,0xf6,0x57,0x8f,0x6c,0x4b,0x99,0x77,0xd6,0x05, + 0x94,0x2f,0xb5,0xb3,0x71,0x18,0x3a,0x7a,0xd7,0xbe,0x94,0x23,0x70,0xbc,0x73,0x0f, + 0xae,0xea,0xc5,0x20,0xc9,0x2c,0x38,0x79,0x1d,0x7b,0x5f,0x7e,0x81,0xce,0xb7,0x5e, + 0x3b,0xe2,0x39,0xf3,0xdf,0xfb,0x01,0xe6,0x2c,0xac,0x3b,0x68,0xb6,0xa2,0xa3,0x77, + 0x25,0x1e,0xef,0xbc,0x6b,0x6f,0xcb,0x44,0x93,0xdb,0xdd,0x33,0x4d,0x32,0x65,0x8e, + 0xd0,0xe2,0x43,0x68,0x67,0x9c,0xed,0x2a,0xbb,0x76,0x75,0xa5,0xad,0xe8,0xe6,0xdb, + 0x8a,0xef,0x7c,0x60,0x89,0x5f,0x55,0x8b,0xec,0xf3,0x9b,0x80,0xb7,0x81,0xd7,0xb0, + 0xf6,0xaf,0xfb,0xc7,0x53,0x6a,0x47,0x94,0xd0,0x78,0x3c,0x7e,0x39,0xf0,0x2d,0xfb, + 0x01,0x5f,0x01,0xde,0x04,0xfe,0x02,0xec,0x0c,0x68,0x5a,0xba,0x04,0x48,0xff,0x12, + 0xb8,0x39,0x99,0x13,0x1a,0xf7,0xb4,0xb2,0xaf,0xad,0x33,0xa9,0x75,0xb0,0x19,0x1b, + 0x24,0x1e,0x6c,0xc1,0x51,0x5c,0x79,0x40,0x2f,0xcb,0x0a,0x6b,0xae,0xba,0x9a,0xe7, + 0x07,0xfa,0x09,0x6e,0x79,0x6b,0xec,0xf5,0xe1,0x09,0xeb,0x38,0xee,0x43,0x1f,0x19, + 0x4e,0x1c,0x10,0xef,0x6e,0x49,0x29,0x0b,0xf4,0x81,0xf6,0x85,0x89,0x77,0xb7,0xe2, + 0x28,0xae,0x40,0x56,0x1c,0x9c,0x78,0xf5,0xe7,0x79,0xee,0x17,0x3f,0xa1,0x77,0xfb, + 0x96,0x31,0xdb,0x55,0xbe,0xf6,0x34,0x56,0x5e,0x72,0xf9,0x21,0x5a,0x3a,0xde,0xb5, + 0x3f,0xe1,0xf5,0x2f,0xc0,0xdb,0xdb,0xb5,0x89,0x3c,0xee,0x56,0x5b,0x56,0x53,0x06, + 0x01,0x4d,0x33,0x80,0xbd,0xf6,0xf1,0xdc,0x18,0xe4,0x9e,0x6f,0xaf,0xdb,0x56,0x00, + 0x5f,0x02,0x96,0xda,0x0a,0xf1,0xa2,0x23,0xcf,0xfd,0xc6,0x9f,0x26,0x9b,0x01,0x4d, + 0x8b,0x91,0x66,0xf0,0xab,0xaa,0xd7,0x9e,0x25,0x14,0x01,0x1b,0xed,0x69,0x4e,0xc2, + 0xf8,0xe1,0xbf,0x7d,0x88,0x8b,0x4e,0x3f,0x29,0xa9,0x7b,0x4a,0xee,0x3c,0xbc,0x47, + 0x6d,0x38,0x24,0x2e,0x38,0x1e,0x8d,0xd0,0xf4,0x8f,0x27,0xd8,0x76,0xdf,0x1d,0xc4, + 0x42,0x03,0x80,0x89,0xdb,0x57,0xcc,0xe2,0x4b,0xae,0x60,0xe1,0xfa,0x0d,0xc8,0x43, + 0x69,0x7b,0x0c,0x83,0xd0,0xdb,0x4f,0x61,0x46,0x06,0x52,0xb2,0x4f,0x65,0x4f,0x3e, + 0x39,0x2b,0x4e,0x1d,0x6e,0x5f,0x3c,0x1c,0xa6,0xf1,0xc9,0xc7,0xd8,0x7e,0xff,0x9d, + 0x76,0x90,0x86,0x89,0xa7,0x78,0x0e,0x4b,0x2e,0xbd,0x82,0x05,0x6b,0xd7,0x23,0x1f, + 0xec,0xd1,0x66,0x18,0x84,0x36,0xff,0x33,0xe1,0xc4,0xef,0xd1,0x58,0x9c,0x13,0x3e, + 0xfa,0x35,0xe2,0x7a,0xd2,0x2b,0xab,0xdf,0x02,0x37,0xd8,0xeb,0xde,0x10,0x10,0x4a, + 0x57,0x19,0x0e,0x68,0x5a,0x68,0xc2,0x04,0x9e,0xe5,0x87,0x97,0x46,0xac,0x33,0x8a, + 0xec,0x75,0x45,0xe5,0x08,0x43,0x58,0xa9,0x7d,0x14,0x8e,0x38,0xf2,0x6d,0x63,0x43, + 0x1c,0x18,0x18,0x71,0x38,0x81,0x13,0x93,0xb9,0xff,0x9a,0xe5,0xb5,0xfc,0xee,0x3b, + 0x9f,0x4f,0x3a,0x91,0xbb,0xb3,0x6a,0x29,0xae,0xca,0x45,0x87,0xb1,0x75,0xc5,0x19, + 0xe8,0x6c,0x07,0x49,0x26,0xaf,0xb4,0xec,0x10,0x77,0xc9,0x68,0xf3,0x36,0x62,0xfb, + 0xb6,0x4c,0x49,0xff,0x85,0x07,0x42,0x44,0x07,0xc3,0xe4,0x15,0x15,0x1e,0x4a,0xa4, + 0x49,0xc0,0x55,0xbd,0x1c,0x67,0x45,0xed,0xa1,0xed,0xea,0x68,0x47,0x92,0x65,0x72, + 0xc7,0x68,0xd7,0x70,0xfb,0xf6,0x6d,0x25,0xd6,0x9c,0xb8,0x6b,0xf2,0x96,0x5d,0x7b, + 0xb8,0xe4,0xba,0x1b,0x92,0x15,0xd2,0x28,0xf0,0xb8,0x3d,0x78,0x7b,0xed,0x63,0xe8, + 0xf7,0x18,0x56,0x76,0x8e,0x1e,0xac,0x44,0x77,0x3d,0xb6,0xad,0x66,0xc8,0x00,0x35, + 0x64,0x7c,0x6a,0xb6,0x7f,0x8f,0x4c,0x87,0x6d,0x26,0x25,0x8c,0x58,0x53,0x44,0x52, + 0x07,0x96,0x45,0xba,0x7c,0x84,0x01,0xcc,0x6f,0x4f,0x27,0x7c,0x1c,0xd8,0x42,0x0a, + 0xda,0x53,0x8f,0xfd,0x23,0x8e,0xcd,0x76,0xc7,0x0f,0xbd,0x8c,0x3e,0x7b,0xcd,0x10, + 0x1f,0xe3,0x3e,0x4e,0xe0,0xad,0x64,0xd6,0xc2,0x4f,0xbd,0xde,0xc8,0xf6,0x3d,0xcd, + 0x2c,0xf6,0x27,0x97,0x1d,0x23,0xd6,0xdc,0x88,0x92,0x57,0x8c,0x52,0x70,0xa8,0xc3, + 0x83,0xec,0x70,0x90,0x3f,0x77,0xec,0x58,0x63,0xbd,0xb7,0x83,0xd8,0xbe,0xc6,0x29, + 0xe9,0xd7,0xed,0xaf,0xbd,0xcd,0xb6,0xe7,0x36,0x02,0x26,0xde,0x12,0x1f,0xab,0x2e, + 0x3a,0x9b,0xdc,0x82,0xbc,0x29,0xb9,0x76,0x74,0xdf,0xbb,0xc8,0x79,0x45,0x56,0x25, + 0x86,0x91,0xed,0x2a,0x3f,0x72,0x0c,0xb5,0xde,0xd3,0x4e,0x6c,0x7f,0xe2,0x75,0x8f, + 0x24,0x09,0x36,0xbe,0xdd,0x34,0x11,0x0d,0xf3,0xc7,0x80,0xa6,0x5d,0x75,0x04,0x99, + 0xcb,0xb5,0x07,0xfa,0x7c,0x7b,0xd0,0x2f,0xb6,0x0d,0x4d,0x65,0xb6,0x8d,0xe7,0x1c, + 0xdb,0xe6,0x53,0x8e,0x65,0x8c,0x8d,0xf9,0x55,0x35,0x04,0xec,0x01,0x02,0x23,0x8c, + 0x50,0xbb,0x81,0xf6,0x80,0xa6,0xcd,0x6a,0xc8,0x98,0x34,0x43,0x44,0x75,0xda,0x8b, + 0xf6,0xa5,0xb6,0x11,0x6c,0xe8,0xa7,0x87,0x03,0xa6,0xf7,0x1d,0xf6,0xb1,0x0b,0xd0, + 0xec,0x91,0x71,0x20,0xa0,0x69,0xe1,0x29,0x7a,0x86,0x73,0x6d,0x43,0x5b,0xc2,0x6d, + 0xfe,0xf0,0x39,0x6b,0xf9,0x76,0xfd,0x07,0x93,0x76,0xa5,0x97,0x14,0x27,0x9e,0xc5, + 0x27,0x1d,0x31,0xbd,0xec,0x28,0xe1,0xee,0xef,0x26,0xdc,0xf4,0x32,0xe8,0x93,0x9f, + 0xe5,0xf5,0x75,0xf7,0xf0,0xc2,0xed,0xf7,0x8f,0x6a,0x65,0xf9,0xb2,0x85,0xac,0x3c, + 0x73,0xdd,0xd4,0x09,0x8d,0xe2,0xc4,0xb3,0xf8,0xe4,0x31,0xd3,0xcb,0x1e,0xae,0x7d, + 0x91,0xa6,0x97,0x0e,0x71,0x39,0x3d,0x12,0x22,0xd1,0x18,0x97,0x7c,0xf5,0x3f,0xd9, + 0xb5,0x3f,0x29,0x03,0xad,0x0e,0xd4,0x05,0x34,0x6d,0xe7,0x14,0xc9,0x8c,0xc3,0xd6, + 0xde,0xf9,0x36,0xa9,0xfd,0x23,0x14,0x4d,0x8d,0x4d,0xfa,0x3c,0x2c,0x6b,0xf2,0xbb, + 0xf6,0xd1,0x08,0x6c,0x09,0x68,0x5a,0x67,0xda,0x11,0xd8,0x76,0xca,0xc8,0x07,0x8e, + 0xc3,0xb2,0x5a,0x1f,0x03,0x2c,0xb7,0x47,0xb9,0x77,0x0f,0x3a,0x1a,0x81,0xe0,0x4c, + 0x6e,0x84,0xfb,0x55,0xf5,0x2e,0xe0,0xb2,0x44,0xbf,0x6f,0x98,0x26,0x7f,0xfb,0xaf, + 0x6f,0x51,0x5b,0x53,0x91,0xfc,0xcd,0x64,0x19,0xb7,0xba,0x12,0x47,0x69,0xd5,0x11, + 0xba,0xd9,0x24,0xde,0xb1,0x97,0x88,0xf6,0xa6,0xe5,0x28,0x31,0x05,0x68,0xdb,0xd3, + 0xcc,0xeb,0xf7,0x3f,0x3e,0xea,0xb3,0xfc,0x8a,0x32,0xd6,0x5e,0x72,0xde,0xd4,0x26, + 0x8e,0x97,0x15,0xdc,0xfe,0x63,0xac,0x5c,0x60,0x87,0x6b,0x9f,0x69,0x12,0xeb,0xd8, + 0x43,0x54,0x7b,0x2b,0xe9,0xe0,0x8e,0x8d,0x6f,0x37,0xf1,0xb1,0xef,0xfe,0x1a,0x25, + 0xb9,0xa8,0xac,0x9b,0x02,0x9a,0x76,0xcd,0x0c,0x2f,0xf3,0x9c,0xc0,0x02,0x5b,0x21, + 0x0d,0x29,0xa7,0x15,0x36,0x0f,0xb6,0xd8,0x33,0xc5,0x4d,0x58,0x21,0xae,0xcd,0x01, + 0x4d,0x8b,0xa6,0x0c,0x81,0xfd,0xaa,0x5a,0x60,0x3f,0xf0,0x5a,0x60,0x9d,0x3d,0x42, + 0x39,0xb0,0xcc,0xe0,0xaf,0xda,0xd3,0xd6,0xc6,0x80,0xa6,0xa5,0x44,0x05,0x2f,0xdb, + 0x2b,0xe7,0x6d,0x7b,0x7a,0x94,0x10,0x2e,0x5c,0x7f,0x1c,0x3f,0xf8,0xdc,0xc7,0x92, + 0xca,0x50,0x39,0x4a,0xce,0xf3,0x8a,0x87,0x8b,0x7f,0x0d,0x65,0xed,0x30,0xe3,0x31, + 0xf4,0xfe,0x2e,0x62,0x2d,0x3b,0x31,0x06,0x3a,0xa7,0x74,0x1c,0x8d,0x84,0xc2,0x3c, + 0xf3,0xfb,0xbb,0x31,0x46,0x18,0x7e,0xfc,0x6b,0x56,0xb2,0x64,0xcd,0xca,0x69,0xe8, + 0x51,0x13,0x39,0xaf,0x64,0xec,0xf6,0xf5,0x75,0x11,0x6b,0xdd,0x81,0x31,0xd0,0x9d, + 0xf4,0x55,0x0d,0xc3,0xe0,0xda,0x1b,0x6e,0xe1,0xc9,0x57,0xdf,0x49,0xe6,0xb4,0x6e, + 0x60,0x49,0x40,0xd3,0xda,0x52,0x44,0xd6,0x5c,0xf6,0xac,0x73,0x85,0xad,0xd0,0x4e, + 0xb4,0x6d,0x39,0x1d,0x58,0x3b,0x3a,0xcf,0x03,0x9b,0x02,0x9a,0xb6,0x77,0xc6,0x08, + 0x6c,0x13,0xf6,0x64,0xe0,0x54,0xe0,0x2c,0x7b,0xf4,0x69,0x02,0x5e,0xb0,0x1f,0x68, + 0x7b,0xaa,0x47,0x7f,0xf8,0x55,0xf5,0x4c,0xe0,0x51,0x12,0xcc,0x89,0xad,0x1b,0x26, + 0x37,0x7d,0xe3,0x53,0x6c,0x58,0x7d,0xf4,0x24,0x87,0x4a,0xe9,0x80,0x80,0xeb,0xb1, + 0x49,0x87,0x2c,0x1e,0x09,0x9d,0xfb,0x5a,0xd9,0xf2,0xec,0x2b,0x84,0x7b,0x7a,0x29, + 0x5f,0xbe,0x88,0x25,0x27,0x1e,0x87,0x63,0x5a,0x8b,0x91,0xdb,0xe5,0x45,0xa7,0xa8, + 0x7d,0xaf,0x6f,0xd9,0xce,0x07,0xbf,0xf9,0x5f,0xb8,0x9d,0x49,0x19,0xdf,0x3e,0x13, + 0xd0,0xb4,0xdf,0xa5,0xb8,0xec,0xb9,0xb1,0x0c,0xb1,0x6b,0x6c,0x85,0xb7,0xd2,0x9e, + 0x86,0xbf,0x8c,0x15,0x02,0xfb,0x5c,0x40,0xd3,0xb6,0x4f,0x19,0x81,0xe7,0xfb,0xfd, + 0xb2,0x69,0x9a,0xab,0x81,0xf7,0xd8,0x84,0x9d,0x0b,0x3c,0x6b,0xdf,0xec,0x9f,0xc0, + 0x7e,0x7b,0x7f,0x2b,0xad,0xe0,0x57,0xd5,0xeb,0x81,0xef,0x27,0xfa,0xfd,0xc2,0xdc, + 0x1c,0xee,0xbe,0xe1,0x3a,0x2a,0xcb,0x4a,0xd2,0xaa,0x9d,0xa6,0x69,0x26,0x91,0x98, + 0x3e,0x35,0x10,0x8e,0x46,0xf9,0xe4,0xbf,0xff,0x8a,0xb7,0x76,0xec,0x49,0xe6,0xb4, + 0xc7,0x81,0xf7,0xcc,0xb6,0x5f,0xf2,0x04,0xa7,0xe0,0x39,0xc0,0x49,0xc0,0x06,0xfb, + 0xa8,0xc0,0xf2,0x1e,0x7c,0x0c,0x78,0x7c,0x3c,0x7f,0x8b,0xf1,0xf6,0x81,0x0b,0xb0, + 0x9c,0x20,0x9e,0x06,0xfe,0x99,0xec,0xe8,0x90,0xe2,0x1d,0xf7,0x47,0xe0,0xc3,0x89, + 0x9e,0xb3,0x66,0xd9,0x02,0x7e,0xf9,0xf5,0xcf,0x90,0xef,0xcd,0x41,0x60,0xfa,0xf0, + 0xc7,0x87,0xfe,0xc9,0x8f,0xff,0x90,0x54,0x20,0x59,0x0b,0xb0,0x32,0xa0,0x69,0xad, + 0x19,0x22,0x9b,0xf9,0xc0,0x7a,0x2c,0x6b,0xf8,0x73,0x01,0x4d,0xbb,0x67,0xc6,0x8c, + 0x58,0x69,0xd6,0x51,0x2e,0xe0,0x6f,0xc0,0xd9,0x89,0xaf,0x87,0x8f,0xe7,0x3b,0x9f, + 0xbe,0x9c,0x1c,0x8f,0x3b,0xa5,0xda,0x12,0x8f,0xc5,0x90,0x24,0x09,0x25,0x81,0x3a, + 0x4e,0x91,0xd0,0x20,0xee,0x14,0x1d,0x84,0x5e,0xdf,0xb2,0x83,0x8f,0x7f,0xf7,0xd7, + 0xc9,0x64,0xfd,0x88,0x00,0x67,0x04,0x34,0xed,0x85,0x6c,0x95,0x63,0x25,0x5b,0x1b, + 0x1e,0xec,0xe9,0xd1,0x7d,0x3e,0xdf,0x7d,0xf6,0x9a,0x3e,0xa1,0x62,0xb4,0x5b,0x77, + 0xef,0xa7,0xbd,0xab,0x9b,0x35,0x47,0x2d,0x4e,0xca,0x4f,0x7a,0x3a,0x21,0x49,0x12, + 0xff,0xba,0xff,0x31,0x5a,0x76,0xec,0xa6,0x6a,0x49,0xed,0x11,0xbf,0xdb,0xb1,0xaf, + 0x85,0x17,0xff,0xf8,0x00,0x25,0xf3,0x6b,0xc8,0x99,0x5c,0xaa,0xd6,0x29,0x87,0xb6, + 0xbf,0x8d,0xab,0x7f,0xf0,0x3f,0xc9,0x64,0x43,0xd1,0x81,0x2b,0x03,0x9a,0xf6,0x70, + 0x36,0xcf,0x58,0xe4,0x6c,0x6e,0xbc,0xed,0xa6,0x76,0x3e,0xf0,0x50,0xa2,0xe7,0x3c, + 0xf0,0xcc,0xab,0x7c,0xe5,0x67,0x0d,0xb4,0x76,0xa6,0x86,0xad,0xce,0xc4,0xa4,0x70, + 0x6e,0x19,0x5d,0xda,0x3e,0xda,0xf6,0x1c,0x3e,0x48,0xc0,0xd0,0x75,0x9a,0x5e,0x7c, + 0x1d,0xd9,0xe1,0xc0,0x9b,0x9f,0x9b,0x52,0xef,0x61,0x4f,0x4b,0x3b,0x9f,0xfd,0xd1, + 0x4d,0x74,0xf6,0x26,0xec,0x42,0x6a,0x00,0x5f,0x08,0x68,0xda,0x9f,0xb2,0x7d,0xc9, + 0xa1,0x64,0x7b,0x07,0x04,0x7b,0x7a,0xe2,0x3e,0x9f,0xef,0x6e,0x2c,0xb7,0xcc,0xd5, + 0x89,0x9c,0xb3,0xbb,0xb5,0x93,0x27,0x5f,0xde,0xc4,0x62,0x7f,0x25,0x55,0x73,0x4a, + 0x67,0xbd,0x0d,0x05,0xa5,0x45,0xec,0xdb,0xb2,0x83,0xd6,0xa6,0x5d,0x14,0x54,0x94, + 0x91,0x5b,0x38,0x3a,0x4f,0x75,0x3c,0x1a,0xe3,0xad,0xa7,0x5e,0xa2,0x6b,0xd7,0x1e, + 0x16,0xae,0x5f,0x4d,0x59,0x4d,0x65,0xca,0xf4,0xff,0x96,0x9d,0xbb,0xf9,0xec,0x7f, + 0xfe,0x96,0xdd,0x6d,0x5d,0xc9,0x68,0xde,0x94,0xb7,0x38,0x0b,0x02,0xcf,0x2c,0x89, + 0x0d,0x9f,0xcf,0xf7,0x88,0x6d,0x10,0x39,0x3b,0x91,0x7e,0xe9,0x0b,0x85,0x79,0xf0, + 0x99,0x8d,0x44,0x22,0x61,0x96,0xcc,0xaf,0x21,0x27,0xc9,0x64,0xf0,0x53,0x09,0x87, + 0xd3,0x49,0x71,0x4d,0x05,0xcd,0x5b,0x77,0xb2,0xf7,0xed,0x26,0x82,0xed,0x9d,0xc4, + 0x62,0x71,0x06,0x7a,0xfa,0x68,0xde,0x1e,0x60,0xf3,0xe3,0xcf,0xd1,0xdb,0xd2,0x4e, + 0xf5,0xca,0x65,0x2c,0x3e,0x61,0x65,0x4a,0x58,0xa6,0x0d,0xc3,0xe4,0x91,0x17,0x5e, + 0xe5,0xdf,0x7e,0xf4,0x3b,0x7a,0x06,0x12,0x8e,0x3e,0xed,0x07,0x2e,0x0d,0x68,0xda, + 0x5d,0x42,0x6a,0xed,0x25,0x94,0xe8,0x82,0xd1,0xf0,0xab,0xea,0xf1,0xc0,0x9f,0x80, + 0xc5,0x89,0x9e,0x93,0xef,0xf5,0xf0,0xad,0x4f,0x7e,0x80,0xd3,0x4f,0x38,0x86,0xbc, + 0x1c,0x0f,0xb3,0xb5,0x97,0x31,0xd8,0x3f,0x40,0xd3,0x2b,0x6f,0xd2,0xda,0xb8,0x13, + 0x3d,0x1a,0xb5,0x5f,0xaf,0x49,0xde,0x9c,0x52,0x6a,0xd7,0x1c,0x43,0x65,0xad,0x9a, + 0x12,0x7d,0xbc,0xaf,0xad,0x93,0x9b,0xee,0x7a,0x98,0xfb,0x9f,0xd9,0x98,0xcc,0x60, + 0xd2,0x08,0x5c,0x12,0xd0,0xb4,0x77,0x84,0x94,0x0a,0x02,0x8f,0x47,0xe2,0x5c,0xe0, + 0x07,0xc0,0x17,0x12,0xb5,0x13,0x98,0xa6,0x89,0x5a,0x5e,0x42,0xfd,0xfb,0xce,0xe2, + 0x94,0xe3,0x8f,0xa2,0xac,0xa8,0x70,0x42,0x39,0x94,0x27,0xff,0x46,0x25,0xa2,0x83, + 0x61,0x06,0xfb,0xfa,0xd1,0xe3,0x3a,0x9e,0x5c,0x2f,0x39,0x79,0xb9,0x48,0xf2,0xec, + 0xbe,0x6a,0x49,0x92,0x68,0xef,0xee,0xe1,0xe1,0x67,0x5e,0xe1,0x57,0x77,0x3e,0x4c, + 0x34,0xb9,0x5c,0xcf,0xbf,0x03,0xbe,0x12,0xd0,0xb4,0x7e,0x21,0x9d,0x82,0xc0,0xc9, + 0x6a,0xe3,0xff,0x01,0x4e,0x48,0xe6,0x3c,0x8f,0xcb,0xc9,0xa5,0x67,0x9c,0xc8,0xd9, + 0x27,0x1f,0xc7,0xb2,0x05,0xf3,0x70,0xbb,0x9c,0x59,0xdb,0x87,0xa6,0x69,0x12,0x68, + 0x6e,0xe5,0xb1,0x17,0x5e,0xe7,0xf7,0x7f,0xfb,0x27,0x03,0xe1,0xa4,0x5c,0x81,0x77, + 0x02,0x57,0x07,0x34,0xed,0x09,0x21,0x8d,0x82,0xc0,0x13,0x25,0xb1,0x84,0xe5,0xf0, + 0xf1,0x3d,0xac,0x28,0x94,0xa4,0x84,0xd7,0xeb,0x71,0xf3,0x89,0xf7,0x9e,0xca,0xaa, + 0xe5,0x75,0x2c,0x9a,0x57,0x49,0x61,0x7e,0x2e,0x0e,0x45,0x99,0x1d,0xed,0x3c,0x43, + 0x9a,0x36,0x1a,0x8b,0xd1,0xd2,0x11,0xe4,0xad,0xa6,0x9d,0x3c,0xf0,0xd4,0xcb,0x3c, + 0xf3,0xc6,0x56,0x5c,0x8e,0xa4,0xcc,0x2d,0x3d,0x58,0x01,0xf9,0x3f,0x0b,0x68,0x5a, + 0x44,0x48,0xa1,0x20,0xf0,0x54,0x10,0xd9,0x6d,0x13,0xf9,0xeb,0xc9,0xac,0x8f,0x87, + 0x60,0x98,0x26,0xbd,0xe1,0x18,0xe7,0x9f,0xb0,0x9c,0xe3,0x97,0x2d,0x64,0xe9,0x82, + 0x1a,0xe6,0x55,0xcc,0xa1,0x28,0x3f,0x0f,0x5f,0x7e,0xae,0x95,0xea,0x30,0xcd,0x48, + 0x2d,0x49,0x12,0x92,0x24,0xd1,0x1f,0x1a,0xa4,0x33,0xd8,0x4b,0xa0,0xb9,0x95,0xb7, + 0x9a,0x76,0xf1,0xc2,0x1b,0x5b,0x78,0x7a,0xf3,0x0e,0x8a,0xbd,0x49,0x3b,0xbc,0xf4, + 0xd9,0x33,0x9e,0x9f,0xa7,0x4a,0x00,0x8c,0x20,0x70,0xe6,0x11,0x59,0xc1,0xda,0x3b, + 0xfe,0x12,0x96,0xef,0xea,0x84,0xfa,0xd0,0x34,0x2d,0x52,0xfb,0xf2,0x3c,0xd4,0xcc, + 0x29,0xe1,0xe8,0x45,0x7e,0x96,0xcc,0xaf,0xc2,0x57,0x90,0x4f,0x45,0x69,0x11,0x5e, + 0x8f,0x87,0xfc,0xdc,0x1c,0x7c,0xf9,0xb9,0x76,0x48,0x9d,0xc4,0x4c,0x1b,0x8f,0xcd, + 0xa1,0x07,0x05,0xfa,0x07,0xc3,0xf4,0xf4,0x0d,0x10,0x0a,0x47,0xe8,0xe8,0xee,0xa1, + 0xad,0xab,0x87,0xbd,0xad,0x1d,0xbc,0xf2,0xce,0x36,0x02,0xcd,0x6d,0xb4,0xf7,0x0c, + 0x20,0x4b,0x13,0x7e,0xc6,0xbd,0xc0,0x8d,0xc0,0x6f,0x33,0xbd,0x14,0x8a,0x20,0xf0, + 0x68,0x32,0x39,0xec,0x69,0x6d,0x1d,0x56,0xe0,0x75,0x08,0x3b,0x21,0xc0,0x4c,0x24, + 0xdd,0xf3,0xab,0xea,0x62,0xe0,0x13,0xc0,0x87,0x98,0x60,0x39,0xd3,0xc3,0x41,0x37, + 0x0c,0x42,0xd1,0x38,0xdd,0xe1,0x38,0x0b,0xe7,0xf8,0x58,0x58,0x59,0x46,0xd5,0x9c, + 0x22,0x2a,0x4a,0x8b,0x28,0xc8,0xf5,0xa2,0x28,0x0a,0x4e,0x87,0x03,0xa7,0x43,0xb1, + 0x0f,0x07,0x8a,0xa2,0xe0,0x50,0x64,0xe4,0xc3,0x18,0xac,0x4c,0x13,0xe2,0xba,0x8e, + 0x61,0x18,0xc4,0x75,0x03,0xdd,0x30,0xd0,0x75,0x83,0xb8,0xae,0x13,0x8f,0xeb,0xe8, + 0xba,0x4e,0x5c,0xd7,0x19,0x8c,0x44,0x69,0xeb,0xea,0x61,0x5f,0x7b,0x17,0x7b,0xda, + 0xba,0x68,0xdc,0xd7,0x8e,0x69,0x98,0x14,0x78,0x9c,0x38,0x15,0x79,0xaa,0xb6,0xa1, + 0x06,0x80,0x27,0x80,0x5b,0x81,0xbf,0xa7,0x63,0x50,0x8c,0x20,0xf0,0xe4,0xc8,0xb3, + 0x06,0xf8,0x3d,0x56,0x3c,0xf2,0xc1,0xe8,0xc5,0x8a,0xb9,0xfc,0x33,0x70,0xd7,0x78, + 0x89,0xc1,0xa6,0x48,0x2b,0x9f,0x08,0x5c,0x62,0x6b,0xe7,0x45,0x42,0xb4,0x0e,0x3b, + 0x45,0x7e,0x0a,0x2b,0xe5,0xeb,0xdf,0x67,0x2a,0x6b,0x85,0x20,0x70,0x6a,0x12,0xf8, + 0x11,0xac,0x30,0xc7,0xf1,0xd0,0x01,0xfc,0x04,0xf8,0xf5,0x54,0x67,0x43,0x38,0x02, + 0x99,0x6b,0x81,0xf3,0xb0,0x42,0x30,0x4f,0xc1,0x4a,0xbb,0x92,0x8d,0x30,0xb0,0x92, + 0x3a,0x3c,0x89,0x15,0xf2,0xf7,0xc2,0x74,0x0f,0xa6,0x82,0xc0,0xe9,0x43,0xe0,0xcf, + 0x70,0x84,0x7c,0xcf,0x4b,0x4e,0x3f,0x9f,0xd3,0x3f,0x7e,0x0d,0xdb,0x5f,0x7b,0x89, + 0xc7,0x7f,0xfd,0x7d,0x40,0xda,0x8a,0xe5,0xfc,0xfe,0xd2,0x0c,0x3f,0xa7,0x0c,0x1c, + 0x6b,0x6b,0xe8,0x13,0xb1,0xdc,0x35,0xab,0xed,0x29,0x7f,0x26,0x21,0x6c,0x0f,0x96, + 0x6f,0xd8,0xb3,0x9f,0x57,0x80,0x97,0xd2,0x28,0x7f,0xb8,0x20,0xf0,0x2c,0x90,0xf8, + 0x7a,0xac,0xed,0x9d,0x43,0x9c,0x2d,0xaa,0x8e,0x5e,0xcd,0xa5,0xdf,0xfe,0x31,0x00, + 0xbf,0x78,0xff,0x7a,0x64,0xa7,0x0b,0xac,0xb4,0xa2,0xdf,0x0c,0x68,0xda,0xcf,0x67, + 0xf9,0xb9,0x8b,0xb0,0xd2,0x0f,0xad,0xb0,0x97,0x00,0x8b,0xb1,0xf2,0x2a,0x55,0x61, + 0x65,0x68,0x48,0x65,0xb4,0x61,0x65,0x05,0x0d,0x60,0x55,0xe4,0xd8,0x0a,0xbc,0x03, + 0xec,0x0a,0x68,0x5a,0x8b,0xa0,0x94,0x20,0x70,0x52,0x58,0xf3,0x9e,0x0b,0x37,0xb4, + 0xbc,0xb3,0xe9,0x57,0x92,0x2c,0x1f,0x92,0xf3,0xc6,0xe9,0xcd,0x45,0x71,0x79,0x08, + 0x07,0x3b,0x29,0xa8,0xa8,0xc6,0x57,0x5e,0xcd,0xee,0x4d,0x2f,0x83,0x65,0xf1,0xfc, + 0x62,0xaa,0x19,0x4e,0xfc,0xaa,0xea,0x0e,0x06,0x83,0x4b,0x06,0xc3,0xe1,0xfb,0x24, + 0x58,0x20,0xcb,0x32,0xb2,0x2c,0x23,0x0d,0xfd,0x94,0x24,0xab,0x02,0xdc,0x90,0x11, + 0xc9,0xfe,0x7b,0xe8,0xf7,0x23,0xbd,0xd0,0x51,0x1b,0x54,0x23,0xb6,0xab,0x46,0x5a, + 0x9a,0x87,0x7e,0x37,0x4d,0x13,0xc3,0x30,0x30,0xec,0x9f,0xa6,0x69,0xea,0x1e,0xb7, + 0xfb,0x9b,0x3e,0x9f,0xef,0x66,0xd3,0x34,0xa3,0x62,0x6f,0x56,0x60,0xca,0xd0,0xd0, + 0x14,0xfc,0x22,0x20,0xf9,0x55,0xf5,0xa3,0x7e,0x55,0xdd,0xe1,0x57,0x55,0xf3,0xe0, + 0x43,0xad,0xa9,0x36,0xaf,0xbf,0xf7,0x9f,0xe6,0xad,0xdb,0x7a,0xcc,0xcf,0xfd,0xe6, + 0x8f,0xa6,0x5a,0x53,0x63,0xfa,0x55,0xf5,0x46,0xdb,0x49,0x23,0x65,0x20,0xcb,0xf2, + 0xc9,0x92,0x55,0xf4,0xcd,0x9c,0xc8,0x21,0x49,0x52,0x42,0xc7,0x04,0xaf,0x6f,0x28, + 0x8a,0xf2,0x1f,0x05,0x79,0x79,0x62,0xeb,0x31,0x85,0xe0,0xc8,0x80,0x36,0x7c,0xa6, + 0xa1,0x29,0xf8,0x64,0x7d,0x9d,0xef,0xff,0xfc,0xaa,0x7a,0x37,0xf0,0x35,0xe0,0x7a, + 0xac,0x84,0xf0,0x96,0x56,0x92,0x15,0x76,0xbc,0xf6,0x32,0xf3,0x96,0x1d,0xc3,0xc2, + 0x55,0x27,0x11,0xe9,0xd8,0x83,0x67,0x8e,0xfa,0x59,0x7b,0x2a,0xf8,0xc3,0x14,0x21, + 0xef,0xa9,0x86,0x61,0xfc,0x1d,0xbb,0x1c,0xaa,0x2c,0xcb,0xb8,0x9c,0x4e,0x1c,0x4e, + 0x27,0x0e,0x87,0x03,0x87,0xa2,0x1c,0xd0,0xc6,0xb6,0x03,0xc5,0x90,0x56,0x66,0x84, + 0x16,0x4e,0x84,0x5d,0x43,0x0e,0x23,0x86,0x61,0xa0,0xdb,0xdb,0x4a,0xb1,0x78,0x9c, + 0x58,0x34,0x4a,0x38,0x1c,0x3e,0x5c,0x29,0x13,0x49,0xd7,0xf5,0xef,0x0e,0x0c,0x0e, + 0xfa,0xb0,0xf6,0xc0,0x05,0xc4,0x14,0x7a,0xd2,0xda,0x77,0x3e,0x96,0xbf,0xec,0xb5, + 0xf5,0x75,0xbe,0xff,0x1a,0x31,0x15,0x5d,0x05,0xdc,0x87,0x95,0x7c,0xdb,0x12,0x5a, + 0xc3,0xa0,0x72,0xc5,0x71,0x98,0xa6,0x49,0xcb,0x96,0xe1,0xba,0x57,0x71,0xe0,0xbd, + 0x01,0x4d,0x7b,0x6c,0x56,0x47,0x51,0x87,0xe3,0x28,0xd3,0x34,0x5f,0xcc,0xcf,0xcb, + 0xcb,0xf3,0x78,0x3c,0x38,0x9d,0xce,0x43,0xc9,0x39,0x43,0x18,0x9a,0x3e,0x47,0x22, + 0x11,0xfa,0x07,0x06,0x08,0x85,0x42,0x63,0x3d,0xef,0xf7,0xe2,0xf1,0xf8,0x7f,0x08, + 0xfa,0x08,0x02,0x4f,0x96,0xc0,0x9f,0xb5,0xd7,0xb3,0x4f,0xd6,0xd7,0xf9,0xce,0x3a, + 0x68,0x3d,0x59,0x81,0xb5,0x75,0xb1,0x62,0xac,0x73,0x4b,0x17,0x2c,0x21,0x1a,0x0e, + 0xd1,0xdb,0xbc,0xbb,0x19,0x58,0x3e,0x5b,0x1e,0x40,0x15,0xe5,0xe5,0x1e,0xd3,0x34, + 0x37,0xb9,0xdd,0xee,0x25,0xa9,0x98,0x41,0x52,0xd7,0x75,0xfa,0xfb,0xfb,0x09,0xf6, + 0xf4,0x8c,0x74,0xf5,0x34,0x9c,0x4e,0xe7,0x45,0xb1,0x58,0xec,0x21,0x41,0xa1,0x59, + 0x9e,0xb9,0xa5,0xf9,0xf3,0x9f,0x6f,0xff,0x3c,0xa9,0xa1,0x29,0x38,0xaa,0xfa,0x60, + 0x40,0xd3,0xf6,0x03,0x67,0x60,0x59,0x4a,0x47,0x1b,0xb7,0xdc,0x1e,0xae,0xfc,0xaf, + 0xff,0xe5,0xea,0x9b,0xef,0x62,0xf1,0x86,0x73,0x2b,0x81,0x1f,0xcf,0x56,0x03,0xdc, + 0x6e,0xf7,0xf5,0x1e,0x8f,0x67,0x49,0xaa,0xa6,0x7f,0x55,0x14,0x85,0xc2,0xc2,0x42, + 0xaa,0xab,0xaa,0xc8,0xcb,0x1d,0xde,0xf9,0x92,0xe3,0xf1,0xf8,0xad,0x1e,0x8f,0xa7, + 0x54,0x50,0x48,0x10,0x78,0xa2,0xda,0x37,0x17,0xab,0x22,0x04,0x58,0x7b,0xaa,0x87, + 0x14,0xff,0xb1,0xb3,0xf4,0xbf,0x17,0xcb,0x33,0x6b,0x18,0xb1,0xc1,0x7e,0x4c,0xc3, + 0xc0,0x95,0xe3,0xe5,0x84,0x8b,0x3e,0x88,0xa9,0xc7,0x3f,0xed,0x57,0xd5,0x75,0x33, + 0xdd,0x06,0xdb,0x15,0xf3,0xba,0x74,0xe8,0x6f,0x45,0x51,0x28,0x2d,0x2d,0xa5,0xac, + 0xb4,0x74,0x68,0xaa,0x3d,0x27,0x1a,0x8d,0xfe,0x50,0x50,0x48,0x10,0x78,0xa2,0x58, + 0xc1,0xe8,0x9a,0xbf,0xeb,0xc7,0xfa,0x52,0x40,0xd3,0x9a,0x80,0xfa,0xd1,0xad,0x76, + 0xf0,0xfc,0xdd,0xb7,0x13,0x1e,0xe8,0xa7,0xbf,0xbb,0x13,0x3b,0xda,0xfd,0x36,0x3b, + 0x27,0xef,0x4c,0xe2,0x87,0x58,0xd5,0x2d,0xd2,0x06,0xb9,0xb9,0xb9,0x94,0xcf,0xb5, + 0x0a,0x9f,0x1b,0x86,0xf1,0x29,0x97,0xd3,0x59,0x27,0x68,0x24,0x08,0x3c,0x11,0xf4, + 0x33,0x7a,0x7b,0xf3,0xb0,0x55,0x0c,0x03,0x9a,0x76,0x37,0x70,0xc7,0xc8,0xcf,0x5e, + 0xfe,0xf3,0xef,0xf8,0xf1,0xe9,0x75,0xdc,0xf3,0xed,0x6b,0x86,0xea,0xd9,0xd6,0x02, + 0xbf,0x9b,0xa9,0xad,0x25,0xbf,0xaa,0x2e,0x62,0x9c,0xea,0x96,0xd4,0x45,0xe1,0x00, + 0x00,0x11,0x68,0x49,0x44,0x41,0x54,0xeb,0xa9,0x0a,0x8f,0xc7,0xc3,0x9c,0xb2,0x32, + 0x00,0x29,0xae,0xeb,0xdf,0x14,0x34,0x12,0x04,0x4e,0x1a,0xf5,0x75,0xbe,0x77,0x80, + 0xdf,0xd8,0x7f,0x6e,0x05,0xfe,0x77,0x9c,0x53,0xbe,0x8c,0x55,0x00,0x6b,0x18,0x8e, + 0x82,0x32,0x14,0xb7,0x95,0xe4,0xbc,0xb0,0x72,0x1e,0xee,0xbc,0x82,0xcb,0x81,0x7f, + 0x9f,0xa1,0x26,0x5c,0x45,0x1a,0x6f,0xe3,0x79,0xbd,0x5e,0x7c,0x85,0x85,0x98,0xa6, + 0x79,0xa9,0xc7,0xe3,0x29,0x12,0x54,0x9a,0x1d,0xa4,0xfd,0xa6,0x7c,0x43,0x53,0xd0, + 0x55,0x5f,0xe7,0x4b,0x28,0x48,0xc1,0xaf,0xaa,0x5f,0x00,0x7e,0x75,0xf0,0xe7,0xbe, + 0x2a,0x3f,0xd7,0x34,0xdc,0x8b,0x1e,0x8f,0xf1,0xd8,0x2d,0xbf,0xe4,0x8d,0xbf,0xde, + 0xf9,0xd5,0xe9,0x74,0xb7,0xb4,0xc3,0x20,0x1b,0x49,0x32,0xc3,0x47,0xaa,0xc1,0x34, + 0x4d,0x9a,0xf7,0xef,0x47,0xd7,0xf5,0x8f,0x1a,0x86,0xf1,0x47,0x41,0x27,0xa1,0x81, + 0x27,0xa2,0x89,0x93,0x89,0x30,0xfa,0x1f,0xac,0x9a,0xad,0xa3,0x10,0x0b,0x87,0x30, + 0x31,0x71,0x7a,0x72,0x58,0x77,0xe9,0xc7,0x31,0x0d,0xfd,0x67,0x7e,0x55,0xfd,0x89, + 0x1d,0x59,0x34,0x1d,0x58,0x94,0xee,0xe4,0x05,0xcb,0xa5,0xb3,0xb4,0xa4,0x04,0xd3, + 0x34,0x2f,0x14,0x54,0x12,0x04,0x9e,0x76,0x04,0x34,0x2d,0x0e,0x5c,0x7b,0xf0,0xe7, + 0x03,0x9d,0x6d,0x3c,0xff,0x97,0x3f,0x10,0x8b,0x84,0x89,0x86,0x43,0x43,0x13,0x93, + 0xeb,0x80,0x47,0xfd,0xaa,0x3a,0x1d,0x59,0xd0,0xcf,0x9e,0x81,0xe6,0x76,0x03,0xb7, + 0xd9,0x9a,0x7e,0xda,0xe0,0x76,0xbb,0xf1,0x7a,0xbd,0x6b,0x72,0x73,0x73,0x9d,0x82, + 0x4e,0x62,0x0a,0x3d,0xed,0xb0,0x8d,0x54,0x0f,0x03,0xe7,0x1e,0xd2,0x19,0xb2,0x6c, + 0x39,0x2b,0x0c,0x39,0x2c,0x98,0x26,0x48,0x52,0x2f,0xf0,0x5d,0xac,0x74,0x2f,0x83, + 0x93,0xb8,0xaf,0x02,0xac,0x0a,0x87,0xc3,0xd7,0x9a,0xa6,0x79,0x59,0x4e,0xce,0xb4, + 0x17,0x18,0xfb,0x44,0x40,0xd3,0xfe,0xe0,0x57,0xd5,0x52,0x40,0xc3,0x76,0xd1,0x9c, + 0x0e,0x44,0x22,0x11,0xda,0xda,0xdb,0xe7,0xe8,0xba,0x2e,0xf2,0x58,0x09,0x02,0xcf, + 0x08,0x89,0x97,0x00,0x9b,0x00,0xcf,0xe1,0xbe,0x53,0xec,0x5f,0xc4,0x69,0x57,0x7e, + 0x8e,0x70,0x5f,0x2f,0xcf,0xdc,0x7e,0x13,0xfd,0x6d,0xcd,0xcd,0xc0,0x2d,0xc0,0x1d, + 0x01,0x4d,0xdb,0x9a,0xe0,0x7d,0x5c,0x58,0x45,0x9c,0x2f,0xc0,0x34,0x3f,0x60,0x44, + 0x42,0x4b,0xfb,0x07,0x23,0xe4,0xe4,0xe5,0xe3,0x74,0x4e,0xbb,0xc2,0x3a,0x2f,0xa0, + 0x69,0x8f,0xd8,0xeb,0xed,0xed,0x4c,0x71,0xca,0x9f,0x83,0xd7,0xc2,0x91,0x48,0x64, + 0x5d,0x4b,0x6b,0xeb,0x0b,0x82,0x52,0x33,0x0b,0x47,0x36,0x36,0x3a,0xa0,0x69,0x8d, + 0x7e,0x55,0xfd,0x29,0x47,0xb0,0x38,0x1f,0x7d,0xd6,0x05,0x2c,0x5d,0x7b,0x1a,0x98, + 0x26,0x55,0x8b,0x97,0x71,0xcb,0x67,0x2e,0xad,0x34,0x0d,0xe3,0xbb,0xc0,0xf5,0x7e, + 0x55,0x0d,0x00,0x2f,0x62,0xc5,0xc1,0xee,0xc5,0x4a,0x83,0x6a,0x60,0x65,0xde,0x98, + 0x8b,0x15,0xdb,0x7b,0x0c,0x70,0x34,0x50,0x02,0x70,0x4a,0xfd,0x97,0x39,0xe1,0xbd, + 0x97,0xf0,0xf8,0x6d,0x37,0xf1,0xfa,0x7d,0xb7,0x27,0xfb,0xc8,0x3a,0x70,0x17,0x49, + 0xd4,0x33,0x3e,0x68,0x70,0x4e,0x26,0xdd,0x65,0x2b,0xe0,0x03,0x12,0x4e,0x29,0x29, + 0x49,0x12,0x1e,0x8f,0xa7,0x5a,0xd0,0x49,0x10,0x78,0x26,0xf1,0x7d,0x2c,0x2f,0xad, + 0xe3,0xc6,0xfa,0xe7,0xa6,0xbf,0xdf,0xc7,0xb2,0x75,0xa7,0x53,0x5c,0x51,0x4d,0x5e, + 0x51,0x09,0xae,0xbc,0x02,0x22,0xbd,0x41,0x00,0x65,0xed,0xc7,0xae,0xa9,0x2d,0xae, + 0xa8,0xae,0xdd,0xfe,0xea,0x8b,0x6c,0xf9,0xc7,0x43,0x23,0x55,0x11,0xb5,0x6b,0xcf, + 0x44,0x3d,0xfa,0x78,0x1a,0x5f,0xf8,0x07,0xcd,0x9b,0x5f,0x1b,0xfe,0x7c,0xd9,0xda, + 0xd3,0xf0,0x16,0x14,0xd2,0xaa,0xed,0x44,0x4e,0xde,0x6d,0xf2,0x07,0xc0,0xbd,0x49, + 0x12,0x78,0xa2,0xb8,0x17,0xd8,0x0c,0xdc,0x94,0xe4,0x79,0x15,0x82,0x4e,0x82,0xc0, + 0x33,0xa9,0x85,0xe3,0x7e,0x55,0xbd,0x0c,0xd8,0x08,0x1c,0xb2,0x8f,0xd9,0xb3,0x2f, + 0xc0,0x6f,0xae,0x38,0x9b,0xe5,0xe7,0x5d,0x46,0x47,0x60,0xfb,0x10,0x79,0x59,0xf1, + 0x9e,0xf7,0x73,0xda,0x47,0xaf,0x06,0x4c,0x8e,0x3e,0xe3,0x5c,0xee,0x35,0x0d,0x1a, + 0xff,0xf9,0x77,0x00,0x8e,0xff,0xc0,0xc7,0x38,0xf7,0xea,0xaf,0x80,0x24,0xb1,0xe6, + 0xa2,0x0f,0x72,0xfb,0x75,0x9f,0x66,0xdf,0xe6,0xd7,0x40,0x92,0x78,0xe4,0xa6,0x1b, + 0x58,0x7d,0xc1,0x65,0x16,0x81,0xe5,0xa4,0x6c,0x87,0xcd,0xc0,0x8f,0x80,0x25,0x33, + 0xd8,0x3d,0xbf,0xc5,0xda,0xa7,0x5e,0x95,0xc4,0x39,0x25,0x82,0x4e,0x33,0x8f,0x6c, + 0xaf,0x0f,0xbc,0x03,0xb8,0x14,0x18,0x73,0x2b,0x4a,0x72,0xb8,0x78,0xf7,0xf1,0x07, + 0x68,0x6b,0x7a,0x7b,0xf8,0xb3,0x9d,0xaf,0x3c,0x47,0x73,0x93,0x55,0x5f,0x2b,0x1a, + 0x0a,0x11,0x19,0x38,0x50,0xd3,0x76,0xa0,0xbb,0x8b,0x68,0x24,0x8c,0x24,0xc9,0x84, + 0xfb,0x7a,0x19,0x08,0x1e,0x28,0x99,0xa9,0x6d,0x7c,0x9e,0xbb,0xbf,0xf3,0x79,0xf6, + 0x0e,0x69,0xe5,0xc4,0x71,0xeb,0x4c,0x24,0xe3,0x3b,0xa8,0x5f,0x4c,0xe0,0x67,0x49, + 0x9e,0x96,0x23,0xe8,0x24,0x34,0xf0,0x6c,0x90,0xf8,0x1f,0x7e,0x55,0xfd,0x28,0x56, + 0x0a,0xda,0x71,0xf7,0x7d,0x43,0x5d,0xed,0xfc,0xef,0xe7,0x3e,0x8c,0x3b,0xaf,0x80, + 0x78,0x78,0x10,0x3d,0x76,0x80,0x5b,0x8d,0x4f,0x3d,0xcc,0xae,0x8d,0xcf,0x51,0x54, + 0xed,0xa7,0x7d,0xe7,0x56,0xf4,0x68,0x64,0xac,0x05,0x63,0xb2,0x8f,0x78,0xcf,0x2c, + 0x75,0xcd,0x03,0xc0,0x60,0x12,0xc4,0x74,0x08,0x3a,0x09,0x0d,0x3c,0x5b,0x24,0xfe, + 0x8b,0xad,0x89,0x13,0xdb,0x26,0x32,0x4d,0x22,0x7d,0x3d,0xa3,0xc8,0x3b,0x84,0x48, + 0x7f,0x2f,0x2d,0x8d,0x6f,0x8d,0x4d,0x5e,0x48,0x36,0x48,0xbf,0x93,0x31,0xc2,0x21, + 0x67,0xa8,0x4f,0x22,0xc0,0x33,0x42,0x3a,0x04,0x81,0xd3,0x85,0xc4,0xf7,0x63,0x95, + 0x4a,0xd9,0x3b,0x9d,0xf7,0x49,0x52,0xff,0x6e,0x9f,0xcc,0xde,0xf3,0x14,0xe0,0x5f, + 0x42,0x32,0x04,0x81,0xd3,0x89,0xc4,0xaf,0x60,0x6d,0xfd,0xdc,0x09,0xd3,0x54,0xa7, + 0x3b,0x39,0x0d,0xbc,0x6b,0x96,0xbb,0xe4,0x5d,0x21,0x15,0x82,0xc0,0xe9,0x46,0xe2, + 0xee,0x80,0xa6,0x7d,0x08,0x38,0x07,0x78,0x6d,0x6a,0xb9,0x2b,0x25,0xbb,0x85,0xb4, + 0x7f,0x8a,0x94,0xfe,0x44,0xdf,0xf3,0x2e,0x21,0x11,0x82,0xc0,0xe9,0x4a,0xe4,0x27, + 0xb0,0x0a,0x7b,0x9f,0x03,0xfc,0x0d,0xcb,0x99,0x62,0xf2,0x1d,0x9e,0xdc,0x16,0x52, + 0xcf,0x2c,0x13,0x58,0x24,0x6a,0x4f,0x71,0x08,0xcb,0xe1,0x91,0x49,0x6c,0x60,0x25, + 0xc6,0x7b,0xdc,0xaf,0xaa,0x25,0xc0,0x05,0x58,0xf5,0x8e,0xd6,0x01,0x95,0x58,0x56, + 0xeb,0x23,0xa9,0x54,0xd3,0x26,0x7e,0x1f,0xf0,0x36,0xf0,0x7a,0x4e,0x4e,0x4e,0x17, + 0x56,0x35,0x89,0x44,0x10,0x9f,0xe5,0x2e,0x18,0x10,0x52,0x20,0x08,0x9c,0x29,0x64, + 0xee,0xc4,0x8a,0xee,0xb9,0x0d,0xc0,0xaf,0xaa,0x3e,0x60,0x3e,0x96,0x07,0x52,0x09, + 0xd6,0x76,0x8b,0x03,0x6b,0x4f,0xb9,0x1f,0x2b,0x41,0x7b,0x2b,0xb0,0x2f,0xa0,0x69, + 0x1d,0x43,0xd7,0xf1,0xab,0xea,0xf2,0x24,0x08,0x2c,0x20,0x20,0x08,0x3c,0x4d,0x84, + 0x0e,0x62,0x05,0x44,0x6c,0x12,0xbd,0x21,0x20,0xd6,0xc0,0x02,0x02,0x02,0x82,0xc0, + 0x02,0x02,0x82,0xc0,0x02,0x02,0x02,0x82,0xc0,0x02,0xb3,0x8a,0xb8,0xe8,0x02,0x41, + 0x60,0x81,0xf4,0x85,0x29,0xba,0x40,0x10,0x58,0x40,0x40,0x40,0x10,0x58,0x40,0x40, + 0x40,0x10,0x58,0x40,0x40,0x40,0x10,0x58,0x40,0x40,0x10,0x58,0x40,0x40,0x40,0x10, + 0x58,0x20,0x31,0xec,0xb5,0x02,0x2b,0x12,0x82,0x69,0x9a,0x9c,0xfd,0x85,0xef,0xac, + 0x6c,0x68,0x0a,0x9e,0x7d,0xdd,0x5f,0x5f,0x3a,0xcb,0x9d,0x5f,0xe8,0x49,0x58,0x20, + 0x1c,0xce,0xe1,0xe0,0x8c,0x40,0x12,0xf7,0x14,0x98,0x1d,0x08,0x5f,0xe8,0x14,0xc6, + 0xe9,0x57,0x5f,0xb7,0xe1,0xe4,0x0f,0x5c,0x51,0x06,0xcc,0xed,0x6e,0xd9,0xe7,0xff, + 0xf5,0x07,0x4f,0x47,0x71,0x8d,0xcf,0x45,0x33,0x16,0x45,0x5d,0x7e,0xcc,0x4f,0x01, + 0x14,0xa7,0x8b,0xc2,0xf2,0x6a,0xda,0xfa,0x12,0x8b,0x4c,0x3c,0xf3,0x9a,0xaf,0x5f, + 0x71,0xc2,0x05,0x97,0x9e,0x02,0x74,0x44,0x42,0x03,0x3d,0x3f,0x3c,0xc5,0x8f,0xab, + 0xa8,0x52,0xbc,0x0c,0x41,0x60,0x01,0xb0,0x82,0xfa,0x4d,0x33,0xb1,0x2d,0xda,0xe2, + 0xaa,0x9a,0x33,0x81,0x33,0x01,0x1c,0x4e,0x17,0xe8,0x09,0xfa,0x66,0x48,0x60,0x8e, + 0xda,0x06,0x4e,0x7c,0x4b,0x58,0x71,0xba,0x0a,0x80,0xe5,0x00,0xb2,0xa2,0x10,0xef, + 0x8d,0xe1,0x4a,0xa0,0x78,0xe8,0x92,0xd3,0xce,0x9f,0x7f,0xfd,0xb7,0x7e,0xb4,0x0c, + 0x68,0xaa,0xaf,0xf3,0x09,0x27,0x12,0x41,0xe0,0xf4,0x47,0x43,0x53,0x30,0x1f,0xab, + 0x0a,0xe1,0x1a,0xac,0x1c,0xcb,0x47,0x77,0xef,0xdf,0x7b,0xd4,0x8d,0x1f,0x39,0x77, + 0xa8,0xa8,0x78,0xc6,0x40,0x3d,0xea,0xd8,0x0b,0x81,0x0b,0x81,0x78,0x43,0x53,0xf0, + 0x5d,0xe0,0x4d,0xe0,0x75,0xac,0xbc,0x5a,0x5b,0xea,0xeb,0x7c,0x41,0x21,0x11,0x82, + 0xc0,0xa9,0x4e,0xd8,0x32,0xac,0x2c,0x1e,0x1b,0x80,0xb5,0xb6,0x26,0x2b,0x38,0x58, + 0x03,0x67,0x81,0x4c,0x1d,0x6d,0x1f,0x1f,0xb5,0x3f,0x0b,0x37,0x34,0x05,0xb7,0x00, + 0x2f,0x61,0x65,0xba,0x7c,0xb1,0xbe,0xce,0xb7,0x57,0x48,0x8c,0x20,0xf0,0x6c,0x13, + 0x56,0x06,0x4e,0xc2,0xaa,0x74,0x78,0x1e,0xb0,0x94,0x23,0x14,0x4c,0xcb,0x62,0x78, + 0x80,0x63,0xed,0xe3,0x1a,0x20,0xd6,0xd0,0x14,0xdc,0x09,0x3c,0x02,0x3c,0x0a,0x3c, + 0x95,0x64,0x9d,0x67,0x01,0x41,0xe0,0x09,0x93,0xd6,0x0b,0x9c,0x0a,0x5c,0x86,0x55, + 0x5b,0xa9,0x54,0xf4,0x4a,0xd2,0x70,0x02,0x8b,0xed,0xe3,0x4b,0xc0,0x40,0x43,0x53, + 0xf0,0x51,0xac,0x24,0xf6,0x8f,0x8a,0xe9,0xb6,0x20,0xf0,0x54,0x93,0x56,0x02,0x4e, + 0x01,0x3e,0x06,0x5c,0x84,0xa8,0x03,0x34,0xd5,0xc8,0x05,0x3e,0x60,0x1f,0x43,0x64, + 0xfe,0x03,0xf0,0x98,0xd0,0xcc,0x82,0xc0,0x93,0x21,0x6e,0x11,0x50,0x0f,0x7c,0x0a, + 0x58,0x34,0x15,0xd7,0x34,0x33,0x34,0x46,0xc8,0x9c,0xba,0x86,0x8d,0x24,0xf3,0xfe, + 0x86,0xa6,0xe0,0xef,0x81,0x9b,0xeb,0xeb,0x7c,0x7b,0x84,0x44,0x0a,0x02,0x27,0x4a, + 0x5c,0x3f,0xf0,0x55,0xe0,0x93,0x4c,0x71,0xd1,0x2e,0x43,0x8f,0x27,0x6c,0xc8,0x4a, + 0x05,0x83,0x97,0xc3,0x9b,0xd8,0xf7,0xfa,0xba,0x3a,0xa6,0xe3,0xf6,0x15,0xc0,0xb7, + 0x80,0xaf,0x37,0x34,0x05,0xff,0x02,0xfc,0xa4,0xbe,0xce,0xf7,0xa6,0x90,0xd0,0x03, + 0x10,0x9e,0x58,0xa3,0x89,0x5b,0xd3,0xd0,0x14,0x6c,0x00,0xb6,0x02,0x9f,0x65,0x1a, + 0x2a,0xee,0x85,0xfa,0x7a,0x13,0xaa,0xce,0x60,0x9a,0x06,0x0e,0x87,0x73,0x56,0xfb, + 0x43,0x92,0x24,0x72,0xab,0xeb,0x12,0xfa,0xee,0xe6,0xc7,0x1e,0xc0,0x34,0xa6,0xcd, + 0x71,0x4b,0x01,0x3e,0x04,0x6c,0x6a,0x68,0x0a,0xde,0xdf,0xd0,0x14,0x3c,0x4a,0x48, + 0xab,0x20,0xf0,0x48,0xe2,0x7a,0x1a,0x9a,0x82,0xdf,0x07,0x1a,0xb1,0xea,0xe2,0xba, + 0xa6,0xeb,0x5e,0xfb,0xb7,0x6f,0x49,0x4c,0x53,0xc7,0x62,0xe4,0x15,0xcf,0xae,0x7d, + 0x4c,0x71,0x38,0xa9,0x3a,0xfa,0x84,0x84,0xbe,0xdb,0xdf,0xde,0x42,0x6b,0x60,0xfb, + 0xb4,0x8f,0x29,0xc0,0xc5,0xc0,0xeb,0x0d,0x4d,0xc1,0x5b,0x1a,0x9a,0x82,0xc5,0x82, + 0xc0,0x82,0xbc,0x1b,0x80,0x77,0x80,0xeb,0x01,0xef,0x74,0xde,0x2b,0x1e,0x8d,0xf2, + 0xda,0x43,0x89,0x55,0x0b,0xcd,0x29,0x2a,0xa5,0xa0,0x74,0xce,0xec,0x6a,0x60,0x45, + 0xa1,0x6a,0x69,0x82,0xca,0x4e,0x92,0xd8,0xfc,0xd4,0xa3,0x13,0x29,0x9f,0x3a,0xd1, + 0xa5,0x5f,0x3d,0xd0,0xd4,0xd0,0x14,0xbc,0xdc,0x36,0x32,0x0a,0x02,0x67,0x19,0x71, + 0x1d,0x0d,0x4d,0xc1,0xff,0x04,0xfe,0x01,0x2c,0x98,0x89,0x7b,0x36,0x6d,0x7c,0x9e, + 0x8e,0xed,0x89,0xd5,0x0b,0xab,0x5b,0x77,0x26,0xde,0x02,0xdf,0xec,0x76,0x92,0x69, + 0xb2,0xe0,0xd8,0x13,0x30,0x13,0x74,0xe1,0xdc,0x78,0xf7,0x1f,0x68,0x0f,0xec,0x98, + 0xc9,0x27,0x2c,0x01,0xee,0x00,0x6e,0x6f,0x68,0x0a,0xe6,0x09,0x02,0x67,0x0f,0x79, + 0x0b,0x80,0x87,0x81,0x6f,0xcc,0x54,0x1f,0x74,0x35,0xef,0xe1,0xe1,0x9f,0xff,0x07, + 0x92,0xac,0x24,0xf4,0xfd,0x95,0x67,0x5f,0x80,0x69,0x4e,0xc5,0x9a,0xd2,0x1c,0xb3, + 0x8e,0x71,0xa2,0xa8,0x5a,0xb4,0x8c,0x92,0xda,0xa5,0x89,0x4d,0xfb,0xf5,0x38,0x8f, + 0xde,0xfc,0x73,0xa2,0xe1,0x19,0xaf,0x88,0xfa,0x11,0xe0,0x85,0x86,0xa6,0x60,0xb5, + 0x20,0x70,0xe6,0x93,0xd7,0x67,0x6b,0xdd,0xb3,0x67,0xea,0x9e,0x5d,0xcd,0x7b,0xb8, + 0xf3,0xbb,0x5f,0x26,0x92,0x60,0x44,0x50,0xdd,0x29,0xe7,0xa0,0xae,0x38,0x76,0xea, + 0x14,0xa9,0x91,0xf8,0x16,0x8f,0x24,0x8f,0x9e,0x8d,0x3a,0xdc,0x6e,0xce,0xfc,0xd4, + 0x97,0x12,0xde,0xff,0xd2,0x5e,0x7d,0x9e,0x27,0x6e,0xf9,0x15,0xb1,0x48,0x64,0xa6, + 0x5f,0xed,0xd1,0xc0,0x8b,0x0d,0x4d,0xc1,0xf9,0x82,0xc0,0x99,0x4b,0x5e,0x17,0xf0, + 0x20,0x56,0x60,0xc1,0xb4,0x43,0x8f,0xc5,0xd8,0xf2,0xc2,0x53,0x34,0x5c,0x73,0x39, + 0x5d,0x81,0x6d,0x09,0xaf,0x7d,0xcf,0xfe,0xf4,0x97,0x27,0x15,0xec,0x60,0x9a,0x13, + 0xdf,0x82,0x1a,0xeb,0xac,0x45,0xab,0x4e,0xe6,0xf8,0x0f,0x7c,0x2c,0xe1,0x6b,0x6c, + 0xfa,0xeb,0x1d,0xdc,0xf7,0x93,0xeb,0x09,0xb6,0xee,0x9f,0xa9,0x35,0xf1,0x10,0x6a, + 0x80,0x27,0x1a,0x9a,0x82,0xa5,0x82,0xc0,0x99,0x89,0x1b,0xb0,0x3c,0xaa,0xa6,0x15, + 0xb1,0xf0,0x20,0x8d,0x2f,0x3d,0xc3,0xed,0x5f,0xbf,0x9a,0x7b,0xbe,0xf3,0x39,0xa2, + 0x03,0xfd,0x09,0x9d,0xe7,0xce,0x2f,0xe4,0x8a,0xff,0xbc,0x09,0xdf,0xdc,0x8a,0xc9, + 0x3d,0x80,0xa1,0xe3,0x70,0xb9,0x87,0x29,0xe9,0x70,0xbb,0x13,0x1f,0x74,0xe2,0xf1, + 0x31,0xb4,0xb2,0xcc,0x99,0x57,0x7e,0x8e,0xe5,0xe7,0x5c,0x9c,0xf0,0x75,0xb6,0x3d, + 0xf7,0x38,0xbf,0xfd,0xf4,0x25,0x3c,0x7f,0xd7,0x6d,0xf4,0x75,0xb6,0xcf,0xe4,0x3b, + 0xae,0x05,0x6e,0xb3,0xfd,0xd4,0x05,0x81,0x33,0x48,0xfb,0xae,0xc6,0xda,0xdb,0x9d, + 0x56,0xf4,0x77,0x77,0x71,0xdb,0xd7,0x3e,0xcd,0x3d,0xff,0xfe,0x05,0xf6,0x6d,0x7e, + 0x15,0x49,0x19,0xdf,0x57,0xc6,0x34,0x4d,0xaa,0x57,0xae,0xe1,0xaa,0x1b,0xff,0x44, + 0x79,0xed,0xd8,0xfb,0xae,0x86,0x61,0x24,0xec,0xed,0x24,0x29,0x0e,0x5c,0x39,0x96, + 0x41,0x5d,0x96,0x65,0xf2,0x4a,0xcb,0x13,0x7e,0xfe,0xee,0xe6,0xbd,0x63,0x6a,0x6f, + 0xa7,0xc7,0xc3,0x05,0x5f,0xf8,0x36,0xeb,0xaf,0xfc,0x42,0xc2,0xda,0x3d,0x16,0xea, + 0xe7,0xe9,0x5b,0x7e,0xc1,0xad,0x9f,0xff,0x08,0xdd,0x2d,0xcd,0x33,0xf9,0xba,0xcf, + 0x07,0x2e,0x15,0x04,0xce,0x2c,0x5c,0x8f,0xe5,0x10,0x30,0xad,0x78,0xe3,0x89,0xbf, + 0xd1,0xda,0xf8,0x56,0x82,0x53,0x5d,0x83,0x82,0x8a,0x6a,0x2e,0xfc,0xe6,0x8f,0xf9, + 0xc8,0x0f,0xfe,0x9b,0xe2,0xca,0x9a,0xc3,0x7e,0x37,0x12,0xea,0x47,0x4a,0xd0,0xb1, + 0xa3,0xb0,0x7a,0x3e,0x1e,0xaf,0x65,0x94,0x95,0x15,0x85,0x92,0xea,0x79,0x09,0x3f, + 0x7f,0xcb,0x8e,0xc6,0xc3,0x4e,0x7b,0x1d,0x2e,0x17,0xa7,0x5e,0x51,0xcf,0x95,0xbf, + 0xb9,0x83,0xc5,0x1b,0xce,0x45,0x0f,0x27,0x56,0x3e,0xb8,0xbf,0xbd,0x85,0x97,0xee, + 0xbb,0x63,0xa6,0xdf,0x77,0x56,0x94,0x70,0xcd,0x0a,0x57,0x4a,0x7b,0x4d,0x74,0xee, + 0x4c,0xdc,0x4b,0x92,0x8e,0x3c,0x26,0x9a,0x86,0x8e,0x24,0x41,0xed,0x69,0x97,0x53, + 0xb3,0x72,0x1d,0x8b,0x8e,0x3d,0x96,0xb2,0xf2,0x42,0xc6,0x5b,0xf2,0xf6,0x77,0x75, + 0x22,0x3b,0x12,0xf3,0x2f,0x99,0x7f,0xfc,0x49,0xb8,0xbc,0x5e,0x4c,0x5b,0x6b,0xd7, + 0x2c,0x3b,0x9a,0x8d,0xd6,0xc2,0x78,0xdc,0x73,0x5b,0xb7,0x6d,0x61,0xb0,0xaf,0x07, + 0x4f,0x6e,0xfe,0x61,0x17,0xd8,0x95,0x8b,0x96,0x72,0xe1,0x57,0x7e,0xc0,0xb2,0x73, + 0x3e,0xce,0xae,0xd7,0x5f,0x66,0xfb,0xb3,0x0f,0xd0,0xbb,0x77,0x0b,0xb2,0x33,0xe7, + 0xb0,0xe7,0x78,0x0a,0x8a,0x66,0xfa,0xb5,0x2f,0x6e,0x68,0x0a,0xae,0xa9,0xaf,0xf3, + 0xfd,0x4b,0x10,0x38,0xfd,0xb1,0x0a,0x2b,0x84,0x6d,0xda,0x71,0xc2,0x05,0x97,0x92, + 0x5b,0x3c,0x97,0xc0,0x96,0x9d,0x44,0x06,0x7a,0x50,0x9c,0x6e,0x3c,0x05,0x45,0xb8, + 0x3c,0x5e,0xbc,0xbe,0x52,0xf2,0x4a,0xe6,0x92,0x5f,0x5a,0x89,0xe2,0xb4,0xc8,0x38, + 0x18,0x85,0xbd,0x7b,0x43,0x14,0x15,0xb9,0xc8,0xcf,0x3f,0xdc,0xeb,0x90,0xd8,0xbf, + 0x7d,0x6b,0xc2,0x86,0xad,0x65,0xeb,0xcf,0x1c,0xe5,0xd6,0x58,0xbd,0xe4,0x28,0x14, + 0x97,0x0b,0x3d,0x16,0x1b,0xf7,0xdc,0x50,0x67,0x2b,0x1d,0xbb,0x03,0x54,0x1f,0xc6, + 0x81,0x43,0xd7,0x4d,0xba,0xbb,0x63,0xf4,0xf7,0xc7,0xc9,0x2d,0x55,0x59,0x71,0xb6, + 0xca,0x8a,0xb3,0x2e,0x63,0xa0,0xbb,0x9d,0xfe,0xee,0x36,0xfa,0x3b,0xf6,0x13,0x19, + 0x1c,0x20,0xd2,0x17,0x24,0x36,0xd8,0x8f,0xec,0x70,0x52,0xb1,0x68,0x05,0xab,0xce, + 0x3a,0x75,0x36,0xde,0xfb,0x7a,0xac,0x8c,0x20,0x82,0xc0,0x69,0x8e,0x9a,0x99,0xba, + 0x91,0xd3,0xe3,0x61,0xe5,0x19,0x67,0xb3,0x74,0x9d,0x41,0x6f,0x6f,0x9c,0x81,0x90, + 0x3e,0xee,0x16,0x8c,0x61,0x40,0x67,0x67,0x94,0x50,0x48,0xa7,0xac,0xcc,0x85,0x7c, + 0xd0,0x56,0x4e,0x74,0x70,0x80,0xd7,0x1f,0xfa,0x4b,0x42,0xf7,0x2f,0x9a,0x57,0x8b, + 0x7a,0xd4,0x71,0xa3,0xa7,0xd4,0x65,0x73,0x59,0x7d,0xc9,0x27,0x78,0xf9,0x8e,0x5b, + 0xc6,0x5f,0x53,0x39,0x9c,0x6c,0x7e,0xfa,0xd1,0x31,0x09,0x1c,0x0e,0xeb,0xb4,0xb7, + 0x47,0xd1,0x75,0xf3,0xe0,0x69,0x07,0xb9,0xc5,0x73,0xc8,0x2d,0x9e,0xc3,0xdc,0xda, + 0x15,0xc3,0x83,0x8e,0x2c,0x43,0x41,0x81,0x83,0xfc,0x7c,0x07,0x8a,0x32,0x2b,0xce, + 0x52,0x55,0x62,0x0d,0x9c,0x19,0x88,0xcd,0xf4,0x0d,0xdd,0x6e,0x99,0xb2,0x32,0x17, + 0x73,0xca,0x5c,0xc8,0x09,0xca,0xee,0xe0,0xa0,0x4e,0x4b,0x4b,0x04,0xe3,0xa0,0x7d, + 0xdb,0x57,0xfe,0x76,0x37,0x3d,0xcd,0xda,0xb8,0xe7,0xeb,0xd1,0x30,0xe7,0x7e,0xee, + 0x1b,0x38,0x0f,0xb2,0x3a,0x9b,0xa6,0xc9,0x89,0xef,0xfb,0x30,0x39,0x45,0x89,0x85, + 0x31,0x6f,0xbc,0xf3,0x56,0x9a,0x9b,0x46,0x7b,0x8c,0x85,0x42,0x3a,0xad,0xad,0x91, + 0x43,0xc9,0x7b,0xd8,0xf6,0x4b,0x54,0x56,0x7a,0xf0,0xf9,0x9c,0xb3,0x45,0xde,0x59, + 0x79,0xef,0x82,0xc0,0xd3,0x83,0xc6,0xd9,0xba,0xb1,0xd7,0xab,0x50,0x5e,0xee,0x49, + 0x78,0x3b,0x34,0x1a,0x35,0x68,0x6f,0x8b,0xda,0x9a,0x77,0x90,0xe7,0xee,0xfc,0x3d, + 0x4f,0xdf,0xf2,0x0b,0xc6,0xde,0xa1,0x1d,0xbd,0xce,0x3c,0xa5,0xfe,0x5a,0xe6,0xaf, + 0x1c,0x7b,0x8b,0x3b,0xaf,0xa8,0x98,0xcb,0xbe,0xf7,0xcb,0xc4,0x84,0xc2,0xe5,0xe6, + 0xae,0xef,0x7e,0x69,0x38,0x38,0x21,0x12,0x31,0x68,0x6f,0x8f,0x24,0x1c,0xcb,0x9c, + 0x93,0x63,0xb5,0xd9,0xe1,0x98,0x75,0x17,0xe5,0x6d,0x82,0xc0,0x99,0x81,0x37,0x81, + 0xce,0xd9,0xba,0xb9,0xcb,0x2d,0x53,0x56,0x9a,0xf8,0x5e,0xec,0x60,0x58,0x67,0xef, + 0xce,0xfd,0xdc,0xf6,0xd5,0x7a,0x9e,0xb9,0x35,0x01,0xd2,0x99,0x26,0xab,0x2e,0xf9, + 0x38,0xa7,0x5c,0x7e,0xe5,0x11,0x8d,0x68,0x35,0x4b,0x8f,0xe6,0xc3,0x3f,0xbd,0x25, + 0xa1,0x7d,0xe1,0x81,0x8e,0x56,0x7e,0x77,0xd5,0xc5,0xbc,0xf1,0xe4,0xdf,0x93,0x22, + 0xaf,0xd3,0x69,0xcd,0x3c,0x52,0x24,0x77,0xdf,0x13,0x82,0xc0,0x19,0x80,0xfa,0x3a, + 0xdf,0x20,0xf0,0x7f,0xb3,0xf9,0x0c,0xde,0x5c,0x05,0xaf,0x37,0xf1,0x5d,0xac,0x17, + 0xef,0xf9,0x23,0x6d,0x4d,0x6f,0x8f,0xfb,0x3d,0x23,0x36,0xc8,0xb1,0x1f,0xfa,0x2a, + 0xab,0x2f,0xb9,0x66,0xd8,0x30,0x76,0x24,0xf8,0x8f,0x39,0x81,0xf3,0xbe,0xfd,0xbf, + 0x14,0xaa,0xcb,0xc7,0xfd,0xae,0x24,0x2b,0xfc,0xf5,0x07,0x5f,0xb4,0x3c,0xaa,0x12, + 0x44,0x69,0xe9,0xa1,0x6b,0xf8,0x59,0xc2,0xa3,0xf5,0x75,0xbe,0x80,0x20,0x70,0xe6, + 0xe0,0xc7,0xc0,0xac,0x26,0x4b,0xf3,0xf9,0x12,0x34,0x84,0x4b,0x12,0x3b,0x9f,0xb9, + 0x7b,0x3c,0xb5,0xcb,0x9c,0x65,0x27,0x71,0xfe,0xf7,0xef,0x66,0xf9,0x19,0x97,0xd0, + 0xd7,0x6f,0x12,0x0e,0xeb,0xe3,0x5e,0xba,0xa3,0x23,0x42,0x41,0xc5,0x02,0xce,0xfd, + 0xda,0x7f,0x73,0xfc,0x15,0xd7,0xe1,0xf0,0x1c,0x39,0x88,0x47,0x72,0x78,0x08,0xf5, + 0x24,0x36,0x79,0xf1,0xe6,0x28,0xb8,0xdd,0x29,0x21,0x52,0x71,0xac,0x4c,0x1e,0x19, + 0x8f,0xac,0x49,0xa9,0x53,0x5f,0xe7,0x6b,0x6d,0x68,0x0a,0x5e,0x03,0xfc,0x79,0xd6, + 0xa6,0xd2,0x2e,0x19,0xb7,0x5b,0x26,0x12,0x31,0xc6,0x9d,0x12,0xcf,0x3d,0x6a,0x3d, + 0xfb,0x5e,0x7b,0x72,0xf4,0xc7,0x86,0x81,0xac,0x28,0xf8,0xd7,0xbf,0x8f,0x85,0x27, + 0xbd,0x87,0x39,0x0b,0x96,0x8d,0x8a,0x6e,0xea,0xec,0x8c,0x51,0x59,0xa9,0x1c,0x76, + 0xfa,0x1a,0x0a,0xe9,0x84,0x42,0x16,0xc9,0x1d,0xee,0x1c,0x96,0x6e,0x78,0x3f,0xf3, + 0x57,0x9d,0xce,0x9e,0xb7,0x5e,0x62,0xdb,0xb3,0x0f,0xd2,0xf1,0xee,0xf3,0xc8,0xee, + 0xd1,0x84,0xce,0xaf,0xa8,0xc5,0x57,0xae,0x26,0xd4,0xbe,0xfc,0x82,0x94,0x11,0xa7, + 0x1f,0xd6,0xd7,0xf9,0x36,0x65,0x83,0x5c,0x67,0x5d,0x20,0x74,0x43,0x53,0xf0,0x87, + 0xb3,0x39,0x3a,0xf7,0xf4,0xc4,0xe8,0xee,0x1e,0xdf,0x38,0x3a,0xd8,0xd3,0xc5,0xee, + 0x57,0x1f,0xa1,0xb7,0x65,0x07,0xb2,0xa7,0x08,0x77,0xfe,0x1c,0x4a,0xd4,0x3a,0x8a, + 0xaa,0x16,0xe0,0xc9,0x2b,0x3c,0xec,0x79,0x65,0x65,0x2e,0x72,0x73,0xc7,0x26,0x52, + 0xf3,0xbe,0x30,0xd1,0xd8,0xd8,0x83,0x87,0xa1,0xc7,0xe9,0xef,0x68,0xa1,0x73,0xcf, + 0x36,0xba,0xf6,0xec,0x20,0xbf,0x40,0xa6,0xb8,0xa2,0x8a,0xfc,0x9a,0x13,0x70,0xe7, + 0x8f,0xef,0x84,0x21,0x49,0x30,0x6f,0x9e,0x37,0x15,0xd6,0xbe,0xf7,0x02,0x1f,0xac, + 0xaf,0xf3,0xe9,0x82,0xc0,0x99,0x49,0x60,0x19,0x2b,0xa8,0xe1,0xda,0xd9,0xb8,0x7f, + 0x38,0x6c,0x6d,0x15,0x25,0x82,0xe2,0x62,0x27,0xf9,0xf9,0x0e,0x42,0x21,0x6b,0xff, + 0x35,0x11,0x78,0x3c,0x32,0xe5,0xe5,0x9e,0x49,0xdd,0xd7,0xe9,0x94,0xa9,0xaa,0xf2, + 0x60,0x9a,0xb0,0x7b,0x77,0x28,0x21,0x03,0x56,0x4e,0x8e,0xcc,0xdc,0xb9,0xb3,0x9e, + 0xd3,0xfe,0x41,0xe0,0xb2,0x6c,0x4a,0x45,0x9b,0x75,0xf1,0xc0,0xf5,0x75,0x3e,0xa3, + 0xbe,0xce,0xf7,0x15,0xac,0xac,0x93,0x33,0x5e,0x84,0x2b,0xa9,0x3d,0x51,0x3b,0x2c, + 0x30,0x27,0x47,0x49,0x58,0xb3,0x85,0xc3,0xc6,0x98,0x7b,0xb5,0x03,0x03,0x89,0x2b, + 0x24,0xaf,0x57,0x9e,0x40,0xbb,0x66,0x5d,0x94,0x6e,0x04,0x3e,0x90,0x6d,0x79,0xa4, + 0xb3,0x36,0xa5,0x4e,0x7d,0x9d,0xef,0xe7,0xc0,0x59,0xc0,0x8c,0xd6,0xe8,0x49,0x2a, + 0x7d,0xb2,0x4d,0x5a,0x59,0x96,0x70,0xb9,0x12,0x7f,0x55,0xe1,0xc1,0x43,0xc9,0x3a, + 0x38,0x98,0x38,0x81,0x3d,0x1e,0x25,0x9d,0x5e,0x65,0x2f,0x70,0x45,0x7d,0x9d,0xef, + 0xf3,0xd9,0x32,0x6d,0x16,0x04,0x3e,0x40,0xe2,0xa7,0x81,0x15,0x40,0x03,0xc9,0xd4, + 0xe0,0x9c,0x05,0x24,0x63,0xdd,0x0d,0x1f,0x64,0x24,0x8b,0xc7,0xcd,0x84,0x3d,0xa8, + 0x24,0x89,0xa4,0x06,0x8b,0x59,0xc6,0xdf,0x81,0x15,0xf5,0x75,0xbe,0x3f,0x67,0xab, + 0x0c,0x67,0x7d,0x56,0xca,0xfa,0x3a,0x5f,0x4f,0x7d,0x9d,0xef,0x53,0x58,0xd5,0x04, + 0x5f,0x4c,0xd5,0xe7,0x74,0x39,0x13,0x7f,0x55,0xd1,0xe8,0x41,0x04,0x8e,0x19,0x09, + 0x6b,0x7e,0x59,0x96,0x26,0xe8,0xfa,0x38,0xa3,0xe3,0x5f,0x23,0x70,0x71,0x7d,0x9d, + 0xef,0xfc,0x6c,0xaf,0xd8,0x20,0xf2,0x42,0x1f,0x20,0xf2,0x4b,0xc0,0x3a,0xe0,0x7d, + 0xc0,0x6b,0xa9,0xf6,0x7c,0xc9,0xb8,0x25,0xc6,0xe3,0xe6,0x11,0xff,0x4e,0xe6,0x3e, + 0x29,0x56,0x0e,0x75,0x27,0x56,0x3a,0xd9,0x63,0xea,0xeb,0x7c,0x0f,0x0a,0xa9,0x15, + 0xa5,0x55,0x0e,0x26,0xb1,0x09,0x3c,0xd0,0xd0,0x14,0xfc,0x1b,0x70,0x06,0xf0,0x75, + 0xe0,0x34,0x52,0xc0,0x5a,0x2f,0x27,0xa1,0x15,0x4d,0x73,0x28,0x2f,0x96,0xf5,0xb7, + 0x6e,0x98,0xd3,0x32,0x50,0xcc,0x20,0xde,0x00,0x7e,0x0a,0xdc,0x53,0x5f,0xe7,0x8b, + 0x09,0x49,0x15,0x04,0x1e,0x8f,0xc8,0x3a,0xf0,0x38,0xf0,0x78,0x43,0x53,0x70,0x19, + 0xf0,0x19,0xac,0xd2,0x1e,0x65,0xb3,0xf5,0x4c,0xc9,0x28,0x42,0xd3,0x34,0x31,0x4d, + 0x73,0x58,0x7b,0x1a,0xc9,0x64,0xa5,0x4c,0x9d,0xd7,0xd0,0x8b,0xb5,0x2d,0x74,0x73, + 0x7d,0x9d,0xef,0x45,0x21,0x95,0x82,0xc0,0x13,0x25,0xf3,0xbb,0xc0,0x17,0x1b,0x9a, + 0x82,0xdf,0xc0,0x4a,0x45,0xfb,0x11,0xac,0xec,0x1e,0xb9,0x33,0x40,0xdb,0x29,0x59, + 0x62,0xa6,0x51,0x45,0xc4,0x18,0xf0,0x14,0x96,0xb7,0xdc,0x83,0xa2,0x4e,0xb0,0x20, + 0xf0,0x54,0x12,0x79,0xd0,0xd6,0x08,0x0f,0xda,0x55,0x00,0xce,0xc1,0xaa,0xd3,0xf3, + 0x5e,0x60,0x5a,0x4a,0x28,0x4c,0x66,0xf9,0x39,0x51,0xd2,0x9a,0x33,0x3f,0x48,0x84, + 0xec,0xd9,0xce,0x83,0xc0,0x43,0xf5,0x75,0xbe,0x0e,0x21,0x6d,0x82,0xc0,0xd3,0x4d, + 0xe6,0x7e,0x2c,0x97,0xbd,0x7b,0xed,0xba,0x3c,0x27,0xda,0xda,0xf9,0x2c,0xac,0x04, + 0xe3,0xf9,0xa2,0x97,0x0e,0x8b,0x41,0xac,0xea,0x8f,0x4f,0xd8,0xc4,0x7d,0x56,0x14, + 0xf1,0x16,0x04,0x9e,0x4d,0x32,0x9b,0xc0,0x4b,0xf6,0xf1,0x3d,0xbb,0x6c,0xcb,0x4a, + 0xac,0x6d,0xa9,0x93,0xed,0xdf,0x27,0x5d,0xf2,0x23,0x8d,0xeb,0x82,0xb7,0x03,0x6f, + 0x61,0x6d,0xd1,0xbd,0x00,0xbc,0x26,0xb4,0xac,0x20,0x70,0x2a,0x13,0xba,0x17,0x78, + 0xd6,0x3e,0x68,0x68,0x0a,0x3a,0xb1,0x8c,0x5f,0xab,0x80,0x95,0xa6,0x61,0x1e,0x27, + 0xcb,0xd2,0x29,0x86,0x61,0xce,0x58,0x9a,0xc6,0x99,0x58,0x03,0xcb,0xd6,0x7c,0x7f, + 0x8f,0x4d,0xd6,0x37,0xed,0xe3,0x15,0x60,0x7f,0x7d,0x9d,0x2f,0x22,0x24,0x43,0x10, + 0x38,0x5d,0x09,0x1d,0x03,0x9a,0x81,0xbf,0xda,0x07,0x00,0x37,0xfc,0xab,0xbd,0x20, + 0x12,0xd1,0x57,0xc6,0x62,0xe6,0x3c,0x49,0x62,0x85,0xae,0x9b,0x95,0xb2,0x2c,0x1d, + 0x6d,0x18,0xe6,0x5c,0x7b,0x0a,0xee,0x65,0x16,0x8c,0xc2,0x63,0x91,0x7d,0xc8,0x98, + 0x0d,0x0c,0x28,0x8a,0xd4,0x27,0x4b,0xd2,0x5e,0x24,0xb6,0x28,0x8a,0xa4,0x29,0x8a, + 0xb4,0x25,0x37,0x57,0xd9,0x59,0x50,0xe0,0x7c,0xfb,0xe3,0xf3,0x0b,0x42,0xe2,0x8d, + 0x0b,0x02,0x67,0x05,0xbe,0xb6,0xa6,0x6c,0x48,0x53,0x1f,0x82,0x9f,0x6f,0x6c,0xf7, + 0x85,0xc3,0x46,0x99,0x2c,0xe3,0xb1,0xb5,0xf7,0x5c,0xd3,0x64,0xae,0x24,0x51,0x25, + 0xcb,0x52,0x0d,0x50,0x62,0x9a,0xe4,0x9a,0xa6,0xe9,0xb0,0x89,0x5e,0x20,0x49,0x92, + 0x17,0x70,0x03,0x4e,0x49,0xc2,0x01,0x0c,0xd8,0x03,0x80,0x64,0x9a,0xe4,0x8d,0x20, + 0x22,0x58,0x41,0x1c,0x11,0x7b,0x3d,0xda,0x63,0x9a,0xf4,0x4a,0x12,0x51,0x59,0x96, + 0x06,0x24,0x89,0x56,0x40,0xb3,0xa7,0xbe,0xed,0x1e,0x8f,0xdc,0x63,0x18,0x68,0x1e, + 0x8f,0xdc,0x5f,0x5c,0xec,0x6a,0xfd,0xe4,0xc2,0xc2,0x7e,0xf1,0xf6,0x52,0x07,0x92, + 0xe8,0x82,0xf4,0xc6,0xff,0xed,0xee,0x97,0x3a,0xda,0xc3,0x8e,0x78,0xdc,0x54,0x0c, + 0xc3,0x54,0x4c,0x13,0xc9,0x34,0x91,0x8a,0x8b,0x9d,0xba,0xed,0x12,0x29,0xb5,0xb5, + 0x46,0x94,0xc1,0xb0,0x2e,0xcb,0xb2,0x64,0xca,0x32,0xc8,0xb2,0x64,0xc8,0x32,0x86, + 0x24,0x49,0xba,0x2c,0x4b,0xb1,0x6f,0x9c,0x3c,0x47,0x17,0x3d,0x29,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x90,0x05,0xf8,0xff,0xbd,0xee,0x3d,0x8e,0x97, + 0x10,0x8f,0xe6,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/png_benchmark/octocat_4bpp.h b/libraries/PNGdec/examples/png_benchmark/octocat_4bpp.h new file mode 100644 index 0000000..d8ba20e --- /dev/null +++ b/libraries/PNGdec/examples/png_benchmark/octocat_4bpp.h @@ -0,0 +1,124 @@ +// +// octocat_4bpp +// Data size = 1808 bytes +// +// PNG, Compression=Flate, Size: 240 x 200, 4-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t octocat_4bpp[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0xc8,0x04,0x03,0x00,0x00,0x00,0x24,0x52,0x71, + 0x61,0x00,0x00,0x00,0x30,0x50,0x4c,0x54,0x45,0x00,0x03,0x00,0x06,0x0a,0x05,0x22, + 0x1e,0x1d,0x45,0x5c,0x65,0x6b,0x57,0x4f,0xad,0x5b,0x53,0xb6,0x75,0x6a,0xa3,0x84, + 0x72,0x67,0x96,0xa8,0xc7,0x9e,0x89,0x7a,0xbb,0xe4,0x83,0xbb,0xcc,0xd9,0xc4,0xc0, + 0x9c,0xd9,0xf0,0xf5,0xca,0xb3,0xfa,0xfc,0xf9,0x45,0x09,0xf7,0x95,0x00,0x00,0x00, + 0x01,0x74,0x52,0x4e,0x53,0x00,0x40,0xe6,0xd8,0x66,0x00,0x00,0x06,0x8e,0x49,0x44, + 0x41,0x54,0x78,0xda,0xed,0xdb,0xbf,0x4b,0x23,0x59,0x1c,0x00,0xf0,0xb9,0x29,0x17, + 0x02,0x9b,0xfc,0x05,0x93,0x17,0x41,0xbd,0xe5,0x8e,0x25,0x36,0x01,0xd9,0x26,0x08, + 0x62,0xb3,0xdd,0x04,0x04,0x59,0xab,0x5c,0xb5,0xec,0x81,0x08,0xc1,0xe6,0x8a,0xd8, + 0x2c,0x1e,0x29,0x4e,0x0c,0x32,0x8d,0xdb,0x2e,0x81,0x34,0x6e,0x6d,0xe9,0xc1,0x36, + 0xa7,0xa7,0x8d,0x44,0xa6,0xb8,0x63,0x55,0x06,0x16,0xad,0x4e,0x38,0x58,0x36,0x37, + 0xf3,0xde,0x9b,0xdf,0xdf,0xc9,0xbc,0x6c,0xbe,0x2f,0x83,0xe7,0xbc,0x46,0x9d,0x17, + 0xdf,0x27,0xdf,0xef,0xfb,0xce,0x7b,0x33,0x13,0x55,0x94,0xbc,0x3d,0xfa,0x46,0x08, + 0xd1,0x64,0xff,0x06,0xd4,0x54,0x42,0xc6,0x1b,0x88,0xfd,0x02,0x16,0x2c,0x2e,0xb3, + 0x97,0xe3,0xc1,0xa2,0x43,0xb9,0xaf,0xd6,0x30,0xa6,0x58,0x5c,0xf6,0xde,0x25,0x2a, + 0x4c,0xc6,0x70,0x71,0x61,0x32,0xc6,0x6b,0x71,0x61,0x4d,0xfc,0xa5,0x04,0xad,0xb6, + 0xc2,0x32,0x74,0x94,0x48,0x84,0x09,0x20,0xb8,0xb6,0x2a,0x15,0x26,0xb1,0x03,0x49, + 0x0d,0x1b,0x16,0x6e,0x39,0x3c,0x35,0x58,0xcb,0xe1,0x1c,0xce,0x4f,0xa7,0x1c,0xce, + 0x0a,0x56,0x1e,0x1a,0xac,0x3d,0x3a,0x38,0xbb,0x39,0xd6,0xb2,0x82,0x49,0x56,0xa7, + 0xd3,0xa4,0x21,0x13,0x92,0x4d,0xc8,0xea,0x43,0x84,0xb5,0x8c,0x32,0x3d,0x51,0xc8, + 0xea,0xc3,0x84,0xb5,0x8c,0x32,0x9d,0x1d,0x4c,0x32,0xca,0x74,0x86,0xb0,0x96,0x51, + 0xa6,0x1f,0x21,0x4c,0x32,0x9a,0xe2,0x1c,0x9e,0x22,0xac,0x65,0x54,0x5b,0xff,0x07, + 0xb8,0x58,0x22,0xc5,0x22,0x7c,0x9c,0x14,0xe5,0xc1,0xcb,0x2d,0xc3,0x69,0xfb,0xad, + 0xd6,0xd2,0x52,0x9d,0x1f,0x9b,0x59,0x5a,0x6a,0xb5,0xb6,0xd8,0xf1,0xcd,0xba,0x14, + 0x78,0xd9,0x48,0x6f,0x9b,0x12,0x60,0xdb,0x3d,0xb8,0x65,0x2d,0xe6,0xf1,0xe3,0x96, + 0x61,0xec,0xa1,0xc3,0xb3,0x1e,0xeb,0x35,0xc3,0x88,0x1d,0xb3,0x8c,0x0d,0x6c,0x38, + 0xee,0x82,0xcd,0x32,0xea,0xb8,0xf0,0x8a,0x98,0x6b,0xcb,0x7b,0xa8,0xf0,0x8c,0x71, + 0x2b,0xda,0x82,0x21,0x4f,0x0e,0xcf,0x1f,0x08,0xc3,0xc1,0x90,0x27,0x87,0xb7,0x6e, + 0xc5,0x9b,0x81,0x08,0xcf,0xf2,0x80,0xef,0x86,0xc3,0xaf,0x49,0x9e,0xd7,0x67,0x6d, + 0xe0,0xc1,0x2b,0xde,0xd8,0x89,0x72,0xa0,0x6f,0x1f,0x0f,0xe6,0x01,0x0f,0x69,0x83, + 0xe1,0x40,0x9f,0x55,0xc7,0x82,0x79,0xa6,0xef,0xd8,0xe0,0x5f,0x13,0x03,0x76,0xfb, + 0x36,0xb0,0xe0,0xf9,0x60,0x50,0x70,0xc8,0xa1,0xbe,0x3d,0x2c,0xf8,0x17,0x6f,0xf0, + 0x8f,0x3f,0xbd,0x4b,0x82,0x69,0x17,0xeb,0xbb,0xc1,0x82,0xbd,0x4c,0x7f,0xd1,0x75, + 0xfd,0x04,0xca,0xf5,0x1d,0xef,0x62,0x7d,0x16,0x12,0x3c,0xe3,0xc1,0xc7,0xf6,0xe8, + 0x6b,0x30,0xcc,0xba,0x78,0x5f,0x1d,0x07,0x9e,0xf5,0xa2,0x5a,0xed,0xda,0xc3,0x43, + 0xf0,0xc9,0x17,0xbd,0xe9,0x74,0x45,0xaa,0xeb,0x1b,0x61,0x35,0x0c,0x0f,0x87,0xff, + 0x9e,0x38,0x09,0x7d,0x07,0x4c,0xf2,0xf0,0x7e,0x6d,0xd8,0x74,0xba,0x58,0xdf,0x2e, + 0x0e,0xec,0x15,0xf5,0x3f,0xc3,0xa1,0x0d,0xaf,0x43,0xf0,0xf1,0xba,0x93,0xec,0x75, + 0x0e,0x7f,0xc2,0x81,0x7f,0x74,0xe1,0x63,0x0a,0xaf,0x25,0xc0,0x5d,0x3a,0xc9,0x52, + 0xe0,0xee,0xeb,0xdf,0x6d,0x78,0x15,0x82,0x9b,0x8d,0x8f,0xb4,0x4b,0x0e,0xec,0xd4, + 0x8f,0xae,0x37,0x40,0x98,0x77,0x85,0xe1,0x09,0x6f,0x53,0x19,0xfc,0x79,0x04,0xfc, + 0x79,0xa8,0xbb,0xf0,0x1f,0x32,0x60,0x3d,0x13,0x38,0xb3,0x54,0x7b,0xf0,0x6a,0x32, + 0xbc,0x8a,0x04,0xab,0x91,0xf3,0xf8,0x98,0x8e,0x0e,0x9e,0x4e,0x5d,0xde,0xc5,0xfa, + 0xfe,0x9e,0xf0,0x19,0x08,0x0c,0xc3,0x0b,0x08,0xef,0x62,0x7d,0x7f,0x8d,0x0d,0x83, + 0xf7,0xe2,0xde,0x92,0x79,0x4f,0x47,0xff,0x19,0x5c,0x32,0x79,0x17,0xeb,0xfb,0x6d, + 0xac,0xe7,0x03,0x40,0x1f,0xdf,0x9d,0xf8,0x46,0x40,0xb7,0x3e,0x7b,0xf3,0x83,0x37, + 0x09,0x3d,0xb0,0x65,0xee,0xc2,0x11,0x03,0x82,0x0a,0xe7,0x85,0xbf,0x55,0xef,0xea, + 0xa6,0x4b,0x0b,0x08,0xdc,0x16,0x59,0x57,0x78,0x77,0x4a,0x08,0x2f,0xf8,0x93,0x36, + 0x32,0xf3,0xde,0x7e,0x7c,0x4f,0x37,0x27,0x10,0x66,0x5d,0xe1,0xfd,0x38,0x71,0x3e, + 0x45,0xa7,0xdc,0xbf,0xf4,0x39,0xd6,0x5f,0x27,0x5d,0xfa,0xd0,0x2e,0xde,0x37,0xc9, + 0xd9,0x14,0xac,0x8a,0x97,0x63,0x5e,0xec,0x59,0xdf,0xf8,0xcc,0x29,0xf0,0xea,0xd0, + 0xf9,0x14,0xbd,0xbc,0xb5,0xf4,0x37,0xf0,0xe5,0xed,0x4d,0xa8,0xb6,0x54,0xd1,0x3f, + 0x42,0xd3,0x62,0xb9,0x9e,0xb9,0x05,0x2f,0xe8,0xaf,0xf4,0x06,0x78,0x41,0xef,0xae, + 0x1f,0x02,0xd5,0xeb,0xf7,0x8e,0xaa,0xae,0xe8,0x2d,0x4c,0x37,0x08,0x07,0xfb,0x76, + 0xe1,0x1c,0x27,0xd9,0x60,0x3e,0x42,0x93,0x1c,0xb9,0x69,0xbb,0xd2,0x57,0xa1,0x9b, + 0x36,0xb7,0xa8,0x35,0x91,0xc8,0xec,0x43,0xda,0x88,0xba,0x9e,0x87,0xef,0x84,0x9b, + 0x6f,0xe0,0xe3,0xa3,0x8a,0x2a,0x72,0x3c,0x79,0x02,0x42,0xb9,0x16,0x6b,0x9f,0xd2, + 0x56,0x48,0xff,0x7b,0x2d,0xed,0xb4,0x7a,0x39,0x0e,0xbc,0x91,0xb6,0x43,0x68,0xe2, + 0xdb,0xc6,0xcc,0x18,0xae,0x85,0xfa,0x91,0x79,0x3c,0xe4,0x6b,0x67,0x82,0xad,0x57, + 0x71,0x78,0x17,0xe9,0x8f,0x04,0x92,0x42,0xbe,0x76,0x4a,0xfa,0xfa,0x95,0xb4,0x80, + 0x23,0xab,0x57,0xa0,0xe9,0x76,0xc5,0x35,0x0f,0xa4,0x05,0x9c,0x9c,0xec,0xab,0x86, + 0xd1,0x6d,0xc4,0xdc,0x1b,0xb4,0x80,0xa3,0x7b,0x94,0xdf,0x9a,0x7a,0x23,0x16,0xb0, + 0x55,0xc7,0x0b,0xd8,0xdb,0xa9,0x62,0xb2,0x95,0x74,0x2a,0xe1,0x04,0xec,0xcb,0x2b, + 0xa9,0x67,0x12,0xb2,0xeb,0xc9,0xb3,0xa3,0x57,0xb0,0xfd,0x3a,0xb6,0xeb,0xc9,0xe5, + 0xe5,0xe4,0xa7,0xa9,0xc6,0x66,0x89,0x60,0x4e,0x70,0xec,0x8a,0x64,0x79,0xeb,0x00, + 0x78,0x4c,0xdd,0xaa,0xa3,0xfd,0x95,0x4f,0xf2,0xb5,0x50,0xb9,0x34,0xb3,0xdc,0xf2, + 0xdb,0xe6,0x52,0xb9,0x84,0xfb,0xa7,0x6b,0xda,0xf8,0x1f,0xbc,0x69,0x38,0x01,0x6a, + 0xe3,0x7e,0xe6,0x87,0xb4,0x6a,0x2c,0xb6,0xb5,0x71,0x3e,0x6e,0xc4,0x5b,0x35,0x16, + 0x0f,0x89,0xf8,0x07,0x7f,0x68,0xc5,0x44,0x83,0xab,0x40,0xe3,0x7d,0x57,0x8c,0x35, + 0xd4,0x32,0x76,0xe4,0xa3,0x36,0x90,0xbf,0x62,0x51,0xaa,0x7c,0xea,0xc8,0x9d,0x3f, + 0x35,0x30,0xe0,0x52,0xf0,0x03,0x4d,0xa7,0x3d,0xc5,0x84,0xed,0xe9,0xac,0x54,0xe3, + 0xb9,0x8e,0x7f,0x6a,0x5a,0x46,0x0d,0xd9,0xe4,0xd3,0x2c,0x52,0xd8,0x65,0x44,0xb8, + 0x60,0xb2,0x0a,0x36,0xab,0x22,0x55,0x5d,0xc6,0xcb,0x35,0x85,0xed,0xe8,0xcc,0x43, + 0xa1,0xd3,0x09,0x2f,0xe4,0x82,0x79,0x4a,0x95,0x4e,0x5b,0x6c,0xe1,0x2c,0xa2,0x46, + 0xac,0xc4,0x97,0x86,0x24,0xb8,0xfc,0x14,0x15,0x8e,0xdf,0xdb,0x12,0xd9,0xb0,0xef, + 0x98,0xcf,0x45,0x60,0x22,0x01,0x3e,0xd4,0x44,0xe0,0xb2,0x82,0xbd,0x6e,0x76,0x42, + 0x5b,0xc5,0x14,0xe1,0xd0,0x22,0x32,0xe2,0x9f,0x9f,0x24,0x5c,0xf1,0xcc,0xb5,0x89, + 0xfb,0x36,0x4a,0x53,0x85,0x3b,0x97,0xee,0x3f,0x8f,0x75,0xaa,0x53,0x83,0x9d,0xb1, + 0x9f,0x5d,0x92,0xb9,0x6d,0x42,0x6a,0x55,0x72,0xc4,0x61,0x35,0x08,0x6b,0xf2,0xae, + 0x2e,0x17,0xc8,0x0b,0xb3,0x5a,0x31,0xcf,0x49,0x8d,0x5f,0xe4,0x40,0xb0,0xa6,0xc8, + 0x28,0xaf,0x67,0x0e,0x7c,0x46,0xf8,0x1c,0x47,0x60,0x55,0x0a,0xec,0x17,0x72,0x85, + 0xb8,0xb0,0x32,0x15,0x38,0x54,0x41,0xd3,0x84,0x95,0xcc,0x60,0x35,0x0d,0x56,0x24, + 0xc1,0x41,0x79,0xba,0x70,0x40,0x2e,0x31,0x62,0x5a,0xb0,0x3f,0xcf,0xea,0xb4,0xe1, + 0x50,0xec,0x39,0x9c,0xc3,0x39,0x9c,0xc3,0x39,0x9c,0xc3,0x89,0xf0,0x9c,0x79,0x48, + 0xa9,0xa3,0x33,0xfa,0xa5,0x63,0x96,0x32,0x85,0x9f,0xcb,0x74,0x99,0x08,0xc3,0x1d, + 0xfa,0x0c,0x41,0x46,0x2b,0x98,0xe6,0x68,0xd8,0x6e,0x92,0xd8,0x74,0x18,0x9f,0x66, + 0xa3,0x0a,0xc0,0xb8,0x09,0x2f,0x98,0xe2,0x30,0x66,0xd0,0x9e,0x2b,0x06,0xa3,0x05, + 0xed,0x8f,0x28,0x08,0x23,0xc9,0x66,0x2a,0x4c,0xbf,0xfc,0x60,0x22,0xcb,0xc1,0xf1, + 0xcc,0x36,0xbb,0x67,0x8d,0xc0,0x55,0x76,0x14,0x57,0x2e,0x84,0xc6,0xe3,0xb1,0x45, + 0x60,0xfa,0x76,0x2a,0xa1,0x17,0x9a,0xb8,0xee,0x05,0x95,0x5e,0x44,0x61,0xfe,0x23, + 0xaa,0x1c,0x1e,0xcc,0x15,0x22,0xf0,0x19,0x7f,0x3f,0x88,0xc9,0x0e,0x07,0x7c,0x49, + 0x78,0x4e,0x23,0xf0,0x05,0x01,0x72,0x6d,0x22,0x06,0xdc,0xe6,0xcf,0x43,0xa2,0x30, + 0xab,0x2e,0xb2,0x88,0x17,0x72,0x38,0xe0,0x6d,0xe2,0xce,0x65,0x14,0x3e,0x67,0x3d, + 0xbf,0xa2,0x85,0x1c,0x82,0xf9,0xe8,0x8b,0xfe,0x5c,0x9f,0x7b,0x73,0xdb,0x26,0x40, + 0x7d,0xa1,0x9e,0xc3,0xf6,0xea,0xe1,0xc1,0xa6,0x0f,0x5f,0x56,0x81,0xfa,0x3a,0xc5, + 0x84,0x6b,0x7d,0x0f,0xae,0xf0,0xa2,0xa2,0x4b,0xd6,0xa0,0x1a,0x5d,0x36,0xf1,0xe0, + 0x8b,0x85,0x85,0xb7,0x3b,0xbd,0x9e,0xf7,0x1e,0xe6,0x78,0x95,0x3b,0x4b,0xd6,0xa0, + 0xd7,0x7b,0xff,0x76,0xa1,0x66,0x4a,0x81,0x9d,0xd1,0x9d,0xe6,0x2f,0x60,0xac,0x9a, + 0x9d,0xd3,0x88,0xf5,0xf4,0xd1,0x4e,0x28,0x13,0x92,0xfb,0x3c,0xc5,0x76,0x25,0x9d, + 0xf1,0x6f,0x06,0xa0,0x8b,0x07,0xf3,0xc0,0xdc,0x4c,0x9b,0x5e,0xae,0xbd,0x54,0xc8, + 0x49,0xb5,0x1b,0xf2,0x07,0xbf,0x82,0x59,0x79,0xef,0xc0,0x01,0xa3,0xc3,0x74,0x66, + 0xe7,0xfa,0xfe,0xae,0xf1,0x3d,0x18,0xf0,0x24,0x70,0x01,0xcc,0x35,0xad,0xa8,0x1d, + 0x0a,0xf7,0xde,0xd3,0x37,0x01,0xc3,0x78,0x6b,0x35,0x87,0xab,0x8e,0xcb,0x20,0xfb, + 0x2c,0xaa,0xf2,0x88,0xfb,0x52,0x61,0x9a,0xeb,0xf7,0x0b,0x35,0x1e,0x21,0xfd,0x71, + 0xbb,0x86,0x3e,0xc5,0xf1,0x5c,0x0f,0x18,0xe1,0x4a,0x6c,0xce,0x4d,0xec,0x93,0x09, + 0x90,0x23,0x70,0x6f,0x04,0x3c,0xe9,0x55,0x57,0x3a,0xdc,0x07,0xe1,0x89,0xaf,0xf6, + 0x0a,0x89,0x70,0x6f,0x24,0x8c,0x79,0x1b,0xe1,0xc3,0x83,0x54,0x18,0xf7,0x06,0x46, + 0x1c,0xc6,0xbe,0x75,0x12,0x85,0xf1,0x6f,0xda,0xc2,0xf0,0x20,0x01,0xc6,0xbf,0x3d, + 0x16,0x82,0x71,0x9f,0x48,0x14,0x84,0x61,0x39,0xcf,0x22,0x52,0x61,0x29,0x0f,0x60, + 0x0a,0xa9,0xb0,0xac,0xe7,0x3e,0x8a,0x32,0x12,0x96,0xfa,0x84,0x4d,0x79,0x92,0x00, + 0x2b,0x53,0x69,0x4f,0x42,0xb0,0x92,0xb7,0xbc,0x41,0xed,0x3f,0x1b,0x02,0x27,0x36, + 0x4c,0x35,0x9c,0x68,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/png_benchmark/octocat_8bpp.h b/libraries/PNGdec/examples/png_benchmark/octocat_8bpp.h new file mode 100644 index 0000000..6318cfb --- /dev/null +++ b/libraries/PNGdec/examples/png_benchmark/octocat_8bpp.h @@ -0,0 +1,124 @@ +// +// octocat_8bpp +// Data size = 1800 bytes +// +// PNG, Compression=Flate, Size: 240 x 200, 8-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t octocat_8bpp[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0xc8,0x08,0x03,0x00,0x00,0x00,0xe1,0xa2,0x9c, + 0x60,0x00,0x00,0x00,0x33,0x50,0x4c,0x54,0x45,0x57,0x61,0x77,0x09,0x08,0x06,0x22, + 0x1e,0x1d,0x2d,0x2d,0x2d,0x44,0x5c,0x67,0x6a,0x57,0x4d,0xad,0x5b,0x52,0xb7,0x74, + 0x6a,0xa2,0x84,0x73,0x6a,0x95,0xa8,0xc7,0x9e,0x8a,0x7b,0xbb,0xe4,0x85,0xbb,0xcc, + 0xdc,0xc3,0xc0,0x9c,0xd9,0xf1,0xf5,0xca,0xb3,0xfd,0xfb,0xf7,0x24,0xdc,0x40,0xfd, + 0x00,0x00,0x00,0x01,0x74,0x52,0x4e,0x53,0x00,0x40,0xe6,0xd8,0x66,0x00,0x00,0x06, + 0x83,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0xdd,0xe1,0xb6,0x9b,0x20,0x0c,0x00,0x60, + 0x05,0xac,0x42,0x95,0xbb,0xf7,0x7f,0xda,0x29,0xb6,0x0a,0x08,0x08,0x8a,0xc7,0x60, + 0x93,0x1f,0xdb,0xb9,0xab,0x74,0xf9,0x1a,0x04,0x44,0xbb,0x55,0x15,0x06,0x06,0xc6, + 0x4f,0x07,0x99,0xa3,0xf8,0xbf,0x23,0x31,0x97,0x0b,0x13,0xba,0xfc,0x2f,0x38,0x0e, + 0xbe,0x20,0xa3,0x8b,0xdf,0xfe,0x74,0x46,0x99,0x93,0xba,0xf4,0xcd,0x33,0xa5,0x94, + 0x2f,0xab,0x0b,0xdf,0x3a,0x73,0x56,0x59,0xf2,0xba,0xec,0x8d,0x2f,0xc9,0xeb,0x7c, + 0x66,0xa4,0x34,0x30,0xb9,0xe6,0x5d,0x09,0x58,0xaf,0x2b,0xb7,0xd8,0x63,0x93,0xde, + 0x14,0x10,0x98,0x44,0x1e,0x66,0x37,0x20,0xc5,0x82,0x55,0x7a,0x24,0x6f,0x00,0x07, + 0xe7,0x0f,0x04,0x23,0xf8,0x61,0x60,0x82,0x60,0x04,0x23,0x18,0xc1,0x38,0x4a,0x23, + 0x18,0xc1,0x08,0xfe,0x15,0x70,0x85,0xe0,0x87,0x7b,0x11,0x8c,0x5d,0x1a,0x87,0xe9, + 0xb2,0xc5,0x84,0xfc,0x96,0x98,0x90,0xdf,0x12,0x13,0x04,0x3f,0x5b,0x4c,0xc8,0x6f, + 0x89,0x09,0x82,0x9f,0x2d,0x26,0x08,0x7e,0xb6,0x98,0x20,0xf8,0xd9,0x62,0x82,0x60, + 0x04,0x3f,0x4a,0x4c,0x10,0x8c,0x60,0x04,0x97,0x2c,0x26,0x08,0x46,0xf0,0x18,0x75, + 0x5d,0xcf,0xbf,0xd6,0xf1,0xc7,0xd3,0x31,0x22,0x8f,0x07,0x05,0xa6,0x4d,0xd7,0x75, + 0x62,0x8d,0x6e,0x8a,0x66,0x0a,0xaa,0x42,0x1d,0xa3,0x42,0xfd,0xa1,0x7a,0x59,0x18, + 0xc7,0x8f,0x47,0x16,0x03,0x6e,0x8c,0xdc,0x8f,0x47,0xd7,0x14,0x01,0xfe,0x70,0xff, + 0xcc,0xd8,0xe7,0x39,0x1b,0x34,0xe0,0xc1,0xb4,0xdb,0xe6,0xbe,0x0d,0xb7,0xd1,0x75, + 0x58,0x47,0x61,0x83,0x69,0x0c,0x37,0x21,0x42,0x45,0x86,0x00,0x6e,0xf2,0x72,0x67, + 0x72,0x03,0x17,0x7c,0x81,0x37,0x20,0xbe,0x1f,0x4c,0xaf,0xf0,0xfa,0xc5,0xb7,0x83, + 0xc7,0xf1,0xea,0xef,0xef,0x1a,0x31,0x05,0x09,0xb6,0xbd,0xff,0x54,0xa4,0xfb,0xb6, + 0xed,0x44,0x07,0x11,0xdc,0x08,0x47,0xda,0xe9,0x64,0x67,0x3b,0xa7,0xf8,0x66,0x30, + 0xf5,0x79,0xd3,0xc4,0x9e,0x76,0xae,0xd3,0xf8,0x66,0xb0,0xd9,0xa1,0xff,0xfd,0x3b, + 0x26,0xf6,0xb6,0xeb,0xa0,0x81,0x69,0xc0,0x1b,0x2f,0xf6,0xb7,0x73,0x94,0xf8,0x5e, + 0x70,0xe7,0x48,0x7c,0x10,0x6d,0x2b,0x92,0xc1,0x6b,0xab,0x9d,0x12,0xdf,0x0b,0x76, + 0x14,0x78,0x78,0xa9,0x18,0xe2,0xc5,0x76,0x2b,0xa3,0xc4,0x14,0x14,0xb8,0xd9,0x82, + 0x3f,0x99,0xcf,0xb9,0x47,0x83,0x8d,0x56,0x46,0xbb,0x06,0x14,0xb8,0x73,0x54,0x4a, + 0x88,0x4f,0xee,0xb1,0xe0,0x41,0x79,0xdb,0xb5,0x55,0xb8,0x4f,0xdf,0xba,0x6b,0xd9, + 0x6d,0x0a,0x2c,0x86,0xa5,0x5c,0x22,0x52,0x3c,0x1e,0xd6,0x4e,0x95,0x6d,0x97,0x56, + 0x46,0x9f,0x06,0x05,0xde,0xf6,0x68,0x55,0xa1,0xb4,0x12,0xab,0x4f,0x68,0xed,0xd6, + 0x7b,0x7d,0xfa,0x56,0xb0,0xa3,0x47,0x6b,0xe0,0x21,0x0d,0x2c,0xdc,0xa3,0x1d,0x6c, + 0xb0,0x78,0xb5,0xc3,0xf0,0x3d,0x1d,0x45,0x2c,0x78,0x6c,0xd0,0x0e,0x62,0x6d,0x05, + 0x16,0x4c,0x37,0xe0,0xaf,0x55,0x45,0x9b,0x00,0x36,0x5a,0x85,0xc0,0xf7,0xde,0x2e, + 0xb5,0x06,0xdb,0x43,0xe0,0x61,0x39,0x05,0x34,0xf0,0x50,0x0a,0xf8,0xf5,0x43,0xe0, + 0x9f,0xeb,0xd2,0x5b,0xb0,0x38,0x04,0x16,0xa0,0xc0,0xd5,0xce,0x3c,0x3c,0xe8,0xa9, + 0x47,0x4f,0x4b,0xc2,0x6a,0x65,0xb4,0xa3,0xf7,0x3e,0xb7,0x94,0x02,0x4e,0x59,0x78, + 0x18,0xad,0x8c,0x76,0xf5,0xf5,0xe0,0xf8,0x5b,0x97,0xdb,0xa5,0x65,0x6b,0x9e,0x8c, + 0xd1,0x4b,0x4b,0xf3,0x14,0xd6,0x97,0x96,0x75,0x7c,0x3a,0x07,0x9d,0x09,0x9f,0x46, + 0xb3,0x19,0xa6,0x87,0xe4,0x1e,0xfd,0x37,0xd8,0xad,0xcc,0x5d,0x9e,0x24,0x53,0x8a, + 0xe1,0x48,0xf9,0xb7,0x2b,0x8f,0xf5,0x7c,0x14,0x29,0x97,0x87,0x46,0xab,0xc0,0xd5, + 0x52,0x5a,0xf1,0x7c,0x2f,0x9d,0xe8,0xf0,0x8e,0x0d,0x80,0xd6,0x3d,0xd8,0xee,0x6c, + 0x00,0xe8,0xad,0x02,0x83,0x74,0x7a,0xa7,0xcd,0x7c,0x86,0x3b,0xb7,0x78,0xa6,0x33, + 0x71,0x48,0xde,0xe2,0x59,0x5a,0x99,0xed,0x6e,0x9a,0x94,0xbc,0xb7,0xd1,0x22,0x37, + 0xe3,0x8e,0x6e,0xe2,0x6d,0x2f,0x87,0x2f,0xc5,0xbb,0xdf,0xda,0xdf,0xa7,0x77,0xb7, + 0x69,0xc7,0x53,0xb5,0x4d,0xda,0xa6,0x0d,0x9e,0xc2,0x19,0xe9,0xe1,0xf7,0xf1,0x97, + 0x78,0x6f,0x23,0x5e,0xcd,0x3b,0x09,0x1b,0xf1,0xd6,0xb2,0x23,0xcf,0xb0,0xeb,0x68, + 0x7a,0x78,0xd8,0xda,0xb9,0xd5,0x22,0xbc,0x60,0x5f,0x3b,0x91,0xd4,0x89,0x13,0xd9, + 0xf1,0x47,0x07,0x4a,0x1c,0xbe,0x99,0xa6,0x06,0xe2,0xe8,0x9b,0x69,0xf6,0x18,0x9d, + 0xaf,0x64,0x55,0x6a,0x87,0x08,0x94,0x38,0x7c,0x07,0xb4,0xf5,0x14,0xd8,0x77,0xfc, + 0xd1,0x41,0x6a,0xef,0x04,0x38,0x33,0x6a,0xd3,0x8b,0x6e,0x0f,0x1f,0x2c,0xf0,0x2e, + 0x9a,0x9c,0x9e,0xa6,0x9a,0xcb,0xbc,0xdd,0xe9,0x59,0x88,0x5c,0x32,0x31,0x5f,0x25, + 0x16,0xb7,0x5e,0x17,0x9e,0x16,0xb7,0xed,0x3a,0x58,0xc7,0x79,0x29,0x24,0x6f,0xba, + 0xb8,0x5d,0xc6,0xe7,0xf6,0x55,0xa2,0xd7,0x14,0xc7,0x8c,0x5c,0xdf,0x19,0xa9,0x7d, + 0x89,0x22,0xbd,0xe9,0x45,0x1e,0x17,0x1d,0x42,0xf8,0x56,0x97,0xd9,0xc7,0xab,0xeb, + 0x8b,0xdc,0x45,0xf4,0xea,0x69,0xa5,0x15,0x51,0x5f,0xd1,0xc0,0xf4,0xda,0xdb,0x01, + 0x5d,0x04,0x25,0x79,0x3a,0x02,0xe5,0xdd,0x5c,0x38,0x36,0xe7,0x57,0x21,0xd6,0x93, + 0xb4,0x15,0xbc,0xd8,0x79,0x50,0x2d,0x51,0xdb,0x10,0xe0,0x5c,0x07,0xb9,0x9e,0x1e, + 0x16,0x3f,0xf2,0xa8,0x61,0xd7,0xd4,0xa4,0x04,0xaf,0x73,0x47,0x84,0x4e,0xdf,0x7f, + 0x88,0x73,0xcf,0x5f,0x76,0xb8,0xf5,0xe9,0x95,0x7c,0x9b,0x40,0xd3,0x37,0x56,0x3e, + 0xdf,0xe6,0x70,0xc4,0xf4,0xed,0x0f,0xcf,0x97,0x59,0xa0,0x78,0xf2,0x6c,0xe0,0xc3, + 0xfd,0x37,0x4a,0x1c,0x96,0x5c,0x77,0x2d,0x00,0x6b,0x35,0x08,0xeb,0x79,0xe4,0x4e, + 0x4b,0xc1,0x56,0x5d,0xc1,0xfa,0x3e,0x32,0xaf,0x92,0xad,0xba,0x80,0x52,0x42,0x59, + 0x74,0x7a,0x75,0x4c,0x80,0x1f,0x88,0x7b,0xc9,0x23,0xc5,0x75,0x64,0x80,0xd4,0xca, + 0x85,0xcc,0xa5,0xac,0x49,0x8a,0xd7,0xff,0x25,0x4b,0xc8,0x62,0xb9,0x16,0x99,0xb1, + 0xa8,0x73,0x2e,0xea,0xdb,0xa2,0x70,0xc5,0x52,0xea,0xdd,0x7a,0x3c,0x95,0x73,0x8d, + 0x5a,0x40,0xc1,0xf2,0x03,0x9e,0x1d,0x54,0x4a,0x96,0x6f,0x42,0x06,0x29,0x5e,0xc0, + 0xb3,0x44,0xca,0x3e,0xe3,0x0a,0x04,0xa2,0x58,0x9a,0x62,0xbe,0x37,0x52,0x27,0xce, + 0xc2,0x20,0xc1,0x5b,0x4b,0xc6,0x75,0x07,0x38,0xb1,0x06,0x5e,0x07,0xae,0x8c,0xab, + 0x4b,0xc8,0xeb,0x0f,0x6d,0xe0,0xca,0xb8,0x9c,0x2e,0x02,0xdc,0x7b,0x7b,0x35,0x79, + 0xa2,0x98,0x4b,0xff,0x85,0xc4,0x23,0xc1,0xfe,0x91,0x2b,0x78,0x4d,0x54,0xd0,0xf5, + 0x92,0x83,0x44,0x39,0xa7,0xdb,0xff,0x09,0xac,0x7e,0x2e,0x98,0xab,0x13,0x99,0x18, + 0xff,0x0d,0x18,0x97,0xec,0x79,0xe0,0x65,0x6a,0xea,0x65,0x3f,0x96,0x98,0x73,0x65, + 0x64,0xea,0xb7,0xde,0x02,0x57,0x7e,0x70,0x55,0x0e,0x78,0x49,0x75,0xba,0x74,0x62, + 0x72,0x5a,0x5b,0x2f,0xbf,0x71,0xeb,0xd6,0x41,0x24,0xb8,0xa0,0x7d,0xd9,0xb1,0xce, + 0x5f,0xb0,0xb2,0xd6,0xd1,0xe0,0x92,0x4a,0x6c,0xde,0x3a,0x9c,0xff,0x5d,0x21,0x36, + 0xd7,0xb6,0xf6,0x12,0x8b,0x06,0xfb,0x87,0x9f,0xa7,0x82,0xab,0x9f,0x03,0x57,0xe7, + 0xc1,0x55,0x59,0x60,0x0f,0xf9,0xc9,0x60,0x27,0xb9,0x36,0x11,0x0f,0x03,0x3b,0xcc, + 0xd5,0xd3,0xc1,0x81,0x4f,0x00,0xc1,0x08,0x46,0x30,0x82,0x11,0x8c,0x60,0x04,0x23, + 0x18,0xc1,0x08,0x46,0x70,0x2e,0x30,0x7d,0x36,0x78,0xd9,0xb8,0xfe,0x3e,0x01,0x24, + 0xa9,0xf1,0xa2,0xac,0x7f,0x17,0xcc,0x4a,0xd5,0x1a,0xc4,0x04,0x30,0x97,0xfa,0x4d, + 0xe8,0x52,0xac,0x2a,0x4e,0x80,0x65,0x39,0x6a,0xb9,0xc6,0x59,0x70,0x01,0x68,0x23, + 0xd7,0x2c,0x60,0xc8,0x66,0x3b,0xd1,0x5c,0x60,0xa0,0x66,0x47,0x9a,0xf9,0xc0,0xe0, + 0xcc,0xee,0x1c,0xb3,0x82,0x21,0x91,0x7d,0x19,0xa6,0x80,0xd7,0x1f,0xa9,0x94,0xb0, + 0xc9,0xfe,0xfc,0xb8,0x21,0x0c,0x83,0x99,0xf1,0x22,0x64,0x72,0x20,0x3b,0xb3,0x6a, + 0x61,0xb0,0xf6,0xe1,0x30,0x09,0x58,0x1c,0xca,0xcd,0x32,0x84,0xc1,0xd6,0xab,0x50, + 0xc9,0xa1,0xc4,0x7a,0x6a,0x12,0xc2,0x60,0xfd,0xe7,0x60,0x89,0x6f,0x15,0xc7,0x7a, + 0x99,0xdc,0x07,0x6b,0xfd,0x01,0xac,0x38,0xd8,0x9f,0xa9,0xf9,0xec,0xc7,0x2e,0xd8, + 0x78,0xe6,0x87,0x81,0xec,0xd5,0x21,0x2e,0x23,0xb6,0x77,0x17,0x6c,0x88,0x29,0xef, + 0xe1,0x89,0xfd,0xf9,0x18,0x0f,0x68,0x7d,0xab,0x65,0x81,0xd9,0xb6,0x07,0x73,0xb2, + 0xfd,0x98,0x00,0x81,0xa3,0x86,0xe7,0xb1,0x54,0x8e,0x65,0x08,0x95,0x4e,0xb0,0xec, + 0x19,0x01,0x3c,0x3b,0xc5,0x80,0x19,0x7f,0xbb,0xd6,0x5d,0xcc,0xfc,0x54,0xb4,0xb5, + 0xd5,0x9b,0xd1,0xdd,0x25,0x26,0x3c,0xf0,0x78,0x0a,0x8f,0xc1,0x39,0x7f,0x4f,0xe1, + 0xa8,0xbb,0x6f,0xe2,0x55,0xc7,0xbf,0xc7,0x86,0x53,0x73,0x59,0x10,0xf8,0x9b,0xfa, + 0x27,0x5c,0xeb,0x2e,0x57,0x9f,0x76,0x34,0x82,0x24,0xde,0xc9,0xc8,0x4e,0x9e,0x6f, + 0x0a,0x6a,0x2d,0x4c,0x64,0x02,0x17,0x22,0xd8,0xca,0x9f,0x6f,0x66,0x21,0x63,0x14, + 0xeb,0xe1,0x7b,0x77,0xc1,0xba,0xa0,0x77,0x8d,0xc9,0xc6,0x62,0x8c,0x27,0x79,0xc1, + 0x83,0x99,0x2e,0x73,0x2f,0xc7,0x92,0xbc,0xd0,0x26,0xe2,0x8d,0x98,0x6a,0xf3,0xd4, + 0x5b,0x7f,0x7d,0x25,0x73,0xe8,0x05,0x4e,0x3a,0x8b,0xd9,0xca,0xd5,0x40,0xf3,0x24, + 0x34,0xbf,0x46,0xe1,0x17,0x38,0xa9,0xc4,0x6a,0x66,0xb5,0x44,0xfa,0x8b,0xfc,0x5d, + 0x40,0x81,0x53,0x4a,0x6c,0x9e,0xd2,0x9b,0x73,0xdc,0xf1,0x2a,0xd0,0x2d,0x80,0x13, + 0xe0,0xf7,0x51,0x30,0xdc,0x3d,0x9e,0x68,0xb0,0x4c,0x00,0x43,0xde,0xc4,0xf3,0x82, + 0xdf,0xc7,0xc1,0xb0,0xf7,0x69,0x43,0xc2,0x43,0x60,0xe8,0x3b,0xf1,0x99,0xc1,0xf0, + 0xef,0xb5,0x64,0x05,0x17,0x70,0x33,0x4d,0x46,0x0a,0x63,0xc0,0x65,0xdc,0x2f,0xcd, + 0x05,0xae,0xe0,0xc6,0x05,0xe0,0x0a,0x7c,0xe4,0x04,0x57,0xa5,0x44,0x0e,0x70,0x55, + 0x5c,0x1c,0x07,0x57,0x05,0x47,0x22,0xb8,0x7a,0x50,0x04,0xc0,0x15,0x06,0x06,0x06, + 0x46,0x54,0xfc,0x07,0xb6,0x73,0x07,0x23,0xe6,0xe8,0x7b,0x79,0x00,0x00,0x00,0x00, + 0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/png_benchmark/png_benchmark.ino b/libraries/PNGdec/examples/png_benchmark/png_benchmark.ino new file mode 100644 index 0000000..4ed09cb --- /dev/null +++ b/libraries/PNGdec/examples/png_benchmark/png_benchmark.ino @@ -0,0 +1,97 @@ +// +// PNG decoder benchmark +// +// Runs images through the PNG decoder without displaying the pixels +// to measure the execution time on various Arduino boards +// +#include +#include "octocat_4bpp.h" +#include "octocat_8bpp.h" +#include "octocat_32bpp.h" + +PNG png; // statically allocate the PNG structure (about 50K of RAM) + +// simple private structure to pass a boolean value to the PNGDRAW callback +typedef struct myprivate +{ + bool bConvert; +} PRIVATE; + +void PNGDraw(PNGDRAW *pDraw) +{ +PRIVATE *pPriv = (PRIVATE *)pDraw->pUser; +uint16_t usPixels[240]; + + if (pPriv->bConvert) + png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0xffffffff); // don't do alpha color blending +} /* PNGDraw() */ + +void setup() { + Serial.begin(115200); + delay(2000); + Serial.println("Starting benchmark..."); +} /* setup() */ + +void loop() { +long lTime; +char szTemp[256]; +int rc; +PRIVATE priv; + +// 32-bpp image + rc = png.openFLASH((uint8_t *)octocat_32bpp, sizeof(octocat_32bpp), PNGDraw); + if (rc == PNG_SUCCESS) { + Serial.println("Successfully opened octocat_32bpp.png"); + priv.bConvert = false; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for native pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + priv.bConvert = true; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for RGB565 pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + png.close(); // not needed for memory->memory decode + } + +// 8-bpp image + rc = png.openFLASH((uint8_t *)octocat_8bpp, sizeof(octocat_8bpp), PNGDraw); + if (rc == PNG_SUCCESS) { + Serial.println("Successfully opened octocat_8bpp.png"); + priv.bConvert = false; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for native pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + priv.bConvert = true; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for RGB565 pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + png.close(); // not needed for memory->memory decode + } +// 4-bpp image + rc = png.openFLASH((uint8_t *)octocat_4bpp, sizeof(octocat_4bpp), PNGDraw); + if (rc == PNG_SUCCESS) { + Serial.println("Successfully opened octocat_4bpp.png"); + priv.bConvert = false; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for native pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + priv.bConvert = true; + lTime = micros(); + rc = png.decode((void *)&priv, PNG_FAST_PALETTE); + lTime = micros() - lTime; + sprintf(szTemp, "Decode time for RGB565 pixels = %d us\n", (int)lTime); + Serial.print(szTemp); + png.close(); // not needed for memory->memory decode + } + delay(5000); +} /* loop() */ diff --git a/libraries/PNGdec/examples/png_transparency/octocat_4bpp.h b/libraries/PNGdec/examples/png_transparency/octocat_4bpp.h new file mode 100644 index 0000000..ec68a3e --- /dev/null +++ b/libraries/PNGdec/examples/png_transparency/octocat_4bpp.h @@ -0,0 +1,66 @@ +// +// octocat_4bpp +// Data size = 872 bytes +// +// PNG, Compression=Flate, Size: 120 x 100, 8-Bpp +// +// for non-Arduino builds... +#ifndef PROGMEM +#define PROGMEM +#endif +const uint8_t octocat_4bpp[] PROGMEM = { + 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x64,0x08,0x03,0x00,0x00,0x00,0x7a,0xae,0x04, + 0x00,0x00,0x00,0x00,0x33,0x50,0x4c,0x54,0x45,0x2f,0x41,0x70,0x00,0x00,0x00,0x2a, + 0x2c,0x2c,0x59,0x49,0x41,0x46,0x5f,0x6a,0x7c,0x65,0x58,0xad,0x5c,0x53,0xb5,0x70, + 0x67,0xa0,0x80,0x71,0x6c,0x99,0xac,0xc9,0xa1,0x8f,0x83,0xb7,0xc9,0x7b,0xbb,0xe4, + 0xdc,0xc5,0xc3,0x9b,0xd8,0xf0,0xf4,0xc9,0xb3,0xff,0xff,0xff,0xfe,0x29,0xa3,0x31, + 0x00,0x00,0x00,0x01,0x74,0x52,0x4e,0x53,0x00,0x40,0xe6,0xd8,0x66,0x00,0x00,0x00, + 0x01,0x62,0x4b,0x47,0x44,0x00,0x88,0x05,0x1d,0x48,0x00,0x00,0x02,0xd6,0x49,0x44, + 0x41,0x54,0x68,0xde,0xed,0xd9,0xed,0x92,0xa3,0x20,0x10,0x05,0x50,0x04,0x54,0x68, + 0x47,0xcc,0xfb,0x3f,0xed,0xa2,0x80,0x9f,0xb0,0x62,0x79,0x89,0x33,0x55,0xf6,0x8f, + 0xdd,0x52,0x9c,0x3e,0x69,0x04,0xc4,0x84,0xb1,0x37,0x76,0xc1,0x6d,0x5c,0xfe,0x03, + 0x8e,0x71,0x2f,0x64,0xba,0x78,0x79,0x46,0xa6,0xac,0x5c,0x97,0x2e,0xce,0xce,0x75, + 0x9a,0x8d,0x5f,0xb8,0xf6,0x1a,0x1c,0xd2,0xf1,0x7d,0x24,0xaf,0x44,0xb9,0x17,0xe2, + 0x85,0x5f,0xf8,0xd7,0xc2,0xec,0x85,0x7f,0x3d,0xcc,0x9f,0x72,0x6f,0xca,0xfc,0x2f, + 0xc2,0xfc,0x29,0xf7,0x39,0x98,0x3f,0xe5,0x3e,0x07,0xf3,0xbf,0x06,0xf3,0x17,0x16, + 0xb5,0x1a,0xa3,0xae,0x6b,0x21,0x44,0x38,0x27,0x84,0x3d,0xf6,0xe7,0x05,0x46,0xde, + 0xe6,0xa8,0x15,0x9d,0x87,0xaa,0xe1,0xb0,0xa2,0x21,0x27,0x48,0x09,0x2c,0xac,0x86, + 0xdc,0x20,0x81,0x84,0xf3,0xdd,0x61,0x50,0x40,0x38,0xb8,0x1f,0x1b,0x29,0x6f,0x69, + 0x53,0x30,0x58,0xd0,0x92,0x3b,0x25,0xaf,0xdb,0x6a,0x14,0xac,0xe6,0xdc,0x7d,0x9f, + 0x90,0x7d,0x93,0x6b,0x23,0x10,0xec,0x0b,0xb6,0x89,0xfb,0xb6,0x69,0xfa,0x4f,0x7f, + 0x74,0xed,0xc9,0xa6,0x69,0xc7,0x2b,0xa6,0x43,0x81,0x81,0xeb,0xa5,0x28,0x9b,0xde, + 0xca,0x91,0x82,0x7b,0xb2,0x1f,0xaa,0x0d,0x25,0x2b,0xcc,0xca,0x35,0xf7,0x34,0x7d, + 0x3e,0xb6,0x64,0x8a,0xc1,0xd4,0x7f,0x68,0xfc,0x4c,0xdb,0xbe,0xbe,0xf9,0x74,0x9a, + 0x87,0x56,0x4b,0x36,0xb9,0xad,0x2b,0x02,0xb7,0x8d,0xb2,0x4d,0xaa,0x14,0xdc,0x34, + 0x69,0xd8,0x35,0x41,0x61,0xf5,0x38,0x4c,0x53,0xf6,0xf8,0x3d,0xf6,0x4d,0x90,0xc1, + 0x15,0xe4,0x65,0x54,0x4f,0xd9,0xe3,0xa3,0xda,0x37,0x41,0x61,0x11,0xe6,0xea,0x54, + 0x57,0x62,0x1e,0xd3,0xca,0x0d,0x4b,0xd7,0xed,0xed,0x2d,0xad,0x56,0xae,0x3e,0xbd, + 0x72,0x2d,0xab,0x1a,0x6a,0x63,0x5d,0x0f,0xd1,0xb5,0x9a,0x1a,0x8a,0xaf,0xd5,0x04, + 0x7b,0x87,0xa1,0xe8,0xd3,0x89,0x9a,0x36,0xfa,0x74,0xba,0xdf,0xd3,0xb3,0x5c,0x27, + 0x9e,0xf9,0x89,0xd3,0xc0,0xf7,0xd4,0x2b,0x1b,0x01,0xff,0x88,0x00,0xbd,0x99,0x1f, + 0x65,0xa2,0xf0,0xcf,0x2e,0x6a,0xd0,0xb7,0xa8,0xa1,0xb7,0x0f,0x44,0x4b,0x03,0xb5, + 0x25,0xdd,0xb9,0x68,0x3a,0xd4,0x4c,0xa9,0xad,0x1e,0xf2,0x5b,0xfa,0x68,0xd5,0x89, + 0xbd,0x2d,0xf8,0x07,0x82,0x69,0x15,0x53,0xb1,0x3a,0xa7,0xea,0xe7,0x1d,0xf5,0x7d, + 0x2a,0xb9,0xdb,0x9d,0x5e,0x5b,0x96,0x10,0x02,0xfc,0x35,0x93,0x94,0x17,0x5f,0xe3, + 0x50,0x9d,0x2b,0x65,0x34,0x17,0xaf,0xc6,0x08,0x98,0x3b,0x40,0xff,0xf0,0xd3,0xe9, + 0x48,0xca,0x2a,0x12,0x40,0xd6,0xa4,0x7e,0x41,0xaa,0x0e,0x3d,0x8c,0x95,0x8d,0xaf, + 0x39,0xef,0x3e,0xe3,0x64,0x63,0x9c,0xa2,0x25,0xcf,0x1a,0x60,0x15,0x63,0xe8,0xfb, + 0xac,0xf3,0x06,0x76,0xc5,0xca,0x0e,0xb0,0x6f,0xc1,0xbb,0xf9,0xbc,0x9b,0xb6,0xf8, + 0x49,0xbc,0x85,0x75,0x37,0x4d,0x69,0x39,0x0e,0xb5,0x2d,0x55,0x10,0x76,0x25,0x73, + 0x6d,0xa4,0x34,0x9a,0xcb,0x4d,0xa9,0x61,0xc2,0x95,0x81,0xb7,0xfd,0x59,0xc5,0x60, + 0x56,0x06,0x66,0x8f,0xc1,0x6b,0xfa,0xcb,0x30,0xdb,0x12,0x5f,0x85,0x37,0xb5,0xbf, + 0xf0,0x0b,0x17,0x87,0xe5,0x97,0xe1,0x71,0xf1,0xe4,0xee,0xb9,0x35,0xfd,0x67,0x8a, + 0xc3,0xc6,0x89,0xda,0xc3,0x66,0x03,0x77,0xc6,0x6d,0x1e,0xf0,0xe8,0x18,0x27,0xb0, + 0x41,0xe3,0x26,0x44,0x06,0x0c,0xb4,0x97,0x8c,0x99,0x30,0x86,0x5e,0xe7,0x33,0x32, + 0x0a,0x4b,0x37,0xe4,0x0c,0x92,0xde,0x66,0x0b,0xd2,0x0e,0xd6,0xc7,0x92,0xef,0xca, + 0x31,0x57,0x9a,0xfd,0x74,0xf2,0x25,0x23,0xe5,0x75,0x22,0xbf,0xe1,0x92,0xf3,0x27, + 0x58,0x2a,0xf5,0x4d,0x1a,0x26,0x1f,0xef,0xaf,0xd4,0x73,0xe9,0xd2,0x74,0x0b,0xa7, + 0x25,0xb4,0xb7,0x77,0x3d,0xad,0xf5,0x8f,0x8d,0x65,0x8c,0x2d,0xa3,0x6a,0x3c,0xaf, + 0xf5,0xce,0x85,0xc1,0x2e,0xbf,0x95,0x75,0xf0,0x3a,0xdf,0xd7,0xfe,0xbc,0x29,0x0c, + 0xaf,0x86,0x92,0xbb,0xcb,0x1a,0xed,0x26,0xe4,0x71,0x73,0xaf,0x1d,0xe4,0x3e,0xc5, + 0xb7,0xe0,0x9f,0xf9,0x5e,0xbb,0xa3,0x0e,0xef,0x1e,0x68,0x7f,0x33,0xc3,0x3d,0x5d, + 0x1f,0x82,0xdd,0x9d,0x1c,0x83,0x4d,0x14,0x06,0xaf,0xd6,0xb9,0x30,0xfc,0xf9,0x94, + 0x05,0x97,0xd8,0x08,0x9c,0xc3,0x85,0xb6,0x3e,0xff,0x87,0x59,0xe1,0x88,0xc0,0xec, + 0x8d,0xd3,0xf8,0x07,0xe9,0x64,0x82,0xb3,0xf5,0x3d,0x65,0xc0,0x00,0x00,0x00,0x00, + 0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82}; diff --git a/libraries/PNGdec/examples/png_transparency/png_transparency.ino b/libraries/PNGdec/examples/png_transparency/png_transparency.ino new file mode 100644 index 0000000..5b0c4b9 --- /dev/null +++ b/libraries/PNGdec/examples/png_transparency/png_transparency.ino @@ -0,0 +1,70 @@ +// +// PNG Drawing with transparency example +// +// loads a 120x100 4-bpp palette image +// and draws it at random locations on the LCD +// +#include +#include +#include + +// 120x100x4-bpp image with transparency +// The small file size (852 bytes) allows it to be decoded and drawn quickly +#include "octocat_4bpp.h" + +PNG png; +SPILCD lcd; +static uint8_t ucTXBuf[1024]; +#define TFT_CS 10 +#define TFT_RST -1 +#define TFT_DC 9 +#define TFT_CLK 13 +#define TFT_MOSI 11 + +// +// Create a private structure to pass info to the draw callback +// For this example we want to pass a random x/y starting point +// +typedef struct my_private_struct +{ + int xoff, yoff; // corner offset +} PRIVATE; + +void PNGDraw(PNGDRAW *pDraw) +{ +uint16_t usPixels[320]; +uint8_t ucMask[40]; +PRIVATE *pPriv = (PRIVATE *)pDraw->pUser; + + png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_BIG_ENDIAN, 0xffffffff); + if (png.getAlphaMask(pDraw, ucMask, 255)) { // if any pixels are opaque, draw them + spilcdWritePixelsMasked(&lcd, pPriv->xoff, pPriv->yoff + pDraw->y, (uint8_t *)usPixels, ucMask, pDraw->iWidth, DRAW_TO_LCD); + } +} /* PNGDraw() */ + +void setup() { + spilcdSetTXBuffer(ucTXBuf, sizeof(ucTXBuf)); + spilcdInit(&lcd, LCD_ILI9341, FLAGS_NONE, 40000000, TFT_CS, TFT_DC, TFT_RST, -1, -1, TFT_MOSI, TFT_CLK); + spilcdSetOrientation(&lcd, LCD_ORIENTATION_270); + spilcdFill(&lcd, 0, DRAW_TO_LCD); + spilcdWriteString(&lcd, 0, 4, (char *)"PNG Test", 0xffff, 0, FONT_12x16, DRAW_TO_LCD); + Serial.begin(115200); + delay(2000); +} + +void loop() { + int rc, i = 0; + PRIVATE priv; + + spilcdFill(&lcd, 0xf81f, DRAW_TO_LCD); + rc = png.openRAM((uint8_t *)octocat_4bpp, sizeof(octocat_4bpp), PNGDraw); + if (rc == PNG_SUCCESS) { + Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType()); + while (1) { // loop forever + priv.xoff = rand() & 0xff; + priv.yoff = rand() % 160; + rc = png.decode((void *)&priv, 0); + } + png.close(); + } +} /* loop() */ diff --git a/libraries/PNGdec/examples/sdcard_slideshow/sdcard_slideshow.ino b/libraries/PNGdec/examples/sdcard_slideshow/sdcard_slideshow.ino new file mode 100644 index 0000000..1726575 --- /dev/null +++ b/libraries/PNGdec/examples/sdcard_slideshow/sdcard_slideshow.ino @@ -0,0 +1,107 @@ +// A simple image slideshow which reads all the .JPG files from the root +// directory of a SD card and shows each for 1 second on an ILI9341 display. + +#include +#include +#include +#include + +#define TFT_DC 9 +#define TFT_CS 10 + +ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC); +PNG png; + +// Setup - initialize ILI9341 display, wait for serial monitor, open SD card +void setup() { + pinMode(34, INPUT_PULLDOWN); + pinMode(33, OUTPUT); + digitalWrite(33, HIGH); // pushbuttons short pins 33 & 34 together + Serial.begin(115200); + tft.begin(); + tft.setRotation(3); + tft.fillScreen(ILI9341_BLACK); + tft.setTextColor(ILI9341_YELLOW); + tft.setTextSize(2); + tft.println("Waiting for Arduino Serial Monitor..."); + + while (!Serial && millis() < 3000); // wait up to 3 seconds for Arduino Serial Monitor + Serial.println("ILI9341 Slideshow"); + tft.fillScreen(ILI9341_BLACK); + tft.setCursor(0, 0); + + while (!SD.begin(4/*BUILTIN_SDCARD*/)) { + Serial.println("Unable to access SD Card"); + tft.println("Unable to access SD Card"); + delay(1000); + } +} + +// Functions to access a file on the SD card +File myfile; + +void * myOpen(const char *filename, int32_t *size) { + Serial.printf("Attempting to open %s\n", filename); + myfile = SD.open(filename); + *size = myfile.size(); + return &myfile; +} +void myClose(void *handle) { + if (myfile) myfile.close(); +} +int32_t myRead(PNGFILE *handle, uint8_t *buffer, int32_t length) { + if (!myfile) return 0; + return myfile.read(buffer, length); +} +int32_t mySeek(PNGFILE *handle, int32_t position) { + if (!myfile) return 0; + return myfile.seek(position); +} + +// Function to draw pixels to the display +void PNGDraw(PNGDRAW *pDraw) { +uint16_t usPixels[320]; + + png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0xffffffff); + tft.writeRect(0, pDraw->y + 24, pDraw->iWidth, 1, usPixels); +} + +// Main loop, scan for all .PNG files on the card and display them +void loop() { + int rc, filecount = 0; + tft.setCursor(0, 0); + File dir = SD.open("/"); + while (true) { + File entry = dir.openNextFile(); + if (!entry) break; + if (entry.isDirectory() == false) { + const char *name = entry.name(); + const int len = strlen(name); + if (len > 3 && strcmp(name + len - 3, "PNG") == 0) { + Serial.print("File: "); + Serial.println(name); + tft.fillScreen(ILI9341_BLACK); + tft.setCursor(0, 0); + tft.print("File: "); + tft.println(name); + rc = png.open((const char *)name, myOpen, myClose, myRead, mySeek, PNGDraw); + if (rc == PNG_SUCCESS) { + Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType()); + rc = png.decode(NULL, 0); + png.close(); + } + filecount = filecount + 1; +// if (digitalRead(34) == LOW) { + // skip delay between images when pushbutton is pressed + delay(2000); +// } + } + } + entry.close(); + } + if (filecount == 0) { + Serial.println("No .PNG files found"); + tft.println("No .PNG files found"); + delay(2000); + } +} diff --git a/libraries/PNGdec/library.properties b/libraries/PNGdec/library.properties new file mode 100644 index 0000000..83c78e2 --- /dev/null +++ b/libraries/PNGdec/library.properties @@ -0,0 +1,10 @@ +name=PNGdec +version=1.0.2 +author=Larry Bank +maintainer=Larry Bank +sentence=Universal PNG decoder for MCUs with at least 48K of RAM. +paragraph=Designed to provide a fully functional PNG decoder that can use minimal memory by decoding a line at a time with an optional callback function. Supports all pixel formats. +category=Display +url=https://github.com/bitbank2/PNGdec +architectures=* +includes=PNGdec.h diff --git a/libraries/PNGdec/linux/Makefile b/libraries/PNGdec/linux/Makefile new file mode 100644 index 0000000..aa06af0 --- /dev/null +++ b/libraries/PNGdec/linux/Makefile @@ -0,0 +1,37 @@ +CFLAGS=-D__LINUX__ -Wall -O2 +LIBS = + +all: png_demo + +png_demo: main.o PNGdec.o adler32.o crc32.o infback.o inffast.o inflate.o inftrees.o zutil.o + $(CC) main.o PNGdec.o adler32.o crc32.o infback.o inffast.o inflate.o inftrees.o zutil.o $(LIBS) -o png_demo + +main.o: main.cpp + $(CXX) $(CFLAGS) -c main.cpp + +PNGdec.o: ../src/PNGdec.cpp ../src/png.inl ../src/PNGdec.h + $(CXX) $(CFLAGS) -c ../src/PNGdec.cpp + +adler32.o: ../src/adler32.c + $(CC) $(CFLAGS) -c ../src/adler32.c + +crc32.o: ../src/crc32.c + $(CC) $(CFLAGS) -c ../src/crc32.c + +infback.o: ../src/infback.c + $(CC) $(CFLAGS) -c ../src/infback.c + +inffast.o: ../src/inffast.c + $(CC) $(CFLAGS) -c ../src/inffast.c + +inflate.o: ../src/inflate.c + $(CC) $(CFLAGS) -c ../src/inflate.c + +inftrees.o: ../src/inftrees.c + $(CC) $(CFLAGS) -c ../src/inftrees.c + +zutil.o: ../src/zutil.c + $(CC) $(CFLAGS) -c ../src/zutil.c + +clean: + rm -rf *.o png_demo diff --git a/libraries/PNGdec/linux/main.cpp b/libraries/PNGdec/linux/main.cpp new file mode 100644 index 0000000..a134781 --- /dev/null +++ b/libraries/PNGdec/linux/main.cpp @@ -0,0 +1,150 @@ +// +// main.cpp +// pngdec_test +// +// Created by Larry Bank on 5/9/21. +// + +#include "../src/PNGdec.h" + +PNG png; // static instance of class + +/* Windows BMP header info (54 bytes) */ +uint8_t winbmphdr[54] = + {0x42,0x4d, + 0,0,0,0, /* File size */ + 0,0,0,0,0x36,4,0,0,0x28,0,0,0, + 0,0,0,0, /* Xsize */ + 0,0,0,0, /* Ysize */ + 1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* number of planes, bits per pel */ + 0,0,0,0}; + +// +// Minimal code to save frames as Windows BMP files +// +void SaveBMP(char *fname, uint8_t *pBitmap, uint8_t *pPalette, int cx, int cy, int bpp) +{ +FILE * oHandle; +int i, bsize, lsize; +uint32_t *l; +uint8_t *s; +uint8_t ucTemp[1024]; + + oHandle = fopen(fname, "w+b"); + bsize = (cx * bpp) >> 3; + lsize = (bsize + 3) & 0xfffc; /* Width of each line */ + winbmphdr[26] = 1; // number of planes + winbmphdr[28] = (uint8_t)bpp; + + /* Write the BMP header */ + l = (uint32_t *)&winbmphdr[2]; + i =(cy * lsize) + 54; + if (bpp <= 8) + i += 1024; + *l = (uint32_t)i; /* Store the file size */ + l = (uint32_t *)&winbmphdr[10]; // pointer to data + *l = i - (cy * lsize); + winbmphdr[14] = 0x28; + l = (uint32_t *)&winbmphdr[18]; + *l = (uint32_t)cx; /* width */ + *(l+1) = (uint32_t)(-cy); /* height */ + fwrite(winbmphdr, 1, 54, oHandle); + if (bpp <= 8) { + if (pPalette == NULL) {// create a grayscale palette + int iDelta, iCount = 1<= 24) { // swap R/B for Windows BMP byte order + uint8_t ucTemp[2048]; + int j, iBpp = bpp/8; + uint8_t *d = ucTemp; + for (j=0; j \n"); + return 0; + } + ihandle = fopen(argv[1],"rb"); // open input file + if (ihandle == NULL) + { + fprintf(stderr, "Unable to open file: %s\n", argv[1]); + return -1; // bad filename passed + } + fseek(ihandle, 0L, SEEK_END); // get the file size + iDataSize = (int)ftell(ihandle); + fseek(ihandle, 0, SEEK_SET); + pData = (uint8_t *)malloc(iDataSize); + fread(pData, 1, iDataSize, ihandle); + fclose(ihandle); + +// for (int j=0; j<10000; j++) { + rc = png.openRAM(pData, iDataSize, NULL); //PNGDraw); + if (rc == PNG_SUCCESS) { + printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType()); + png.setBuffer((uint8_t *)malloc(png.getBufferSize())); + rc = png.decode(NULL, 0); //PNG_CHECK_CRC); + i = 1; + pPalette = NULL; + switch (png.getPixelType()) { + case PNG_PIXEL_INDEXED: + pPalette = png.getPalette(); + i = 1; + break; + case PNG_PIXEL_TRUECOLOR: + i = 3; + break; + case PNG_PIXEL_TRUECOLOR_ALPHA: + i = 4; + break; + } + SaveBMP((char *)argv[2], png.getBuffer(), pPalette, png.getWidth(), png.getHeight(), i*png.getBpp()); + png.close(); + free(png.getBuffer()); +// } // for j + } + return 0; +} diff --git a/libraries/PNGdec/perf_small.png b/libraries/PNGdec/perf_small.png new file mode 100644 index 0000000..a43bfcb Binary files /dev/null and b/libraries/PNGdec/perf_small.png differ diff --git a/libraries/PNGdec/src/PNGdec.cpp b/libraries/PNGdec/src/PNGdec.cpp new file mode 100644 index 0000000..8e4305f --- /dev/null +++ b/libraries/PNGdec/src/PNGdec.cpp @@ -0,0 +1,209 @@ +// +// PNG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 5/3/2021 +// Original PNG code written 20+ years ago :) +// The goal of this code is to decode PNG images on embedded systems +// +// Copyright 2021 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "PNGdec.h" + +// forward references +PNG_STATIC int PNGInit(PNGIMAGE *pPNG); +PNG_STATIC int DecodePNG(PNGIMAGE *pImage, void *pUser, int iOptions); +PNG_STATIC uint8_t PNGMakeMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold); +// Include the C code which does the actual work +#include "png.inl" + +// +// Memory initialization +// +int PNG::openRAM(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_png, 0, sizeof(PNGIMAGE)); + _png.ucMemType = PNG_MEM_RAM; + _png.pfnRead = readRAM; + _png.pfnSeek = seekMem; + _png.pfnDraw = pfnDraw; + _png.pfnOpen = NULL; + _png.pfnClose = NULL; + _png.PNGFile.iSize = iDataSize; + _png.PNGFile.pData = pData; + return PNGInit(&_png); +} /* openRAM() */ +// +// It's necessary to separate out a FLASH version on Harvard architecture machines +// +int PNG::openFLASH(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_png, 0, sizeof(PNGIMAGE)); + _png.ucMemType = PNG_MEM_FLASH; + _png.pfnRead = readFLASH; + _png.pfnSeek = seekMem; + _png.pfnDraw = pfnDraw; + _png.pfnOpen = NULL; + _png.pfnClose = NULL; + _png.PNGFile.iSize = iDataSize; + _png.PNGFile.pData = pData; + return PNGInit(&_png); +} /* openRAM() */ + +// +// File (SD/MMC) based initialization +// +int PNG::open(const char *szFilename, PNG_OPEN_CALLBACK *pfnOpen, PNG_CLOSE_CALLBACK *pfnClose, PNG_READ_CALLBACK *pfnRead, PNG_SEEK_CALLBACK *pfnSeek, PNG_DRAW_CALLBACK *pfnDraw) +{ + memset(&_png, 0, sizeof(PNGIMAGE)); + _png.pfnRead = pfnRead; + _png.pfnSeek = pfnSeek; + _png.pfnDraw = pfnDraw; + _png.pfnOpen = pfnOpen; + _png.pfnClose = pfnClose; + _png.PNGFile.fHandle = (*pfnOpen)(szFilename, &_png.PNGFile.iSize); + if (_png.PNGFile.fHandle == NULL) + return 0; + return PNGInit(&_png); + +} /* open() */ +// +// return the last error (if any) +// +int PNG::getLastError() +{ + return _png.iError; +} /* getLastError() */ +// +// Get the width of the image in pixels +// can be called after opening the file (before decoding) +// +int PNG::getWidth() +{ + return _png.iWidth; +} /* getWidth() */ +// +// Get the height of the image in pixels +// can be called after opening the file (before decoding) +// +int PNG::getHeight() +{ + return _png.iHeight; +} /* getHeight() */ +// +// For truecolor and palette images, it's possible to have a single +// transparent color defined. This call will return it if defined +// +uint32_t PNG::getTransparentColor() +{ + return _png.iTransparent; +} /* getTransparentColor() */ +// +// Alpha information can be per pixel, per color or a single color +// depending on the PNG pixel type of the image +// This call simply tells you if there is alpha for the current pixel type +// +int PNG::hasAlpha() +{ + return _png.iHasAlpha; +} /* hasAlpha() */ +// +// Returns true or false for the use of Adam7 interlacing +// This option is not supported by the decoder, but after opening the image +// you can determine if it's set +// +int PNG::isInterlaced() +{ + return _png.iInterlaced; +} /* isInterlaced() */ + +// +// Returns the number of bits per color stimulus +// values of 1,2,4, and 8 are supported +// +int PNG::getBpp() +{ + return (int)_png.ucBpp; +} /* getBpp() */ +// +// Returns the PNG pixel type (see enum in PNGdec.h) +// +int PNG::getPixelType() +{ + return (int)_png.ucPixelType; +} /* getPixelType() */ +// +// Set the image buffer to memory managed by the caller +// If set, decode() will not use the PNGDRAW callback function +// and instead write the image into this buffer in one shot +// +void PNG::setBuffer(uint8_t *pBuffer) +{ + _png.pImage = pBuffer; +} /* setBuffer() */ +// +// Returns the previously set image buffer or NULL if there is none +// +uint8_t * PNG::getBuffer() +{ + return _png.pImage; +} /* getBuffer() */ +// +// Returns the size in bytes of the buffer needed to hold the uncompressed image +// +int PNG::getBufferSize() +{ + return _png.iHeight * _png.iPitch; +} /* getBufferSize() */ +// +// Returns a pointer to the palette +// If there is alpha info for the palette, it starts at pPalette[768] +// +uint8_t * PNG::getPalette() +{ + return _png.ucPalette; +} /* getPalette() */ +// +// Close the file - not needed when decoding from memory +// +void PNG::close() +{ + if (_png.pfnClose) + (*_png.pfnClose)(_png.PNGFile.fHandle); +} /* close() */ + +// +// Decode the image +// returns: +// 0 = PNG_SUCCESS +// non 0 = PNG enumerated error code +// +int PNG::decode(void *pUser, int iOptions) +{ + return DecodePNG(&_png, pUser, iOptions); +} /* decode() */ +// +// Convert a line of native pixels (all supported formats) into RGB565 +// can optionally mix in a background color - set to -1 to disable +// Background color is in the form of a uint32_t -> 00BBGGRR (MSB on left) +// +void PNG::getLineAsRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndianness, uint32_t u32Bkgd) +{ + PNGRGB565(pDraw, pPixels, iEndianness, u32Bkgd, hasAlpha()); +} /* getLineAsRGB565() */ + +uint8_t PNG::getAlphaMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold) +{ + return PNGMakeMask(pDraw, pMask, ucThreshold); +} /* getAlphaMask() */ diff --git a/libraries/PNGdec/src/PNGdec.h b/libraries/PNGdec/src/PNGdec.h new file mode 100644 index 0000000..fade6c4 --- /dev/null +++ b/libraries/PNGdec/src/PNGdec.h @@ -0,0 +1,216 @@ +// +// PNG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 5/3/2021 +// Original PNG code written 20+ years ago :) +// The goal of this code is to decode PNG images on embedded systems +// +// Copyright 2021 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#ifndef __PNGDEC__ +#define __PNGDEC__ +#if defined( __MACH__ ) || defined( __LINUX__ ) || defined( __MCUXPRESSO ) +#include +#include +#include +#include +#define memcpy_P memcpy +#define PROGMEM +#else +#include +#endif +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +// +// PNG Decoder +// Written by Larry Bank +// Copyright (c) 2021 BitBank Software, Inc. +// +// Designed to decode most PNG images (1-32 bpp) +// using less than 40K of RAM +// +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif +/* Defines and variables */ +#define PNG_FILE_BUF_SIZE 2048 +// Number of bytes to reserve for current and previous lines +// Defaults to 640 32-bit pixels max width +#define PNG_MAX_BUFFERED_PIXELS (640*4 + 1) +// PNG filter type +enum { + PNG_FILTER_NONE=0, + PNG_FILTER_SUB, + PNG_FILTER_UP, + PNG_FILTER_AVG, + PNG_FILTER_PAETH, + PNG_FILTER_COUNT +}; + +// decode options +enum { + PNG_CHECK_CRC = 1, + PNG_FAST_PALETTE = 2 +}; + +// source pixel type +enum { + PNG_PIXEL_GRAYSCALE=0, + PNG_PIXEL_TRUECOLOR=2, + PNG_PIXEL_INDEXED=3, + PNG_PIXEL_GRAY_ALPHA=4, + PNG_PIXEL_TRUECOLOR_ALPHA=6 +}; +// RGB565 endianness +enum { + PNG_RGB565_LITTLE_ENDIAN = 0, + PNG_RGB565_BIG_ENDIAN +}; + +enum { + PNG_MEM_RAM=0, + PNG_MEM_FLASH +}; + +// Error codes returned by getLastError() +enum { + PNG_SUCCESS = 0, + PNG_INVALID_PARAMETER, + PNG_DECODE_ERROR, + PNG_MEM_ERROR, + PNG_NO_BUFFER, + PNG_UNSUPPORTED_FEATURE, + PNG_INVALID_FILE, + PNG_TOO_BIG +}; + +typedef struct png_draw_tag +{ + int y; // starting x,y of this line + int iWidth; // size of this line + int iPitch; // bytes per line + int iPixelType; // PNG pixel type (0,2,3,4,6) + int iBpp; // bits per color stimulus + int iHasAlpha; // flag indicating the presence of an alpha palette + void *pUser; // user supplied pointer + uint8_t *pPalette; + uint16_t *pFastPalette; + uint8_t *pPixels; +} PNGDRAW; + +typedef struct png_file_tag +{ + int32_t iPos; // current file position + int32_t iSize; // file size + uint8_t *pData; // memory file pointer + void * fHandle; // class pointer to File/SdFat or whatever you want +} PNGFILE; + +// Callback function prototypes +typedef int32_t (PNG_READ_CALLBACK)(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen); +typedef int32_t (PNG_SEEK_CALLBACK)(PNGFILE *pFile, int32_t iPosition); +typedef void * (PNG_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize); +typedef void (PNG_DRAW_CALLBACK)(PNGDRAW *); +typedef void (PNG_CLOSE_CALLBACK)(void *pHandle); + +// +// our private structure to hold a JPEG image decode state +// +typedef struct png_image_tag +{ + int iWidth, iHeight; // image size + uint8_t ucBpp, ucPixelType; + uint8_t ucMemType; + uint8_t *pImage; + int iPitch; // bytes per line + int iHasAlpha; + int iInterlaced; + uint32_t iTransparent; // transparent color index/value + int iError; + PNG_READ_CALLBACK *pfnRead; + PNG_SEEK_CALLBACK *pfnSeek; + PNG_OPEN_CALLBACK *pfnOpen; + PNG_DRAW_CALLBACK *pfnDraw; + PNG_CLOSE_CALLBACK *pfnClose; + PNGFILE PNGFile; + uint8_t ucZLIB[32768 + sizeof(inflate_state)]; // put this here to avoid needing malloc/free + uint8_t ucPalette[1024]; + uint8_t ucPixels[PNG_MAX_BUFFERED_PIXELS * 2]; + uint8_t ucFileBuf[PNG_FILE_BUF_SIZE]; // holds temp file data +} PNGIMAGE; + +#ifdef __cplusplus +#define PNG_STATIC static +// +// The PNG class wraps portable C code which does the actual work +// +class PNG +{ + public: + int openRAM(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw); + int openFLASH(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw); + int open(const char *szFilename, PNG_OPEN_CALLBACK *pfnOpen, PNG_CLOSE_CALLBACK *pfnClose, PNG_READ_CALLBACK *pfnRead, PNG_SEEK_CALLBACK *pfnSeek, PNG_DRAW_CALLBACK *pfnDraw); + void close(); + int decode(void *pUser, int iOptions); + int getWidth(); + int getHeight(); + int getBpp(); + int hasAlpha(); + uint32_t getTransparentColor(); + int isInterlaced(); + uint8_t * getPalette(); + int getPixelType(); + int getLastError(); + int getBufferSize(); + uint8_t *getBuffer(); + void setBuffer(uint8_t *pBuffer); + uint8_t getAlphaMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold); + void getLineAsRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndianness, uint32_t u32Bkgd); + + private: + PNGIMAGE _png; +}; +#else +#define PNG_STATIC +int PNG_openRAM(PNGIMAGE *pPNG, uint8_t *pData, int iDataSize); +int PNG_openFile(PNGIMAGE *pPNG, const char *szFilename); +int PNG_getWidth(PNGIMAGE *pPNG); +int PNG_getHeight(PNGIMAGE *pPNG); +int PNG_decode(PNGIMAGE *pPNG, void *pUser, int iOptions); +void PNG_close(PNGIMAGE *pPNG); +int PNG_getLastError(PNGIMAGE *pPNG); +int PNG_getBpp(PNGIMAGE *pPNG); +int PNG_getLastError(PNGIMAGE *pPNG); +int PNG_getBufferSize(PNGIMAGE *pPNG); +uint8_t *PNG_getPalette(PNGIMAGE *pPNG); +int PNG_getPixelType(PNGIMAGE *pPNG); +int PNG_hasAlpha(PNGIMAGE *pPNG); +int PNG_isInterlaced(PNGIMAGE *pPNG); +uint8_t *PNG_getBuffer(PNGIMAGE *pPNG); +void PNG_setBuffer(PNGIMAGE *pPNG, uint8_t *pBuffer); +#endif // __cplusplus + +// Due to unaligned memory causing an exception, we have to do these macros the slow way +#define INTELSHORT(p) ((*p) + (*(p+1)<<8)) +#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24)) +#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1))) +#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3))) + +// Must be a 32-bit target processor +#define REGISTER_WIDTH 32 + +#endif // __PNGDEC__ diff --git a/libraries/PNGdec/src/adler32.c b/libraries/PNGdec/src/adler32.c new file mode 100644 index 0000000..d0be438 --- /dev/null +++ b/libraries/PNGdec/src/adler32.c @@ -0,0 +1,186 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(adler, buf, len) + uLong adler; + const Bytef *buf; + z_size_t len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/libraries/PNGdec/src/crc32.c b/libraries/PNGdec/src/crc32.c new file mode 100644 index 0000000..9580440 --- /dev/null +++ b/libraries/PNGdec/src/crc32.c @@ -0,0 +1,442 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, z_size_t)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, z_size_t)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + +#ifdef BYFOUR + +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *buf4++; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/libraries/PNGdec/src/crc32.h b/libraries/PNGdec/src/crc32.h new file mode 100644 index 0000000..9e0c778 --- /dev/null +++ b/libraries/PNGdec/src/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/libraries/PNGdec/src/infback.c b/libraries/PNGdec/src/infback.c new file mode 100644 index 0000000..59679ec --- /dev/null +++ b/libraries/PNGdec/src/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/libraries/PNGdec/src/inffast.c b/libraries/PNGdec/src/inffast.c new file mode 100644 index 0000000..2f71cab --- /dev/null +++ b/libraries/PNGdec/src/inffast.c @@ -0,0 +1,404 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#if (INTPTR_MAX == INT64_MAX) || defined(HAL_ESP32_HAL_H_) || defined(TEENSYDUINO) || defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7) +#define ALLOWS_UNALIGNED +#endif + +#if INTPTR_MAX == INT64_MAX +#define REGISTER_WIDTH 64 +typedef uint64_t BIGUINT; +typedef uint32_t SMALLUINT; +#else +#define REGISTER_WIDTH 32 +typedef uint32_t BIGUINT; +typedef uint16_t SMALLUINT; +#endif // native register size + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + BIGUINT hold, tmpbits; /* local strm->hold */ +// unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < (REGISTER_WIDTH/2)) { // helps on 32 and 64-bit CPUs +#ifdef ALLOWS_UNALIGNED + tmpbits = *(SMALLUINT *)in; + hold |= (BIGUINT)(tmpbits << bits); + in += sizeof(SMALLUINT); + bits += (REGISTER_WIDTH / 2); +#else + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; +#endif + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + *out++ = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { +#if REGISTER_WIDTH == 32 + if (bits < op) { + hold += (uint32_t)(*in++) << bits; + bits += 8; + } +#endif + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < (REGISTER_WIDTH/2)) { // helps on 32 and 64-bit CPUs +#ifdef UNALIGNED_OK + tmpbits = *(SMALLUINT *)in; + hold |= (BIGUINT)(tmpbits << bits); + in += sizeof(SMALLUINT); + bits += (REGISTER_WIDTH / 2); +#else + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; +#endif + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ +#if REGISTER_WIDTH == 32 + if (bits < op) { +#ifdef ALLOWS_UNALIGNED + hold |= (*(uint16_t *)in << bits); + bits += 16; + in += 2; +#else + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { // this is NEVER true + hold += (unsigned long)(*in++) << bits; + bits += 8; + } +#endif // ALLOWS_UNALIGNED + } +#endif // 32-bit CPU + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } +#ifdef ALLOWS_UNALIGNED + { + uint8_t *pEnd = out+len; + while (out < pEnd) { + *(uint32_t *)out = *(uint32_t *)from; + out += 4; + from += 4; + } + // correct for possible overshoot of destination ptr + out = pEnd; + } +#else + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } +#endif // ALLOWS_UNALIGNED + } + else { + from = out - dist; /* copy direct from output */ +#ifdef ALLOWS_UNALIGNED + { + uint8_t *pEnd = out+len; + int overlap = (int)(intptr_t)(out-from); + if (overlap >= 4) { // overlap of source/dest won't impede normal copy + while (out < pEnd) { + *(uint32_t *)out = *(uint32_t *)from; + out += 4; + from += 4; + } + // correct for possible overshoot of destination ptr + out = pEnd; + } else if (overlap == 1) { // copy 1-byte pattern + uint32_t pattern = *from; + pattern = pattern | (pattern << 8); + pattern = pattern | (pattern << 16); + while (out < pEnd) { + *(uint32_t *)out = pattern; + out += 4; + } + out = pEnd; // correct possible overshoot + } else { // overlap of 2 or 3 + while (out < pEnd) { + *out++ = *from++; + } + } + } +#else + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } +#endif // ALLOWS_UNALIGNED + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ +// len = bits >> 3; +// in -= len; +// bits -= len << 3; +// hold &= (1 << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/libraries/PNGdec/src/inffast.h b/libraries/PNGdec/src/inffast.h new file mode 100644 index 0000000..e5c1aa4 --- /dev/null +++ b/libraries/PNGdec/src/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/libraries/PNGdec/src/inffixed.h b/libraries/PNGdec/src/inffixed.h new file mode 100644 index 0000000..d628327 --- /dev/null +++ b/libraries/PNGdec/src/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/libraries/PNGdec/src/inflate.c b/libraries/PNGdec/src/inflate.c new file mode 100644 index 0000000..a0b07ec --- /dev/null +++ b/libraries/PNGdec/src/inflate.c @@ -0,0 +1,1610 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#if (INTPTR_MAX == INT64_MAX) || defined(HAL_ESP32_HAL_H_) || defined(TEENSYDUINO) || defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7) +#define ALLOWS_UNALIGNED +#endif + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; +// DEBUG - this would mess up my pre-allocated buffer +// if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { +// ZFREE(strm, state->window); +// state->window = Z_NULL; +// } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif +// ==== DEBUG - I use a static buffer (already set) to avoid this memory allocation + state =(struct inflate_state FAR *)strm->state; +// ==== DEBUG +// state = (struct inflate_state FAR *) +// ZALLOC(strm, 1, sizeof(struct inflate_state)); +// if (state == Z_NULL) return Z_MEM_ERROR; +// Tracev((stderr, "inflate: allocated\n")); +// strm->state = (struct internal_state FAR *)state; + state->strm = strm; +// state->window = Z_NULL; <-- I set this too to avoid a later allocation + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); +// if (ret != Z_OK) { +// ZFREE(strm, state); +// strm->state = Z_NULL; +// } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) + return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ +// DEBUG - I set up this buffer earlier to avoid using malloc +// if (state->window == Z_NULL) { +// state->window = (unsigned char FAR *) +// ZALLOC(strm, 1U << state->wbits, +// sizeof(unsigned char)); +// if (state->window == Z_NULL) return 1; +// } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush, check_crc) +z_streamp strm; +int flush; +int check_crc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + if (check_crc) { + strm->adler = state->check = adler32(0L, Z_NULL, 0); + } + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; +#ifdef ALLOWS_UNALIGNED + { + uint8_t *pEnd = put+copy; + int overlap = (int)(intptr_t)(put-from); + if (overlap >= 4) { // overlap of source/dest won't impede normal copy + while (put < pEnd-3) { // overwriting the output buffer here would be bad, so respect the true length + *(uint32_t *)put = *(uint32_t *)from; + put += 4; + from += 4; + } + while (put < pEnd) { // tail end + *put++ = *from++; + } + } else if (overlap == 1) { // copy 1-byte pattern + uint32_t pattern = *from; + pattern = pattern | (pattern << 8); + pattern = pattern | (pattern << 16); + while (put < pEnd) { + *(uint32_t *)put = pattern; + put += 4; + } + put = pEnd; // correct possible overshoot + } else { // overlap of 2 or 3 + while (put < pEnd) { + *put++ = *from++; + } + } + } +#else + do { + *put++ = *from++; + } while (--copy); +#endif // ALLOWS_UNALIGNED + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (check_crc) { + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + } + out = left; + if (check_crc) { + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (check_crc) { + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + } + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/libraries/PNGdec/src/inflate.h b/libraries/PNGdec/src/inflate.h new file mode 100644 index 0000000..7a0c29d --- /dev/null +++ b/libraries/PNGdec/src/inflate.h @@ -0,0 +1,126 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + uint64_t hold; /* input bit accumulator */ +// unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/libraries/PNGdec/src/inftrees.c b/libraries/PNGdec/src/inftrees.c new file mode 100644 index 0000000..2ea08fc --- /dev/null +++ b/libraries/PNGdec/src/inftrees.c @@ -0,0 +1,304 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/libraries/PNGdec/src/inftrees.h b/libraries/PNGdec/src/inftrees.h new file mode 100644 index 0000000..baa53a0 --- /dev/null +++ b/libraries/PNGdec/src/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/libraries/PNGdec/src/png.inl b/libraries/PNGdec/src/png.inl new file mode 100644 index 0000000..f4fe649 --- /dev/null +++ b/libraries/PNGdec/src/png.inl @@ -0,0 +1,903 @@ +// +// PNG Decoder +// +// written by Larry Bank +// bitbank@pobox.com +// Arduino port started 5/3/2021 +// Original PNG code written 20+ years ago :) +// The goal of this code is to decode PNG images on embedded systems +// +// Copyright 2021 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +// +#include "zlib.h" +// +// Convert 8-bit grayscale into RGB565 +// +static const uint16_t usGrayTo565[] = {0x0000,0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020, // 0 + 0x0841,0x0841,0x0841,0x0841,0x0861,0x0861,0x0861,0x0861, + 0x1082,0x1082,0x1082,0x1082,0x10a2,0x10a2,0x10a2,0x10a2, + 0x18c3,0x18c3,0x18c3,0x18c3,0x18e3,0x18e3,0x18e3,0x18e3, + 0x2104,0x2104,0x2104,0x2104,0x2124,0x2124,0x2124,0x2124, + 0x2945,0x2945,0x2945,0x2945,0x2965,0x2965,0x2965,0x2965, + 0x3186,0x3186,0x3186,0x3186,0x31a6,0x31a6,0x31a6,0x31a6, + 0x39c7,0x39c7,0x39c7,0x39c7,0x39e7,0x39e7,0x39e7,0x39e7, + 0x4208,0x4208,0x4208,0x4208,0x4228,0x4228,0x4228,0x4228, + 0x4a49,0x4a49,0x4a49,0x4a49,0x4a69,0x4a69,0x4a69,0x4a69, + 0x528a,0x528a,0x528a,0x528a,0x52aa,0x52aa,0x52aa,0x52aa, + 0x5acb,0x5acb,0x5acb,0x5acb,0x5aeb,0x5aeb,0x5aeb,0x5aeb, + 0x630c,0x630c,0x630c,0x630c,0x632c,0x632c,0x632c,0x632c, + 0x6b4d,0x6b4d,0x6b4d,0x6b4d,0x6b6d,0x6b6d,0x6b6d,0x6b6d, + 0x738e,0x738e,0x738e,0x738e,0x73ae,0x73ae,0x73ae,0x73ae, + 0x7bcf,0x7bcf,0x7bcf,0x7bcf,0x7bef,0x7bef,0x7bef,0x7bef, + 0x8410,0x8410,0x8410,0x8410,0x8430,0x8430,0x8430,0x8430, + 0x8c51,0x8c51,0x8c51,0x8c51,0x8c71,0x8c71,0x8c71,0x8c71, + 0x9492,0x9492,0x9492,0x9492,0x94b2,0x94b2,0x94b2,0x94b2, + 0x9cd3,0x9cd3,0x9cd3,0x9cd3,0x9cf3,0x9cf3,0x9cf3,0x9cf3, + 0xa514,0xa514,0xa514,0xa514,0xa534,0xa534,0xa534,0xa534, + 0xad55,0xad55,0xad55,0xad55,0xad75,0xad75,0xad75,0xad75, + 0xb596,0xb596,0xb596,0xb596,0xb5b6,0xb5b6,0xb5b6,0xb5b6, + 0xbdd7,0xbdd7,0xbdd7,0xbdd7,0xbdf7,0xbdf7,0xbdf7,0xbdf7, + 0xc618,0xc618,0xc618,0xc618,0xc638,0xc638,0xc638,0xc638, + 0xce59,0xce59,0xce59,0xce59,0xce79,0xce79,0xce79,0xce79, + 0xd69a,0xd69a,0xd69a,0xd69a,0xd6ba,0xd6ba,0xd6ba,0xd6ba, + 0xdedb,0xdedb,0xdedb,0xdedb,0xdefb,0xdefb,0xdefb,0xdefb, + 0xe71c,0xe71c,0xe71c,0xe71c,0xe73c,0xe73c,0xe73c,0xe73c, + 0xef5d,0xef5d,0xef5d,0xef5d,0xef7d,0xef7d,0xef7d,0xef7d, + 0xf79e,0xf79e,0xf79e,0xf79e,0xf7be,0xf7be,0xf7be,0xf7be, + 0xffdf,0xffdf,0xffdf,0xffdf,0xffff,0xffff,0xffff,0xffff}; + +// +// C interface +// +#ifndef __cplusplus +// C API +int PNG_openRAM(PNGIMAGE *pPNG, uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw) +{ + pPNG->iError = PNG_SUCCESS; + pPNG->pfnRead = readMem; + pPNG->pfnSeek = seekMem; + pPNG->pfnDraw = pfnDraw; + pPNG->pfnOpen = NULL; + pPNG->pfnClose = NULL; + pPNG->PNGFile.iSize = iDataSize; + pPNG->PNGFile.pData = pData; + return PNGInit(pPNG); +} /* PNG_openRAM() */ + +#ifdef __LINUX__ +int PNG_openFile(PNGIMAGE *pPNG, const char *szFilename, PNG_DRAW_CALLBACK *pfnDraw) +{ + pPNG->iError = PNG_SUCCESS; + pPNG->pfnRead = readFile; + pPNG->pfnSeek = seekFile; + pPNG->pfnDraw = pfnDraw; + pPNG->pfnOpen = NULL; + pPNG->pfnClose = closeFile; + pPNG->PNGFile.fHandle = fopen(szFilename, "r+b"); + if (pPNG->PNGFile.fHandle == NULL) + return 0; + fseek((FILE *)pPNG->PNGFile.fHandle, 0, SEEK_END); + pPNG->PNGFile.iSize = (int)ftell((FILE *)pPNG->PNGFile.fHandle); + fseek((FILE *)pPNG->PNGFile.fHandle, 0, SEEK_SET); + return PNGInit(pPNG); +} /* PNG_openFile() */ +#endif // __LINUX__ +void PNG_close(PNGIMAGE *pPNG) +{ + if (pPNG->pfnClose) + (*pPNG->pfnClose)(pPNG->PNGFile.fHandle); +} /* PNG_close() */ + +int PNG_getWidth(PNGIMAGE *pPNG) +{ + return pPNG->iWidth; +} /* PNG_getsWidth() */ + +int PNG_getHeight(PNGIMAGE *pPNG) +{ + return pPNG->iHeight; +} /* PNG_getHeight() */ + +int PNG_getLastError(PNGIMAGE *pPNG) +{ + return pPNG->iError; +} /* PNG_getLastError() */ + +uint8_t *PNG_getPalette(PNGIMAGE *pPNG) +{ + return pPNG->ucPalette; +} /* PNG_getPalette() */ + +int PNG_getBufferSize(PNGIMAGE *pPNG) +{ + return pPNG->iHeight * pPNG->iPitch; +} /* PNG_getBufferSize() */ + +uint8_t * PNG_getBuffer(PNGIMAGE *pPNG) +{ + return pPNG->pImage; +} /* PNG_getBuffer() */ + +#endif // !__cplusplus +PNG_STATIC uint8_t PNGMakeMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold) +{ + uint8_t alpha, c, *s, *d, *pPal; + uint8_t cHasOpaque = 0; + int i, x; + + switch (pDraw->iPixelType) { + case PNG_PIXEL_TRUECOLOR_ALPHA: // truecolor + alpha + s = pDraw->pPixels; + d = pMask; + for (x=0; xiWidth; x+=8) { // groups of 8 pixels in each byte of mask + c = 0; + for (i=0; i<8; i++) { + c <<= 1; + alpha = s[3]; + if (alpha >= ucThreshold) // if opaque 'enough', set the bit + c |= 1; + s += 4; + } + *d++ = c; + cHasOpaque |= c; + } + break; + case PNG_PIXEL_GRAY_ALPHA: + s = pDraw->pPixels; + d = pMask; + for (x=0; xiWidth; x+=8) { // groups of 8 pixels in each byte of mask + c = 0; + for (i=0; i<8; i++) { + c <<= 1; + alpha = s[1]; + if (alpha >= ucThreshold) // if opaque 'enough', set the bit + c |= 1; + s += 2; + } + *d++ = c; + cHasOpaque |= c; + } + break; + case PNG_PIXEL_INDEXED: + s = pDraw->pPixels; + pPal = &pDraw->pPalette[768]; + d = pMask; + for (x=0; xiWidth; x+=8) { // groups of 8 pixels in each byte of mask + uint8_t ucPix = 0; + c = 0; + switch (pDraw->iBpp) { + case 2: + for (i=0; i<8; i++) { + if (i == 0 || i == 4) + ucPix = *s++; + c <<= 1; + alpha = pPal[ucPix >> 6]; // get palette alpha for this color + if (alpha >= ucThreshold) // if opaque 'enough', set the bit + c |= 1; + ucPix <<= 2; + } + break; + case 4: + for (i=0; i<8; i++) { + if ((i & 1) == 0) + ucPix = *s++; + c <<= 1; + alpha = pPal[ucPix >> 4]; // get palette alpha for this color + if (alpha >= ucThreshold) // if opaque 'enough', set the bit + c |= 1; + ucPix <<= 4; + } + break; + case 8: + for (i=0; i<8; i++) { + c <<= 1; + alpha = pPal[s[0]]; // get palette alpha for this color + if (alpha >= ucThreshold) // if opaque 'enough', set the bit + c |= 1; + s++; + } + break; + } // switch on bit depth + *d++ = c; + cHasOpaque |= c; + } + break; + default: // No alpha channel; make a mask of all 1's + memset(pMask, 0xff, (pDraw->iWidth+7)>>3); + cHasOpaque = 1; + break; + } // switch on pixel type + return cHasOpaque; // let the caller know if any pixels are opaque +} /* PNGMakeMask() */ +// +// Convert a line of native PNG pixels into RGB565 +// handles all standard pixel types +// written for simplicity, not necessarily performance +// +PNG_STATIC void PNGRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndiannes, uint32_t u32Bkgd, int iHasAlpha) +{ + int x, j; + uint16_t usPixel, *pDest = pPixels; + uint8_t c, a, *pPal, *s = pDraw->pPixels; + + switch (pDraw->iPixelType) { + case PNG_PIXEL_GRAY_ALPHA: + for (x=0; xiWidth; x++) { + c = *s++; // gray level + a = *s++; + j = (a * c) >> 8; // multiply by the alpha + usPixel = usGrayTo565[j]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } + break; + case PNG_PIXEL_GRAYSCALE: + switch (pDraw->iBpp) { + case 8: + for (x=0; xiWidth; x++) { + c = *s++; + usPixel = (c >> 3); // blue + usPixel |= ((c >> 2) << 5); // green + usPixel |= ((c >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } + break; + case 1: + for (x=0; xiWidth; x++) { + if ((x & 7) == 0) { + c = *s++; + } + if (c & 0x80) { + usPixel = 0xffff; + } else { + usPixel = 0; + } + *pDest++ = usPixel; + c <<= 1; + } + break; + } // switch on bpp + break; + case PNG_PIXEL_TRUECOLOR: + for (x=0; xiWidth; x++) { + usPixel = (s[2] >> 3); // blue + usPixel |= ((s[1] >> 2) << 5); // green + usPixel |= ((s[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + s += 3; + } + break; + case PNG_PIXEL_INDEXED: // palette color (can be 1/2/4 or 8 bits per pixel) + if (pDraw->pFastPalette && !pDraw->iHasAlpha) { // faster RGB565 palette exists + switch (pDraw->iBpp) { + case 8: + for (x=0; xiWidth; x++) { + c = *s++; + usPixel = pDraw->pFastPalette[c]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } + break; + case 4: + for (x=0; xiWidth; x+=2) { + c = *s++; + usPixel = pDraw->pFastPalette[c >> 4]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + usPixel = pDraw->pFastPalette[c & 0xf]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } + break; + case 2: + for (x=0; xiWidth; x+=4) { + c = *s++; + for (j=0; j<4; j++) { // work on pairs of bits + usPixel = pDraw->pFastPalette[c >> 6]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + c <<= 2; + } + } + break; + case 1: + for (x=0; xiWidth; x++) { + if ((x & 7) == 0) { + c = *s++; + } + usPixel = pDraw->pFastPalette[c >> 7]; + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + c <<= 1; + } + break; + } // switch on bpp + return; + } + switch (pDraw->iBpp) { + case 8: // 8-bit palette also supports palette alpha + if (pDraw->iHasAlpha) { // use the alpha to modify the palette + for (x=0; xiWidth; x++) { + int a; + c = *s++; + a = pDraw->pPalette[768+c]; // get alpha + pPal = &pDraw->pPalette[c * 3]; + usPixel = ((pPal[2] * a) >> 11); // blue + usPixel |= (((pPal[1] * a) >> 10) << 5); // green + usPixel |= (((pPal[0] * a) >> 11) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } // for x + } else { + for (x=0; xiWidth; x++) { + c = *s++; + pPal = &pDraw->pPalette[c * 3]; + usPixel = (pPal[2] >> 3); // blue + usPixel |= ((pPal[1] >> 2) << 5); // green + usPixel |= ((pPal[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } // for x + } // not alpha palette + break; + case 4: + for (x=0; xiWidth; x+=2) { + c = *s++; + pPal = &pDraw->pPalette[(c >> 4) * 3]; + usPixel = (pPal[2] >> 3); // blue + usPixel |= ((pPal[1] >> 2) << 5); // green + usPixel |= ((pPal[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + pPal = &pDraw->pPalette[(c & 0xf) * 3]; + usPixel = (pPal[2] >> 3); // blue + usPixel |= ((pPal[1] >> 2) << 5); // green + usPixel |= ((pPal[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + } + break; + case 2: + for (x=0; xiWidth; x+=4) { + c = *s++; + for (j=0; j<4; j++) { // work on pairs of bits + pPal = &pDraw->pPalette[(c >> 6) * 3]; + usPixel = (pPal[2] >> 3); // blue + usPixel |= ((pPal[1] >> 2) << 5); // green + usPixel |= ((pPal[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + c <<= 2; + } + } + break; + case 1: + for (x=0; xiWidth; x++) { + if ((x & 7) == 0) { + c = *s++; + } + pPal = &pDraw->pPalette[(c >> 7) * 3]; + usPixel = (pPal[2] >> 3); // blue + usPixel |= ((pPal[1] >> 2) << 5); // green + usPixel |= ((pPal[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + c <<= 1; + } + break; + } // switch on bits per pixel + break; + case PNG_PIXEL_TRUECOLOR_ALPHA: // truecolor + alpha + if (u32Bkgd != 0xffffffff) { // user wants to blend it with a background color + uint32_t r, g, b, a; + uint32_t b_r, b_g, b_b; + b_r = u32Bkgd & 0xff; b_g = (u32Bkgd & 0xff00) >> 8; + b_b = (u32Bkgd >> 16) & 0xff; + uint16_t u16Clr = (u32Bkgd & 0xf8) << 8; + u16Clr |= ((u32Bkgd & 0xfc00) >> 5); + u16Clr |= ((u32Bkgd & 0xf80000) >> 19); + for (x=0; xiWidth; x++) { + r = s[0]; g = s[1]; b = s[2]; a = s[3]; + if (a == 0) + usPixel = u16Clr; + else if (a == 255) { // fully opaque + usPixel = (s[2] >> 3); // blue + usPixel |= ((s[1] >> 2) << 5); // green + usPixel |= ((s[0] >> 3) << 11); // red + } else { // mix the colors + r = ((r * a) + (b_r * (255-a))) >> 8; + g = ((g * a) + (b_g * (255-a))) >> 8; + b = ((b * a) + (b_b * (255-a))) >> 8; + usPixel = (b >> 3); // blue + usPixel |= ((g >> 2) << 5); // green + usPixel |= ((r >> 3) << 11); // red + } + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + s += 4; // skip alpha + } + } else { // ignore alpha + for (x=0; xiWidth; x++) { + usPixel = (s[2] >> 3); // blue + usPixel |= ((s[1] >> 2) << 5); // green + usPixel |= ((s[0] >> 3) << 11); // red + if (iEndiannes == PNG_RGB565_BIG_ENDIAN) + usPixel = __builtin_bswap16(usPixel); + *pDest++ = usPixel; + s += 4; // skip alpha + } + } + break; + } +} /* PNGRGB565() */ +// +// Helper functions for memory based images +// +PNG_STATIC int32_t seekMem(PNGFILE *pFile, int32_t iPosition) +{ + if (iPosition < 0) iPosition = 0; + else if (iPosition >= pFile->iSize) iPosition = pFile->iSize-1; + pFile->iPos = iPosition; + return iPosition; +} /* seekMem() */ + +PNG_STATIC int32_t readFLASH(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy_P(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readFLASH() */ + +PNG_STATIC int32_t readRAM(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + + iBytesRead = iLen; + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos; + if (iBytesRead <= 0) + return 0; + memcpy(pBuf, &pFile->pData[pFile->iPos], iBytesRead); + pFile->iPos += iBytesRead; + return iBytesRead; +} /* readRAM() */ +// +// Verify it's a PNG file and then parse the IHDR chunk +// to get basic image size/type/etc +// +PNG_STATIC int PNGParseInfo(PNGIMAGE *pPage) +{ + uint8_t *s = pPage->ucFileBuf; + int iBytesRead; + + pPage->iHasAlpha = pPage->iInterlaced = 0; + // Read a few bytes to just parse the size/pixel info + iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, 32); + if (iBytesRead < 32) { // a PNG file this tiny? probably bad + pPage->iError = PNG_INVALID_FILE; + return pPage->iError; + } + + if (MOTOLONG(s) != (int32_t)0x89504e47) { // check that it's a PNG file + pPage->iError = PNG_INVALID_FILE; + return pPage->iError; + } + if (MOTOLONG(&s[12]) == 0x49484452/*'IHDR'*/) { + pPage->iWidth = MOTOLONG(&s[16]); + pPage->iHeight = MOTOLONG(&s[20]); + pPage->ucBpp = s[24]; // bits per pixel + pPage->ucPixelType = s[25]; // pixel type + pPage->iInterlaced = s[28]; + if (pPage->iInterlaced || pPage->ucBpp > 8) { // 16-bit pixels are not supported (yet) + pPage->iError = PNG_UNSUPPORTED_FEATURE; + return pPage->iError; + } + // calculate the number of bytes per line of pixels + switch (pPage->ucPixelType) { + case PNG_PIXEL_GRAYSCALE: // grayscale + case PNG_PIXEL_INDEXED: // indexed + pPage->iPitch = (pPage->iWidth * pPage->ucBpp + 7)/8; // bytes per pixel + break; + case PNG_PIXEL_TRUECOLOR: // truecolor + pPage->iPitch = ((3 * pPage->ucBpp) * pPage->iWidth + 7)/8; + break; + case PNG_PIXEL_GRAY_ALPHA: // grayscale + alpha + pPage->iPitch = ((2 * pPage->ucBpp) * pPage->iWidth + 7)/8; + pPage->iHasAlpha = 1; + break; + case PNG_PIXEL_TRUECOLOR_ALPHA: // truecolor + alpha + pPage->iPitch = ((4 * pPage->ucBpp) * pPage->iWidth + 7)/8; + pPage->iHasAlpha = 1; + } // switch + } + if (pPage->iPitch >= PNG_MAX_BUFFERED_PIXELS) + return PNG_TOO_BIG; + + return PNG_SUCCESS; +} /* PNGParseInfo() */ +// +// De-filter the current line of pixels +// +PNG_STATIC void DeFilter(uint8_t *pCurr, uint8_t *pPrev, int iWidth, int iPitch) +{ + uint8_t ucFilter = *pCurr++; + int x, iBpp; + if (iPitch <= iWidth) + iBpp = 1; + else + iBpp = iPitch / iWidth; + + pPrev++; // skip filter of previous line + switch (ucFilter) { // switch on filter type + case PNG_FILTER_NONE: + // nothing to do :) + break; + case PNG_FILTER_SUB: + for (x=iBpp; xucFileBuf; + struct inflate_state *state; + + // Either the image buffer must be allocated or a draw callback must be set before entering + if (pPage->pImage == NULL && pPage->pfnDraw == NULL) { + pPage->iError = PNG_NO_BUFFER; + return 0; + } + // Use internal buffer to maintain the current and previous lines + pCurr = pPage->ucPixels; + pPrev = &pPage->ucPixels[pPage->iPitch+1]; + pPage->iError = PNG_SUCCESS; + // Start decoding the image + bDone = FALSE; + // Inflate the compressed image data + // The allocation functions are disabled and zlib has been modified + // to not use malloc/free and instead the buffer is part of the PNG class + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + // Insert the memory pointer here to avoid having to use malloc() inside zlib + state = (struct inflate_state FAR *)pPage->ucZLIB; + d_stream.state = (struct internal_state FAR *)state; + state->window = &pPage->ucZLIB[sizeof(inflate_state)]; // point to 32k dictionary buffer + err = inflateInit(&d_stream); +#ifdef FUTURE +// if (inpage->cCompression == PIL_COMP_IPHONE_FLATE) +// err = mz_inflateInit2(&d_stream, -15); // undocumented option which ignores header and crcs +// else +// err = mz_inflateInit2(&d_stream, 15); +#endif // FUTURE + + iFileOffset = 8; // skip PNG file signature + iOffset = 0; // internal buffer offset starts at 0 + // Read some data to start + (*pPage->pfnSeek)(&pPage->PNGFile, iFileOffset); + iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, PNG_FILE_BUF_SIZE); + iFileOffset += iBytesRead; + y = 0; + d_stream.avail_out = 0; + d_stream.next_out = pPage->pImage; + + while (y < pPage->iHeight) { // continue until fully decoded + // parse the markers until the next data block + while (!bDone) + { + iLen = MOTOLONG(&s[iOffset]); // chunk length + if (iLen < 0 || iLen + (iFileOffset - iBytesRead) > pPage->PNGFile.iSize) // invalid data + { + pPage->iError = PNG_DECODE_ERROR; + return 1; + } + iMarker = MOTOLONG(&s[iOffset+4]); + iOffset += 8; // point to the marker data + switch (iMarker) + { + case 0x44474b62: // 'bKGD' DEBUG + break; + case 0x67414d41: //'gAMA' + break; +#ifdef FUTURE + case 0x6663544C: //'fcTL' frame control block for animated PNG (need to get size of this partial image) + pPage->iWidth = MOTOLONG(&pPage->pData[iOffset + 4]); // frame width + pPage->iHeight = MOTOLONG(&pPage->pData[iOffset + 8]); // frame height + bDone = TRUE; + break; +#endif + case 0x504c5445: //'PLTE' palette colors + memset(&pPage->ucPalette[768], 0xff, 256); // assume all colors are opaque unless specified + memcpy(pPage->ucPalette, &s[iOffset], iLen); + if (iOptions & PNG_FAST_PALETTE) { // create a RGB565 palette + int i, iColors = 1 << pPage->ucBpp; + uint16_t usPixel, *d; + uint8_t *s = pPage->ucPalette; + d = (uint16_t *)&pPage->ucPixels[sizeof(pPage->ucPixels)-512]; + for (i=0; i> 3); // blue + usPixel |= ((s[1] >> 2) << 5); // green + usPixel |= ((s[0] >> 3) << 11); // red + *d++ = usPixel; + s += 3; + } + } + break; + case 0x74524e53: //'tRNS' transparency info + if (pPage->ucPixelType == PNG_PIXEL_INDEXED) // if palette exists + { + memcpy(&pPage->ucPalette[768], &s[iOffset], iLen); + pPage->iHasAlpha = 1; + } + else if (iLen == 2) // for grayscale images + { + pPage->iTransparent = s[iOffset + 1]; // lower part of 2-byte value is transparent color index + pPage->iHasAlpha = 1; + } + else if (iLen == 6) // transparent color for 24-bpp image + { + pPage->iTransparent = s[iOffset + 5]; // lower part of 2-byte value is transparent color value + pPage->iTransparent |= (s[iOffset + 3] << 8); + pPage->iTransparent |= (s[iOffset + 1] << 16); + pPage->iHasAlpha = 1; + } + break; + case 0x49444154: //'IDAT' image data block + while (iLen) { + if (iOffset >= iBytesRead) { + // we ran out of data; get some more + iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, pPage->ucFileBuf, (iLen > PNG_FILE_BUF_SIZE) ? PNG_FILE_BUF_SIZE : iLen); + iFileOffset += iBytesRead; + iOffset = 0; + } else { + // number of bytes remaining in buffer + iBytesRead -= iOffset; + } + if (iBytesRead > iLen) { // we read too much + d_stream.next_in = &pPage->ucFileBuf[iOffset]; + d_stream.avail_in = iLen; + iOffset += iLen; // point to start of next marker + iBytesRead -= iLen; // keep remaining byte count + iLen = 0; // every byte will be decoded + } else { + d_stream.next_in = &pPage->ucFileBuf[iOffset]; + d_stream.avail_in = iBytesRead; + iLen -= iBytesRead; + iOffset += iBytesRead; + iBytesRead = 0; + } + // if (iMarker == 0x66644154) // data starts at offset 4 in APNG frame data block + // { + // d_stream.next_in += 4; + // d_stream.avail_in -= 4; + // } + err = 0; + while (err == Z_OK) { + if (d_stream.avail_out == 0) { // reset for next line + d_stream.avail_out = pPage->iPitch+1; + d_stream.next_out = pCurr; + } // otherwise it could be a continuation of an unfinished line + err = inflate(&d_stream, Z_NO_FLUSH, iOptions & PNG_CHECK_CRC); + if ((err == Z_OK || err == Z_STREAM_END) && d_stream.avail_out == 0) {// successfully decoded line + DeFilter(pCurr, pPrev, pPage->iWidth, pPage->iPitch); + if (pPage->pImage == NULL) { // no image buffer, send it line by line + PNGDRAW pngd; + pngd.pUser = pUser; + pngd.iPitch = pPage->iPitch; + pngd.iWidth = pPage->iWidth; + pngd.pPalette = pPage->ucPalette; + pngd.pFastPalette = (iOptions & PNG_FAST_PALETTE) ? (uint16_t *)&pPage->ucPixels[sizeof(pPage->ucPixels)-512] : NULL; + pngd.pPixels = pCurr+1; + pngd.iPixelType = pPage->ucPixelType; + pngd.iHasAlpha = pPage->iHasAlpha; + pngd.iBpp = pPage->ucBpp; + pngd.y = y; + (*pPage->pfnDraw)(&pngd); + } else { + // copy to destination bitmap + memcpy(&pPage->pImage[y * pPage->iPitch], &pCurr[1], pPage->iPitch); + } + y++; + // swap current and previous lines + tmp = pCurr; pCurr = pPrev; pPrev = tmp; + } else { // some error + tmp = NULL; + } + } + if (err == Z_STREAM_END && d_stream.avail_out == 0) { + // successful decode, stop here + y = pPage->iHeight; + bDone = TRUE; + } else if (err == Z_DATA_ERROR || err == Z_STREAM_ERROR) { + iLen = 0; // quit now + y = pPage->iHeight; + pPage->iError = PNG_DECODE_ERROR; + bDone = TRUE; // force loop to exit with error + } else if (err == Z_BUF_ERROR) { + y |= 0; // need more data + } + } // while (iLen) + if (y != pPage->iHeight && iFileOffset < pPage->PNGFile.iSize) { + // need to read more IDAT chunks + if (iBytesRead) { // data remaining in buffer + // move the data down + memmove(pPage->ucFileBuf, &pPage->ucFileBuf[iOffset], iBytesRead); + iOffset = 0; + } else { + iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, pPage->ucFileBuf, PNG_FILE_BUF_SIZE); + iFileOffset += iBytesRead; + iOffset = 0; + } + } + break; + // case 0x69545874: //'iTXt' + // case 0x7a545874: //'zTXt' +#ifdef FUTURE + case 0x74455874: //'tEXt' + { + char szTemp[256]; + char *pDest = NULL; + memcpy(szTemp, &s[iOffset], 80); // get the label length (Title, Author, Description, Copyright, Creation Time, Software, Disclaimer, Warning, Source, Comment) + i = (int)strlen(szTemp) + 1; // start of actual text + if (strcmp(szTemp, "Comment") == 0 || strcmp(szTemp, "Description") == 0) pDest = &pPage->szComment[0]; + else if (strcmp(szTemp, "Software") == 0) pDest = &pPage->szSoftware[0]; + else if (strcmp(szTemp, "Author") == 0) pDest = &pPage->szArtist[0]; + if (pDest != NULL) + { + if ((iLen - i) < 128) + { + memcpy(pPage->szComment, &pPage->pData[iOffset + i], iLen - i); + pPage->szComment[iLen - i + 1] = 0; + } + else + { + memcpy(pPage->szComment, &pPage->pData[iOffset + i], 127); + pPage->szComment[127] = '\0'; + } + } + } + break; +#endif + } // switch + iOffset += (iLen + 4); // skip data + CRC + if (iOffset > iBytesRead-8) { // need to read more data + iFileOffset += (iOffset - iBytesRead); + (*pPage->pfnSeek)(&pPage->PNGFile, iFileOffset); + iBytesRead = (*pPage->pfnRead)(&pPage->PNGFile, s, PNG_FILE_BUF_SIZE); + iFileOffset += iBytesRead; + iOffset = 0; + } + } // while !bDone + } // while y < height + err = inflateEnd(&d_stream); + return pPage->iError; +} /* DecodePNG() */ diff --git a/libraries/PNGdec/src/zconf.h b/libraries/PNGdec/src/zconf.h new file mode 100644 index 0000000..5e1d68a --- /dev/null +++ b/libraries/PNGdec/src/zconf.h @@ -0,0 +1,534 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/libraries/PNGdec/src/zlib.h b/libraries/PNGdec/src/zlib.h new file mode 100644 index 0000000..3134972 --- /dev/null +++ b/libraries/PNGdec/src/zlib.h @@ -0,0 +1,1912 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush, int check_crc)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if any input has been consumed in a previous + deflate() call, then the input available so far is compressed with the old + level and strategy using deflate(strm, Z_BLOCK). There are three approaches + for the compression levels 0, 1..3, and 4..9 respectively. The new level + and strategy will take effect at the next call of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/libraries/PNGdec/src/zutil.c b/libraries/PNGdec/src/zutil.c new file mode 100644 index 0000000..abefc23 --- /dev/null +++ b/libraries/PNGdec/src/zutil.c @@ -0,0 +1,326 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +//#ifndef Z_SOLO +//# include "gzguts.h" +//#endif + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + (void)opaque; +// return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : +// (voidpf)calloc(items, size); + return Z_NULL; // DEBUG - no longer used +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + (void)opaque; +// free(ptr); // DEBUG - no longer used +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/libraries/PNGdec/src/zutil.h b/libraries/PNGdec/src/zutil.h new file mode 100644 index 0000000..46e8c8b --- /dev/null +++ b/libraries/PNGdec/src/zutil.h @@ -0,0 +1,271 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */