├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── README.md ├── library.properties ├── license.txt └── src ├── sbc.h └── sbc ├── formats.h ├── sbc.c ├── sbc.h ├── sbc_math.h ├── sbc_primitives.c ├── sbc_primitives.h ├── sbc_primitives_armv6.c ├── sbc_primitives_armv6.h ├── sbc_primitives_iwmmxt.c ├── sbc_primitives_iwmmxt.h ├── sbc_primitives_mmx.c ├── sbc_primitives_mmx.h ├── sbc_primitives_neon.c ├── sbc_primitives_neon.h ├── sbc_tables.h ├── sbcdec.c ├── sbcenc.c ├── sbcinfo.c └── sbctester.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "unistd.h": "c" 4 | } 5 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | # set the project name 4 | project(arduino_libsbc) 5 | 6 | # lots of warnings and all warnings as errors 7 | ## add_compile_options(-Wall -Wextra ) 8 | set(CMAKE_CXX_STANDARD 17) 9 | 10 | # define libraries 11 | add_library (arduino_libsbc 12 | "${PROJECT_SOURCE_DIR}/src/sbc/sbc.c" 13 | "${PROJECT_SOURCE_DIR}/src/sbc/sbc_primitives.c" 14 | ) 15 | 16 | target_compile_options(arduino_libsbc PRIVATE -Wdouble-promotion -Wno-ignored-attributes) 17 | target_compile_definitions(arduino_libsbc PUBLIC -DARDUINO) 18 | 19 | # define location for header files 20 | target_include_directories(arduino_libsbc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-libsbc 2 | 3 | SBC, or low-complexity subband codec, is an audio subband codec specified by the Bluetooth Special Interest Group (SIG) for the Advanced Audio Distribution Profile (A2DP). SBC is a digital audio encoder and decoder used to transfer data to Bluetooth audio output devices like headphones or loudspeakers. It can also be used on the Internet. It was designed with Bluetooth bandwidth limitations and processing power in mind to obtain a reasonably good audio quality at medium bit rates with low computational complexity. As of A2DP version 1.3, the Low Complexity Subband Coding remains the default codec and its implementation is mandatory for devices supporting that profile, but vendors are free to add their own codecs to match their needs. 4 | 5 | The current implementation can be found as part of many other projects. Unfortunately I did not find any stand alone library with only the codec, so I decided to create this project and make it Arduino compliant. 6 | 7 | 8 | ## Installation 9 | 10 | For Arduino, you can download the library as zip and call include Library -> zip library. Or you can git clone this project into the Arduino libraries folder e.g. with 11 | 12 | ``` 13 | cd ~/Documents/Arduino/libraries 14 | git clone pschatzmann/arduino-libsbc.git 15 | ``` 16 | This has the advantage that you can easily get the latest code updates by just executing the command ```git pull``` 17 | 18 | ## Documentation 19 | 20 | I recommend to use this library together with my [Arduino Audio Tools](https://github.com/pschatzmann/arduino-audio-tools). 21 | This is just one of many __codecs__ that I have collected so far: Further details can be found in the [Encoding and Decoding Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Encoding-and-Decoding-of-Audio) of the Audio Tools. 22 | Last but not least here is also a link to the official [SBC documentation](https://www.bluetooth.com/specifications/specs/low-complexity-communication-codec-1-0/) 23 | 24 | 25 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=libsbc 2 | version=0.1 3 | author=Phil Schatzmann 4 | maintainer= 5 | sentence=libsbc audio decoder for Arduino 6 | paragraph=libsbc audio decoder for Arduino 7 | category=Signal Input/Output 8 | url=https://github.com/pschatzmann/arduino-libsbc 9 | architectures=* 10 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright © 2007 Free Software Foundation, Inc. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | The GNU General Public License is a free, copyleft license for software and other kinds of works. 10 | 11 | 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. 12 | 13 | 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. 14 | 15 | 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. 16 | 17 | 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. 18 | 19 | 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. 20 | 21 | 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. 22 | 23 | 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. 24 | 25 | 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. 26 | 27 | The precise terms and conditions for copying, distribution and modification follow. 28 | 29 | TERMS AND CONDITIONS 30 | 0. Definitions. 31 | “This License” refers to version 3 of the GNU General Public License. 32 | 33 | “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. 34 | 35 | “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. 36 | 37 | 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. 38 | 39 | A “covered work” means either the unmodified Program or a work based on the Program. 40 | 41 | 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. 42 | 43 | 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. 44 | 45 | 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. 46 | 47 | 1. Source Code. 48 | 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. 49 | 50 | 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. 51 | 52 | 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. 53 | 54 | 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. 55 | 56 | The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. 57 | 58 | The Corresponding Source for a work in source code form is that same work. 59 | 60 | 2. Basic Permissions. 61 | 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. 62 | 63 | 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. 64 | 65 | Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 66 | 67 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 68 | 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. 69 | 70 | 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. 71 | 72 | 4. Conveying Verbatim Copies. 73 | 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. 74 | 75 | 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. 76 | 77 | 5. Conveying Modified Source Versions. 78 | 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: 79 | 80 | a) The work must carry prominent notices stating that you modified it, and giving a relevant date. 81 | 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”. 82 | 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. 83 | 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. 84 | 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. 85 | 86 | 6. Conveying Non-Source Forms. 87 | 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: 88 | 89 | 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. 90 | 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. 91 | 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. 92 | 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. 93 | 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. 94 | 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. 95 | 96 | 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. 97 | 98 | “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. 99 | 100 | 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). 101 | 102 | 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. 103 | 104 | 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. 105 | 106 | 7. Additional Terms. 107 | “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. 108 | 109 | 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. 110 | 111 | 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: 112 | 113 | a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or 114 | 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 115 | 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 116 | d) Limiting the use for publicity purposes of names of licensors or authors of the material; or 117 | e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or 118 | 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. 119 | 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. 120 | 121 | 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. 122 | 123 | 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. 124 | 125 | 8. Termination. 126 | 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). 127 | 128 | 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. 129 | 130 | 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. 131 | 132 | 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. 133 | 134 | 9. Acceptance Not Required for Having Copies. 135 | 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. 136 | 137 | 10. Automatic Licensing of Downstream Recipients. 138 | 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. 139 | 140 | 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. 141 | 142 | 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. 143 | 144 | 11. Patents. 145 | 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”. 146 | 147 | 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. 148 | 149 | 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. 150 | 151 | 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. 152 | 153 | 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. 154 | 155 | 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. 156 | 157 | 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. 158 | 159 | 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. 160 | 161 | 12. No Surrender of Others' Freedom. 162 | 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. 163 | 164 | 13. Use with the GNU Affero General Public License. 165 | 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. 166 | 167 | 14. Revised Versions of this License. 168 | 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. 169 | 170 | 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. 171 | 172 | 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. 173 | 174 | 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. 175 | 176 | 15. Disclaimer of Warranty. 177 | 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. 178 | 179 | 16. Limitation of Liability. 180 | 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. 181 | 182 | 17. Interpretation of Sections 15 and 16. 183 | 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. 184 | 185 | END OF TERMS AND CONDITIONS 186 | 187 | -------------------------------------------------------------------------------- /src/sbc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sbc/sbc.h" -------------------------------------------------------------------------------- /src/sbc/formats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2004-2010 Marcel Holtmann 6 | * 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | * 22 | */ 23 | #pragma once 24 | 25 | #if defined(ARDUINO) 26 | # define bswap_16(v) __builtin_bswap16(v) 27 | # define bswap_32(v) __builtin_bswap32(v) 28 | #else 29 | # include 30 | #endif 31 | 32 | #if __BYTE_ORDER == __LITTLE_ENDIAN 33 | # define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) 34 | # define LE_SHORT(v) (v) 35 | # define LE_INT(v) (v) 36 | # define BE_SHORT(v) bswap_16(v) 37 | # define BE_INT(v) bswap_32(v) 38 | #elif __BYTE_ORDER == __BIG_ENDIAN 39 | # define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24)) 40 | # define LE_SHORT(v) bswap_16(v) 41 | # define LE_INT(v) bswap_32(v) 42 | # define BE_SHORT(v) (v) 43 | # define BE_INT(v) (v) 44 | #else 45 | # error "Wrong endian" 46 | #endif 47 | 48 | #define AU_MAGIC COMPOSE_ID('.','s','n','d') 49 | 50 | #define AU_FMT_ULAW 1 51 | #define AU_FMT_LIN8 2 52 | #define AU_FMT_LIN16 3 53 | 54 | struct au_header { 55 | uint32_t magic; /* '.snd' */ 56 | uint32_t hdr_size; /* size of header (min 24) */ 57 | uint32_t data_size; /* size of data */ 58 | uint32_t encoding; /* see to AU_FMT_XXXX */ 59 | uint32_t sample_rate; /* sample rate */ 60 | uint32_t channels; /* number of channels (voices) */ 61 | }; 62 | -------------------------------------------------------------------------------- /src/sbc/sbc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __SBC_H 28 | #define __SBC_H 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #include 35 | #include 36 | 37 | #ifndef SBC_FREQ_16000 38 | /* sampling frequency */ 39 | #define SBC_FREQ_16000 0x00 40 | #define SBC_FREQ_32000 0x01 41 | #define SBC_FREQ_44100 0x02 42 | #define SBC_FREQ_48000 0x03 43 | #endif 44 | 45 | 46 | /* blocks */ 47 | #define SBC_BLK_4 0x00 48 | #define SBC_BLK_8 0x01 49 | #define SBC_BLK_12 0x02 50 | #define SBC_BLK_16 0x03 51 | 52 | /* channel mode */ 53 | #define SBC_MODE_MONO 0x00 54 | #define SBC_MODE_DUAL_CHANNEL 0x01 55 | #define SBC_MODE_STEREO 0x02 56 | #define SBC_MODE_JOINT_STEREO 0x03 57 | 58 | /* allocation method */ 59 | #define SBC_AM_LOUDNESS 0x00 60 | #define SBC_AM_SNR 0x01 61 | 62 | /* subbands */ 63 | #define SBC_SB_4 0x00 64 | #define SBC_SB_8 0x01 65 | 66 | /* Data endianess */ 67 | #define SBC_LE 0x00 68 | #define SBC_BE 0x01 69 | 70 | struct sbc_struct { 71 | unsigned long flags; 72 | 73 | uint8_t frequency; 74 | uint8_t blocks; 75 | uint8_t subbands; 76 | uint8_t mode; 77 | uint8_t allocation; 78 | uint8_t bitpool; 79 | uint8_t endian; 80 | 81 | void *priv; 82 | void *priv_alloc_base; 83 | }; 84 | 85 | typedef struct sbc_struct sbc_t; 86 | 87 | int sbc_init(sbc_t *sbc, unsigned long flags); 88 | int sbc_reinit(sbc_t *sbc, unsigned long flags); 89 | 90 | ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len); 91 | 92 | /* Decodes ONE input block into ONE output block */ 93 | ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, 94 | void *output, size_t output_len, size_t *written); 95 | 96 | /* Encodes ONE input block into ONE output block */ 97 | ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, 98 | void *output, size_t output_len, ssize_t *written); 99 | 100 | /* Returns the output block size in bytes */ 101 | size_t sbc_get_frame_length(sbc_t *sbc); 102 | 103 | /* Returns the time one input/output block takes to play in msec*/ 104 | unsigned sbc_get_frame_duration(sbc_t *sbc); 105 | 106 | /* Returns the input block size in bytes */ 107 | size_t sbc_get_codesize(sbc_t *sbc); 108 | 109 | const char *sbc_get_implementation_info(sbc_t *sbc); 110 | void sbc_finish(sbc_t *sbc); 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | #endif /* __SBC_H */ 117 | -------------------------------------------------------------------------------- /src/sbc/sbc_math.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2008 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #include 28 | 29 | #define fabs(x) ((x) < 0 ? -(x) : (x)) 30 | /* C does not provide an explicit arithmetic shift right but this will 31 | always be correct and every compiler *should* generate optimal code */ 32 | #define ASR(val, bits) ((-2 >> 1 == -1) ? \ 33 | ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits))) 34 | 35 | #define SCALE_SPROTO4_TBL 12 36 | #define SCALE_SPROTO8_TBL 14 37 | #define SCALE_NPROTO4_TBL 11 38 | #define SCALE_NPROTO8_TBL 11 39 | #define SCALE4_STAGED1_BITS 15 40 | #define SCALE4_STAGED2_BITS 16 41 | #define SCALE8_STAGED1_BITS 15 42 | #define SCALE8_STAGED2_BITS 16 43 | 44 | typedef int32_t sbc_fixed_t; 45 | 46 | #define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS) 47 | #define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS) 48 | #define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS) 49 | #define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS) 50 | 51 | #define SBC_FIXED_0(val) { val = 0; } 52 | #define MUL(a, b) ((a) * (b)) 53 | #if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__)) 54 | #define MULA(a, b, res) ({ \ 55 | int tmp = res; \ 56 | __asm__( \ 57 | "mla %0, %2, %3, %0" \ 58 | : "=&r" (tmp) \ 59 | : "0" (tmp), "r" (a), "r" (b)); \ 60 | tmp; }) 61 | #else 62 | #define MULA(a, b, res) ((a) * (b) + (res)) 63 | #endif 64 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "sbc.h" 31 | #include "sbc_math.h" 32 | #include "sbc_tables.h" 33 | 34 | #include "sbc_primitives.h" 35 | #include "sbc_primitives_mmx.h" 36 | #include "sbc_primitives_iwmmxt.h" 37 | #include "sbc_primitives_neon.h" 38 | #include "sbc_primitives_armv6.h" 39 | 40 | /* 41 | * A reference C code of analysis filter with SIMD-friendly tables 42 | * reordering and code layout. This code can be used to develop platform 43 | * specific SIMD optimizations. Also it may be used as some kind of test 44 | * for compiler autovectorization capabilities (who knows, if the compiler 45 | * is very good at this stuff, hand optimized assembly may be not strictly 46 | * needed for some platform). 47 | * 48 | * Note: It is also possible to make a simple variant of analysis filter, 49 | * which needs only a single constants table without taking care about 50 | * even/odd cases. This simple variant of filter can be implemented without 51 | * input data permutation. The only thing that would be lost is the 52 | * possibility to use pairwise SIMD multiplications. But for some simple 53 | * CPU cores without SIMD extensions it can be useful. If anybody is 54 | * interested in implementing such variant of a filter, sourcecode from 55 | * bluez versions 4.26/4.27 can be used as a reference and the history of 56 | * the changes in git repository done around that time may be worth checking. 57 | */ 58 | 59 | static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out, 60 | const FIXED_T *consts) 61 | { 62 | FIXED_A t1[4]; 63 | FIXED_T t2[4]; 64 | int hop = 0; 65 | 66 | /* rounding coefficient */ 67 | t1[0] = t1[1] = t1[2] = t1[3] = 68 | (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); 69 | 70 | /* low pass polyphase filter */ 71 | for (hop = 0; hop < 40; hop += 8) { 72 | t1[0] += (FIXED_A) in[hop] * consts[hop]; 73 | t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; 74 | t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; 75 | t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; 76 | t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; 77 | t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; 78 | t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; 79 | t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; 80 | } 81 | 82 | /* scaling */ 83 | t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE; 84 | t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE; 85 | t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE; 86 | t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE; 87 | 88 | /* do the cos transform */ 89 | t1[0] = (FIXED_A) t2[0] * consts[40 + 0]; 90 | t1[0] += (FIXED_A) t2[1] * consts[40 + 1]; 91 | t1[1] = (FIXED_A) t2[0] * consts[40 + 2]; 92 | t1[1] += (FIXED_A) t2[1] * consts[40 + 3]; 93 | t1[2] = (FIXED_A) t2[0] * consts[40 + 4]; 94 | t1[2] += (FIXED_A) t2[1] * consts[40 + 5]; 95 | t1[3] = (FIXED_A) t2[0] * consts[40 + 6]; 96 | t1[3] += (FIXED_A) t2[1] * consts[40 + 7]; 97 | 98 | t1[0] += (FIXED_A) t2[2] * consts[40 + 8]; 99 | t1[0] += (FIXED_A) t2[3] * consts[40 + 9]; 100 | t1[1] += (FIXED_A) t2[2] * consts[40 + 10]; 101 | t1[1] += (FIXED_A) t2[3] * consts[40 + 11]; 102 | t1[2] += (FIXED_A) t2[2] * consts[40 + 12]; 103 | t1[2] += (FIXED_A) t2[3] * consts[40 + 13]; 104 | t1[3] += (FIXED_A) t2[2] * consts[40 + 14]; 105 | t1[3] += (FIXED_A) t2[3] * consts[40 + 15]; 106 | 107 | out[0] = t1[0] >> 108 | (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); 109 | out[1] = t1[1] >> 110 | (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); 111 | out[2] = t1[2] >> 112 | (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); 113 | out[3] = t1[3] >> 114 | (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); 115 | } 116 | 117 | static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out, 118 | const FIXED_T *consts) 119 | { 120 | FIXED_A t1[8]; 121 | FIXED_T t2[8]; 122 | int i, hop; 123 | 124 | /* rounding coefficient */ 125 | t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 126 | (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); 127 | 128 | /* low pass polyphase filter */ 129 | for (hop = 0; hop < 80; hop += 16) { 130 | t1[0] += (FIXED_A) in[hop] * consts[hop]; 131 | t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; 132 | t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; 133 | t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; 134 | t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; 135 | t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; 136 | t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; 137 | t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; 138 | t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8]; 139 | t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9]; 140 | t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10]; 141 | t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11]; 142 | t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12]; 143 | t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13]; 144 | t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14]; 145 | t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15]; 146 | } 147 | 148 | /* scaling */ 149 | t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE; 150 | t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE; 151 | t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE; 152 | t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE; 153 | t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE; 154 | t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE; 155 | t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE; 156 | t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE; 157 | 158 | 159 | /* do the cos transform */ 160 | t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0; 161 | 162 | for (i = 0; i < 4; i++) { 163 | t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0]; 164 | t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1]; 165 | t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2]; 166 | t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3]; 167 | t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4]; 168 | t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5]; 169 | t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6]; 170 | t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7]; 171 | t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8]; 172 | t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9]; 173 | t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10]; 174 | t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11]; 175 | t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12]; 176 | t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13]; 177 | t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14]; 178 | t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15]; 179 | } 180 | 181 | for (i = 0; i < 8; i++) 182 | out[i] = t1[i] >> 183 | (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS); 184 | } 185 | 186 | static inline void sbc_analyze_4b_4s_simd(int16_t *x, 187 | int32_t *out, int out_stride) 188 | { 189 | /* Analyze blocks */ 190 | sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd); 191 | out += out_stride; 192 | sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even); 193 | out += out_stride; 194 | sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd); 195 | out += out_stride; 196 | sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even); 197 | } 198 | 199 | static inline void sbc_analyze_4b_8s_simd(int16_t *x, 200 | int32_t *out, int out_stride) 201 | { 202 | /* Analyze blocks */ 203 | sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd); 204 | out += out_stride; 205 | sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even); 206 | out += out_stride; 207 | sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd); 208 | out += out_stride; 209 | sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even); 210 | } 211 | 212 | static inline int16_t unaligned16_be(const uint8_t *ptr) 213 | { 214 | return (int16_t) ((ptr[0] << 8) | ptr[1]); 215 | } 216 | 217 | static inline int16_t unaligned16_le(const uint8_t *ptr) 218 | { 219 | return (int16_t) (ptr[0] | (ptr[1] << 8)); 220 | } 221 | 222 | /* 223 | * Internal helper functions for input data processing. In order to get 224 | * optimal performance, it is important to have "nsamples", "nchannels" 225 | * and "big_endian" arguments used with this inline function as compile 226 | * time constants. 227 | */ 228 | 229 | static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal( 230 | int position, 231 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 232 | int nsamples, int nchannels, int big_endian) 233 | { 234 | /* handle X buffer wraparound */ 235 | if (position < nsamples) { 236 | if (nchannels > 0) 237 | memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position], 238 | 36 * sizeof(int16_t)); 239 | if (nchannels > 1) 240 | memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position], 241 | 36 * sizeof(int16_t)); 242 | position = SBC_X_BUFFER_SIZE - 40; 243 | } 244 | 245 | #define PCM(i) (big_endian ? \ 246 | unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) 247 | 248 | /* copy/permutate audio samples */ 249 | while ((nsamples -= 8) >= 0) { 250 | position -= 8; 251 | if (nchannels > 0) { 252 | int16_t *x = &X[0][position]; 253 | x[0] = PCM(0 + 7 * nchannels); 254 | x[1] = PCM(0 + 3 * nchannels); 255 | x[2] = PCM(0 + 6 * nchannels); 256 | x[3] = PCM(0 + 4 * nchannels); 257 | x[4] = PCM(0 + 0 * nchannels); 258 | x[5] = PCM(0 + 2 * nchannels); 259 | x[6] = PCM(0 + 1 * nchannels); 260 | x[7] = PCM(0 + 5 * nchannels); 261 | } 262 | if (nchannels > 1) { 263 | int16_t *x = &X[1][position]; 264 | x[0] = PCM(1 + 7 * nchannels); 265 | x[1] = PCM(1 + 3 * nchannels); 266 | x[2] = PCM(1 + 6 * nchannels); 267 | x[3] = PCM(1 + 4 * nchannels); 268 | x[4] = PCM(1 + 0 * nchannels); 269 | x[5] = PCM(1 + 2 * nchannels); 270 | x[6] = PCM(1 + 1 * nchannels); 271 | x[7] = PCM(1 + 5 * nchannels); 272 | } 273 | pcm += 16 * nchannels; 274 | } 275 | #undef PCM 276 | 277 | return position; 278 | } 279 | 280 | static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal( 281 | int position, 282 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 283 | int nsamples, int nchannels, int big_endian) 284 | { 285 | /* handle X buffer wraparound */ 286 | if (position < nsamples) { 287 | if (nchannels > 0) 288 | memcpy(&X[0][SBC_X_BUFFER_SIZE - 72], &X[0][position], 289 | 72 * sizeof(int16_t)); 290 | if (nchannels > 1) 291 | memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position], 292 | 72 * sizeof(int16_t)); 293 | position = SBC_X_BUFFER_SIZE - 72; 294 | } 295 | 296 | #define PCM(i) (big_endian ? \ 297 | unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) 298 | 299 | /* copy/permutate audio samples */ 300 | while ((nsamples -= 16) >= 0) { 301 | position -= 16; 302 | if (nchannels > 0) { 303 | int16_t *x = &X[0][position]; 304 | x[0] = PCM(0 + 15 * nchannels); 305 | x[1] = PCM(0 + 7 * nchannels); 306 | x[2] = PCM(0 + 14 * nchannels); 307 | x[3] = PCM(0 + 8 * nchannels); 308 | x[4] = PCM(0 + 13 * nchannels); 309 | x[5] = PCM(0 + 9 * nchannels); 310 | x[6] = PCM(0 + 12 * nchannels); 311 | x[7] = PCM(0 + 10 * nchannels); 312 | x[8] = PCM(0 + 11 * nchannels); 313 | x[9] = PCM(0 + 3 * nchannels); 314 | x[10] = PCM(0 + 6 * nchannels); 315 | x[11] = PCM(0 + 0 * nchannels); 316 | x[12] = PCM(0 + 5 * nchannels); 317 | x[13] = PCM(0 + 1 * nchannels); 318 | x[14] = PCM(0 + 4 * nchannels); 319 | x[15] = PCM(0 + 2 * nchannels); 320 | } 321 | if (nchannels > 1) { 322 | int16_t *x = &X[1][position]; 323 | x[0] = PCM(1 + 15 * nchannels); 324 | x[1] = PCM(1 + 7 * nchannels); 325 | x[2] = PCM(1 + 14 * nchannels); 326 | x[3] = PCM(1 + 8 * nchannels); 327 | x[4] = PCM(1 + 13 * nchannels); 328 | x[5] = PCM(1 + 9 * nchannels); 329 | x[6] = PCM(1 + 12 * nchannels); 330 | x[7] = PCM(1 + 10 * nchannels); 331 | x[8] = PCM(1 + 11 * nchannels); 332 | x[9] = PCM(1 + 3 * nchannels); 333 | x[10] = PCM(1 + 6 * nchannels); 334 | x[11] = PCM(1 + 0 * nchannels); 335 | x[12] = PCM(1 + 5 * nchannels); 336 | x[13] = PCM(1 + 1 * nchannels); 337 | x[14] = PCM(1 + 4 * nchannels); 338 | x[15] = PCM(1 + 2 * nchannels); 339 | } 340 | pcm += 32 * nchannels; 341 | } 342 | #undef PCM 343 | 344 | return position; 345 | } 346 | 347 | /* 348 | * Input data processing functions. The data is endian converted if needed, 349 | * channels are deintrleaved and audio samples are reordered for use in 350 | * SIMD-friendly analysis filter function. The results are put into "X" 351 | * array, getting appended to the previous data (or it is better to say 352 | * prepended, as the buffer is filled from top to bottom). Old data is 353 | * discarded when neededed, but availability of (10 * nrof_subbands) 354 | * contiguous samples is always guaranteed for the input to the analysis 355 | * filter. This is achieved by copying a sufficient part of old data 356 | * to the top of the buffer on buffer wraparound. 357 | */ 358 | 359 | static int sbc_enc_process_input_4s_le(int position, 360 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 361 | int nsamples, int nchannels) 362 | { 363 | if (nchannels > 1) 364 | return sbc_encoder_process_input_s4_internal( 365 | position, pcm, X, nsamples, 2, 0); 366 | else 367 | return sbc_encoder_process_input_s4_internal( 368 | position, pcm, X, nsamples, 1, 0); 369 | } 370 | 371 | static int sbc_enc_process_input_4s_be(int position, 372 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 373 | int nsamples, int nchannels) 374 | { 375 | if (nchannels > 1) 376 | return sbc_encoder_process_input_s4_internal( 377 | position, pcm, X, nsamples, 2, 1); 378 | else 379 | return sbc_encoder_process_input_s4_internal( 380 | position, pcm, X, nsamples, 1, 1); 381 | } 382 | 383 | static int sbc_enc_process_input_8s_le(int position, 384 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 385 | int nsamples, int nchannels) 386 | { 387 | if (nchannels > 1) 388 | return sbc_encoder_process_input_s8_internal( 389 | position, pcm, X, nsamples, 2, 0); 390 | else 391 | return sbc_encoder_process_input_s8_internal( 392 | position, pcm, X, nsamples, 1, 0); 393 | } 394 | 395 | static int sbc_enc_process_input_8s_be(int position, 396 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 397 | int nsamples, int nchannels) 398 | { 399 | if (nchannels > 1) 400 | return sbc_encoder_process_input_s8_internal( 401 | position, pcm, X, nsamples, 2, 1); 402 | else 403 | return sbc_encoder_process_input_s8_internal( 404 | position, pcm, X, nsamples, 1, 1); 405 | } 406 | 407 | /* Supplementary function to count the number of leading zeros */ 408 | 409 | static inline int sbc_clz(uint32_t x) 410 | { 411 | #ifdef __GNUC__ 412 | return __builtin_clz(x); 413 | #else 414 | /* TODO: this should be replaced with something better if good 415 | * performance is wanted when using compilers other than gcc */ 416 | int cnt = 0; 417 | while (x) { 418 | cnt++; 419 | x >>= 1; 420 | } 421 | return 32 - cnt; 422 | #endif 423 | } 424 | 425 | static void sbc_calc_scalefactors( 426 | int32_t sb_sample_f[16][2][8], 427 | uint32_t scale_factor[2][8], 428 | int blocks, int channels, int subbands) 429 | { 430 | int ch, sb, blk; 431 | for (ch = 0; ch < channels; ch++) { 432 | for (sb = 0; sb < subbands; sb++) { 433 | uint32_t x = 1 << SCALE_OUT_BITS; 434 | for (blk = 0; blk < blocks; blk++) { 435 | int32_t tmp = fabs(sb_sample_f[blk][ch][sb]); 436 | if (tmp != 0) 437 | x |= tmp - 1; 438 | } 439 | scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) - 440 | sbc_clz(x); 441 | } 442 | } 443 | } 444 | 445 | static int sbc_calc_scalefactors_j( 446 | int32_t sb_sample_f[16][2][8], 447 | uint32_t scale_factor[2][8], 448 | int blocks, int subbands) 449 | { 450 | int blk, joint = 0; 451 | int32_t tmp0, tmp1; 452 | uint32_t x, y; 453 | 454 | /* last subband does not use joint stereo */ 455 | int sb = subbands - 1; 456 | x = 1 << SCALE_OUT_BITS; 457 | y = 1 << SCALE_OUT_BITS; 458 | for (blk = 0; blk < blocks; blk++) { 459 | tmp0 = fabs(sb_sample_f[blk][0][sb]); 460 | tmp1 = fabs(sb_sample_f[blk][1][sb]); 461 | if (tmp0 != 0) 462 | x |= tmp0 - 1; 463 | if (tmp1 != 0) 464 | y |= tmp1 - 1; 465 | } 466 | scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x); 467 | scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y); 468 | 469 | /* the rest of subbands can use joint stereo */ 470 | while (--sb >= 0) { 471 | int32_t sb_sample_j[16][2]; 472 | x = 1 << SCALE_OUT_BITS; 473 | y = 1 << SCALE_OUT_BITS; 474 | for (blk = 0; blk < blocks; blk++) { 475 | tmp0 = sb_sample_f[blk][0][sb]; 476 | tmp1 = sb_sample_f[blk][1][sb]; 477 | sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1); 478 | sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1); 479 | tmp0 = fabs(tmp0); 480 | tmp1 = fabs(tmp1); 481 | if (tmp0 != 0) 482 | x |= tmp0 - 1; 483 | if (tmp1 != 0) 484 | y |= tmp1 - 1; 485 | } 486 | scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - 487 | sbc_clz(x); 488 | scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - 489 | sbc_clz(y); 490 | x = 1 << SCALE_OUT_BITS; 491 | y = 1 << SCALE_OUT_BITS; 492 | for (blk = 0; blk < blocks; blk++) { 493 | tmp0 = fabs(sb_sample_j[blk][0]); 494 | tmp1 = fabs(sb_sample_j[blk][1]); 495 | if (tmp0 != 0) 496 | x |= tmp0 - 1; 497 | if (tmp1 != 0) 498 | y |= tmp1 - 1; 499 | } 500 | x = (31 - SCALE_OUT_BITS) - sbc_clz(x); 501 | y = (31 - SCALE_OUT_BITS) - sbc_clz(y); 502 | 503 | /* decide whether to use joint stereo for this subband */ 504 | if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) { 505 | joint |= 1 << (subbands - 1 - sb); 506 | scale_factor[0][sb] = x; 507 | scale_factor[1][sb] = y; 508 | for (blk = 0; blk < blocks; blk++) { 509 | sb_sample_f[blk][0][sb] = sb_sample_j[blk][0]; 510 | sb_sample_f[blk][1][sb] = sb_sample_j[blk][1]; 511 | } 512 | } 513 | } 514 | 515 | /* bitmask with the information about subbands using joint stereo */ 516 | return joint; 517 | } 518 | 519 | /* 520 | * Detect CPU features and setup function pointers 521 | */ 522 | void sbc_init_primitives(struct sbc_encoder_state *state) 523 | { 524 | /* Default implementation for analyze functions */ 525 | state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_simd; 526 | state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_simd; 527 | 528 | /* Default implementation for input reordering / deinterleaving */ 529 | state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le; 530 | state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be; 531 | state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le; 532 | state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be; 533 | 534 | /* Default implementation for scale factors calculation */ 535 | state->sbc_calc_scalefactors = sbc_calc_scalefactors; 536 | state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j; 537 | state->implementation_info = "Generic C"; 538 | 539 | /* X86/AMD64 optimizations */ 540 | #ifdef SBC_BUILD_WITH_MMX_SUPPORT 541 | sbc_init_primitives_mmx(state); 542 | #endif 543 | 544 | /* ARM optimizations */ 545 | #ifdef SBC_BUILD_WITH_ARMV6_SUPPORT 546 | sbc_init_primitives_armv6(state); 547 | #endif 548 | #ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT 549 | sbc_init_primitives_iwmmxt(state); 550 | #endif 551 | #ifdef SBC_BUILD_WITH_NEON_SUPPORT 552 | sbc_init_primitives_neon(state); 553 | #endif 554 | } 555 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __SBC_PRIMITIVES_H 28 | #define __SBC_PRIMITIVES_H 29 | 30 | #define SCALE_OUT_BITS 15 31 | #define SBC_X_BUFFER_SIZE 328 32 | 33 | #if defined(__GNUC__) && !defined(ARDUINO) 34 | #define SBC_ALWAYS_INLINE __attribute__((always_inline)) 35 | #else 36 | #define SBC_ALWAYS_INLINE inline 37 | #endif 38 | 39 | struct sbc_encoder_state { 40 | int position; 41 | int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE]; 42 | /* Polyphase analysis filter for 4 subbands configuration, 43 | * it handles 4 blocks at once */ 44 | void (*sbc_analyze_4b_4s)(int16_t *x, int32_t *out, int out_stride); 45 | /* Polyphase analysis filter for 8 subbands configuration, 46 | * it handles 4 blocks at once */ 47 | void (*sbc_analyze_4b_8s)(int16_t *x, int32_t *out, int out_stride); 48 | /* Process input data (deinterleave, endian conversion, reordering), 49 | * depending on the number of subbands and input data byte order */ 50 | int (*sbc_enc_process_input_4s_le)(int position, 51 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 52 | int nsamples, int nchannels); 53 | int (*sbc_enc_process_input_4s_be)(int position, 54 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 55 | int nsamples, int nchannels); 56 | int (*sbc_enc_process_input_8s_le)(int position, 57 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 58 | int nsamples, int nchannels); 59 | int (*sbc_enc_process_input_8s_be)(int position, 60 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 61 | int nsamples, int nchannels); 62 | /* Scale factors calculation */ 63 | void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8], 64 | uint32_t scale_factor[2][8], 65 | int blocks, int channels, int subbands); 66 | /* Scale factors calculation with joint stereo support */ 67 | int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8], 68 | uint32_t scale_factor[2][8], 69 | int blocks, int subbands); 70 | const char *implementation_info; 71 | }; 72 | 73 | /* 74 | * Initialize pointers to the functions which are the basic "building bricks" 75 | * of SBC codec. Best implementation is selected based on target CPU 76 | * capabilities. 77 | */ 78 | void sbc_init_primitives(struct sbc_encoder_state *encoder_state); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_armv6.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | #include "sbc.h" 30 | #include "sbc_math.h" 31 | #include "sbc_tables.h" 32 | 33 | #include "sbc_primitives_armv6.h" 34 | 35 | /* 36 | * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline. 37 | */ 38 | 39 | #ifdef SBC_BUILD_WITH_ARMV6_SUPPORT 40 | 41 | static void __attribute__((naked)) sbc_analyze_four_armv6() 42 | { 43 | /* r0 = in, r1 = out, r2 = consts */ 44 | asm volatile ( 45 | "push {r1, r4-r7, lr}\n" 46 | "push {r8-r11}\n" 47 | "ldrd r4, r5, [r0, #0]\n" 48 | "ldrd r6, r7, [r2, #0]\n" 49 | "ldrd r8, r9, [r0, #16]\n" 50 | "ldrd r10, r11, [r2, #16]\n" 51 | "mov r14, #0x8000\n" 52 | "smlad r3, r4, r6, r14\n" 53 | "smlad r12, r5, r7, r14\n" 54 | "ldrd r4, r5, [r0, #32]\n" 55 | "ldrd r6, r7, [r2, #32]\n" 56 | "smlad r3, r8, r10, r3\n" 57 | "smlad r12, r9, r11, r12\n" 58 | "ldrd r8, r9, [r0, #48]\n" 59 | "ldrd r10, r11, [r2, #48]\n" 60 | "smlad r3, r4, r6, r3\n" 61 | "smlad r12, r5, r7, r12\n" 62 | "ldrd r4, r5, [r0, #64]\n" 63 | "ldrd r6, r7, [r2, #64]\n" 64 | "smlad r3, r8, r10, r3\n" 65 | "smlad r12, r9, r11, r12\n" 66 | "ldrd r8, r9, [r0, #8]\n" 67 | "ldrd r10, r11, [r2, #8]\n" 68 | "smlad r3, r4, r6, r3\n" /* t1[0] is done */ 69 | "smlad r12, r5, r7, r12\n" /* t1[1] is done */ 70 | "ldrd r4, r5, [r0, #24]\n" 71 | "ldrd r6, r7, [r2, #24]\n" 72 | "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */ 73 | "smlad r12, r8, r10, r14\n" 74 | "smlad r14, r9, r11, r14\n" 75 | "ldrd r8, r9, [r0, #40]\n" 76 | "ldrd r10, r11, [r2, #40]\n" 77 | "smlad r12, r4, r6, r12\n" 78 | "smlad r14, r5, r7, r14\n" 79 | "ldrd r4, r5, [r0, #56]\n" 80 | "ldrd r6, r7, [r2, #56]\n" 81 | "smlad r12, r8, r10, r12\n" 82 | "smlad r14, r9, r11, r14\n" 83 | "ldrd r8, r9, [r0, #72]\n" 84 | "ldrd r10, r11, [r2, #72]\n" 85 | "smlad r12, r4, r6, r12\n" 86 | "smlad r14, r5, r7, r14\n" 87 | "ldrd r4, r5, [r2, #80]\n" /* start loading cos table */ 88 | "smlad r12, r8, r10, r12\n" /* t1[2] is done */ 89 | "smlad r14, r9, r11, r14\n" /* t1[3] is done */ 90 | "ldrd r6, r7, [r2, #88]\n" 91 | "ldrd r8, r9, [r2, #96]\n" 92 | "ldrd r10, r11, [r2, #104]\n" /* cos table fully loaded */ 93 | "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */ 94 | "smuad r4, r3, r4\n" 95 | "smuad r5, r3, r5\n" 96 | "smlad r4, r12, r8, r4\n" 97 | "smlad r5, r12, r9, r5\n" 98 | "smuad r6, r3, r6\n" 99 | "smuad r7, r3, r7\n" 100 | "smlad r6, r12, r10, r6\n" 101 | "smlad r7, r12, r11, r7\n" 102 | "pop {r8-r11}\n" 103 | "stmia r1, {r4, r5, r6, r7}\n" 104 | "pop {r1, r4-r7, pc}\n" 105 | ); 106 | } 107 | 108 | #define sbc_analyze_four(in, out, consts) \ 109 | ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \ 110 | sbc_analyze_four_armv6)((in), (out), (consts)) 111 | 112 | static void __attribute__((naked)) sbc_analyze_eight_armv6() 113 | { 114 | /* r0 = in, r1 = out, r2 = consts */ 115 | asm volatile ( 116 | "push {r1, r4-r7, lr}\n" 117 | "push {r8-r11}\n" 118 | "ldrd r4, r5, [r0, #24]\n" 119 | "ldrd r6, r7, [r2, #24]\n" 120 | "ldrd r8, r9, [r0, #56]\n" 121 | "ldrd r10, r11, [r2, #56]\n" 122 | "mov r14, #0x8000\n" 123 | "smlad r3, r4, r6, r14\n" 124 | "smlad r12, r5, r7, r14\n" 125 | "ldrd r4, r5, [r0, #88]\n" 126 | "ldrd r6, r7, [r2, #88]\n" 127 | "smlad r3, r8, r10, r3\n" 128 | "smlad r12, r9, r11, r12\n" 129 | "ldrd r8, r9, [r0, #120]\n" 130 | "ldrd r10, r11, [r2, #120]\n" 131 | "smlad r3, r4, r6, r3\n" 132 | "smlad r12, r5, r7, r12\n" 133 | "ldrd r4, r5, [r0, #152]\n" 134 | "ldrd r6, r7, [r2, #152]\n" 135 | "smlad r3, r8, r10, r3\n" 136 | "smlad r12, r9, r11, r12\n" 137 | "ldrd r8, r9, [r0, #16]\n" 138 | "ldrd r10, r11, [r2, #16]\n" 139 | "smlad r3, r4, r6, r3\n" /* t1[6] is done */ 140 | "smlad r12, r5, r7, r12\n" /* t1[7] is done */ 141 | "ldrd r4, r5, [r0, #48]\n" 142 | "ldrd r6, r7, [r2, #48]\n" 143 | "pkhtb r3, r12, r3, asr #16\n" /* combine t1[6] and t1[7] */ 144 | "str r3, [sp, #-4]!\n" /* save to stack */ 145 | "smlad r3, r8, r10, r14\n" 146 | "smlad r12, r9, r11, r14\n" 147 | "ldrd r8, r9, [r0, #80]\n" 148 | "ldrd r10, r11, [r2, #80]\n" 149 | "smlad r3, r4, r6, r3\n" 150 | "smlad r12, r5, r7, r12\n" 151 | "ldrd r4, r5, [r0, #112]\n" 152 | "ldrd r6, r7, [r2, #112]\n" 153 | "smlad r3, r8, r10, r3\n" 154 | "smlad r12, r9, r11, r12\n" 155 | "ldrd r8, r9, [r0, #144]\n" 156 | "ldrd r10, r11, [r2, #144]\n" 157 | "smlad r3, r4, r6, r3\n" 158 | "smlad r12, r5, r7, r12\n" 159 | "ldrd r4, r5, [r0, #0]\n" 160 | "ldrd r6, r7, [r2, #0]\n" 161 | "smlad r3, r8, r10, r3\n" /* t1[4] is done */ 162 | "smlad r12, r9, r11, r12\n" /* t1[5] is done */ 163 | "ldrd r8, r9, [r0, #32]\n" 164 | "ldrd r10, r11, [r2, #32]\n" 165 | "pkhtb r3, r12, r3, asr #16\n" /* combine t1[4] and t1[5] */ 166 | "str r3, [sp, #-4]!\n" /* save to stack */ 167 | "smlad r3, r4, r6, r14\n" 168 | "smlad r12, r5, r7, r14\n" 169 | "ldrd r4, r5, [r0, #64]\n" 170 | "ldrd r6, r7, [r2, #64]\n" 171 | "smlad r3, r8, r10, r3\n" 172 | "smlad r12, r9, r11, r12\n" 173 | "ldrd r8, r9, [r0, #96]\n" 174 | "ldrd r10, r11, [r2, #96]\n" 175 | "smlad r3, r4, r6, r3\n" 176 | "smlad r12, r5, r7, r12\n" 177 | "ldrd r4, r5, [r0, #128]\n" 178 | "ldrd r6, r7, [r2, #128]\n" 179 | "smlad r3, r8, r10, r3\n" 180 | "smlad r12, r9, r11, r12\n" 181 | "ldrd r8, r9, [r0, #8]\n" 182 | "ldrd r10, r11, [r2, #8]\n" 183 | "smlad r3, r4, r6, r3\n" /* t1[0] is done */ 184 | "smlad r12, r5, r7, r12\n" /* t1[1] is done */ 185 | "ldrd r4, r5, [r0, #40]\n" 186 | "ldrd r6, r7, [r2, #40]\n" 187 | "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */ 188 | "smlad r12, r8, r10, r14\n" 189 | "smlad r14, r9, r11, r14\n" 190 | "ldrd r8, r9, [r0, #72]\n" 191 | "ldrd r10, r11, [r2, #72]\n" 192 | "smlad r12, r4, r6, r12\n" 193 | "smlad r14, r5, r7, r14\n" 194 | "ldrd r4, r5, [r0, #104]\n" 195 | "ldrd r6, r7, [r2, #104]\n" 196 | "smlad r12, r8, r10, r12\n" 197 | "smlad r14, r9, r11, r14\n" 198 | "ldrd r8, r9, [r0, #136]\n" 199 | "ldrd r10, r11, [r2, #136]!\n" 200 | "smlad r12, r4, r6, r12\n" 201 | "smlad r14, r5, r7, r14\n" 202 | "ldrd r4, r5, [r2, #(160 - 136 + 0)]\n" 203 | "smlad r12, r8, r10, r12\n" /* t1[2] is done */ 204 | "smlad r14, r9, r11, r14\n" /* t1[3] is done */ 205 | "ldrd r6, r7, [r2, #(160 - 136 + 8)]\n" 206 | "smuad r4, r3, r4\n" 207 | "smuad r5, r3, r5\n" 208 | "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */ 209 | /* r3 = t2[0:1] */ 210 | /* r12 = t2[2:3] */ 211 | "pop {r0, r14}\n" /* t2[4:5], t2[6:7] */ 212 | "ldrd r8, r9, [r2, #(160 - 136 + 32)]\n" 213 | "smuad r6, r3, r6\n" 214 | "smuad r7, r3, r7\n" 215 | "ldrd r10, r11, [r2, #(160 - 136 + 40)]\n" 216 | "smlad r4, r12, r8, r4\n" 217 | "smlad r5, r12, r9, r5\n" 218 | "ldrd r8, r9, [r2, #(160 - 136 + 64)]\n" 219 | "smlad r6, r12, r10, r6\n" 220 | "smlad r7, r12, r11, r7\n" 221 | "ldrd r10, r11, [r2, #(160 - 136 + 72)]\n" 222 | "smlad r4, r0, r8, r4\n" 223 | "smlad r5, r0, r9, r5\n" 224 | "ldrd r8, r9, [r2, #(160 - 136 + 96)]\n" 225 | "smlad r6, r0, r10, r6\n" 226 | "smlad r7, r0, r11, r7\n" 227 | "ldrd r10, r11, [r2, #(160 - 136 + 104)]\n" 228 | "smlad r4, r14, r8, r4\n" 229 | "smlad r5, r14, r9, r5\n" 230 | "ldrd r8, r9, [r2, #(160 - 136 + 16 + 0)]\n" 231 | "smlad r6, r14, r10, r6\n" 232 | "smlad r7, r14, r11, r7\n" 233 | "ldrd r10, r11, [r2, #(160 - 136 + 16 + 8)]\n" 234 | "stmia r1!, {r4, r5}\n" 235 | "smuad r4, r3, r8\n" 236 | "smuad r5, r3, r9\n" 237 | "ldrd r8, r9, [r2, #(160 - 136 + 16 + 32)]\n" 238 | "stmia r1!, {r6, r7}\n" 239 | "smuad r6, r3, r10\n" 240 | "smuad r7, r3, r11\n" 241 | "ldrd r10, r11, [r2, #(160 - 136 + 16 + 40)]\n" 242 | "smlad r4, r12, r8, r4\n" 243 | "smlad r5, r12, r9, r5\n" 244 | "ldrd r8, r9, [r2, #(160 - 136 + 16 + 64)]\n" 245 | "smlad r6, r12, r10, r6\n" 246 | "smlad r7, r12, r11, r7\n" 247 | "ldrd r10, r11, [r2, #(160 - 136 + 16 + 72)]\n" 248 | "smlad r4, r0, r8, r4\n" 249 | "smlad r5, r0, r9, r5\n" 250 | "ldrd r8, r9, [r2, #(160 - 136 + 16 + 96)]\n" 251 | "smlad r6, r0, r10, r6\n" 252 | "smlad r7, r0, r11, r7\n" 253 | "ldrd r10, r11, [r2, #(160 - 136 + 16 + 104)]\n" 254 | "smlad r4, r14, r8, r4\n" 255 | "smlad r5, r14, r9, r5\n" 256 | "smlad r6, r14, r10, r6\n" 257 | "smlad r7, r14, r11, r7\n" 258 | "pop {r8-r11}\n" 259 | "stmia r1!, {r4, r5, r6, r7}\n" 260 | "pop {r1, r4-r7, pc}\n" 261 | ); 262 | } 263 | 264 | #define sbc_analyze_eight(in, out, consts) \ 265 | ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \ 266 | sbc_analyze_eight_armv6)((in), (out), (consts)) 267 | 268 | static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride) 269 | { 270 | /* Analyze blocks */ 271 | sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd); 272 | out += out_stride; 273 | sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even); 274 | out += out_stride; 275 | sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd); 276 | out += out_stride; 277 | sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even); 278 | } 279 | 280 | static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride) 281 | { 282 | /* Analyze blocks */ 283 | sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd); 284 | out += out_stride; 285 | sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even); 286 | out += out_stride; 287 | sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd); 288 | out += out_stride; 289 | sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even); 290 | } 291 | 292 | void sbc_init_primitives_armv6(struct sbc_encoder_state *state) 293 | { 294 | state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6; 295 | state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6; 296 | state->implementation_info = "ARMv6 SIMD"; 297 | } 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_armv6.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __SBC_PRIMITIVES_ARMV6_H 28 | #define __SBC_PRIMITIVES_ARMV6_H 29 | 30 | #include "sbc_primitives.h" 31 | 32 | #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ 33 | defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ 34 | defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \ 35 | defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \ 36 | defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ 37 | defined(__ARM_ARCH_7M__) 38 | #define SBC_HAVE_ARMV6 1 39 | #endif 40 | 41 | #if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \ 42 | defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \ 43 | defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \ 44 | (!defined(__thumb__) || defined(__thumb2__)) 45 | 46 | #define SBC_BUILD_WITH_ARMV6_SUPPORT 47 | 48 | void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state); 49 | 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_iwmmxt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2010 Keith Mok 6 | * Copyright (C) 2008-2010 Nokia Corporation 7 | * Copyright (C) 2004-2010 Marcel Holtmann 8 | * Copyright (C) 2004-2005 Henryk Ploetz 9 | * Copyright (C) 2005-2006 Brad Midgley 10 | * 11 | * 12 | * This library is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public 14 | * License as published by the Free Software Foundation; either 15 | * version 2.1 of the License, or (at your option) any later version. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | * Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public 23 | * License along with this library; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include "sbc.h" 31 | #include "sbc_math.h" 32 | #include "sbc_tables.h" 33 | 34 | #include "sbc_primitives_iwmmxt.h" 35 | 36 | /* 37 | * IWMMXT optimizations 38 | */ 39 | 40 | #ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT 41 | 42 | static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out, 43 | const FIXED_T *consts) 44 | { 45 | asm volatile ( 46 | "wldrd wr0, [%0]\n" 47 | "tbcstw wr4, %2\n" 48 | "wldrd wr2, [%1]\n" 49 | "wldrd wr1, [%0, #8]\n" 50 | "wldrd wr3, [%1, #8]\n" 51 | "wmadds wr0, wr2, wr0\n" 52 | " wldrd wr6, [%0, #16]\n" 53 | "wmadds wr1, wr3, wr1\n" 54 | " wldrd wr7, [%0, #24]\n" 55 | "waddwss wr0, wr0, wr4\n" 56 | " wldrd wr8, [%1, #16]\n" 57 | "waddwss wr1, wr1, wr4\n" 58 | " wldrd wr9, [%1, #24]\n" 59 | " wmadds wr6, wr8, wr6\n" 60 | " wldrd wr2, [%0, #32]\n" 61 | " wmadds wr7, wr9, wr7\n" 62 | " wldrd wr3, [%0, #40]\n" 63 | " waddwss wr0, wr6, wr0\n" 64 | " wldrd wr4, [%1, #32]\n" 65 | " waddwss wr1, wr7, wr1\n" 66 | " wldrd wr5, [%1, #40]\n" 67 | " wmadds wr2, wr4, wr2\n" 68 | "wldrd wr6, [%0, #48]\n" 69 | " wmadds wr3, wr5, wr3\n" 70 | "wldrd wr7, [%0, #56]\n" 71 | " waddwss wr0, wr2, wr0\n" 72 | "wldrd wr8, [%1, #48]\n" 73 | " waddwss wr1, wr3, wr1\n" 74 | "wldrd wr9, [%1, #56]\n" 75 | "wmadds wr6, wr8, wr6\n" 76 | " wldrd wr2, [%0, #64]\n" 77 | "wmadds wr7, wr9, wr7\n" 78 | " wldrd wr3, [%0, #72]\n" 79 | "waddwss wr0, wr6, wr0\n" 80 | " wldrd wr4, [%1, #64]\n" 81 | "waddwss wr1, wr7, wr1\n" 82 | " wldrd wr5, [%1, #72]\n" 83 | " wmadds wr2, wr4, wr2\n" 84 | "tmcr wcgr0, %4\n" 85 | " wmadds wr3, wr5, wr3\n" 86 | " waddwss wr0, wr2, wr0\n" 87 | " waddwss wr1, wr3, wr1\n" 88 | "\n" 89 | "wsrawg wr0, wr0, wcgr0\n" 90 | " wldrd wr4, [%1, #80]\n" 91 | "wsrawg wr1, wr1, wcgr0\n" 92 | " wldrd wr5, [%1, #88]\n" 93 | "wpackwss wr0, wr0, wr0\n" 94 | " wldrd wr6, [%1, #96]\n" 95 | "wpackwss wr1, wr1, wr1\n" 96 | "wmadds wr2, wr5, wr0\n" 97 | " wldrd wr7, [%1, #104]\n" 98 | "wmadds wr0, wr4, wr0\n" 99 | "\n" 100 | " wmadds wr3, wr7, wr1\n" 101 | " wmadds wr1, wr6, wr1\n" 102 | " waddwss wr2, wr3, wr2\n" 103 | " waddwss wr0, wr1, wr0\n" 104 | "\n" 105 | "wstrd wr0, [%3]\n" 106 | "wstrd wr2, [%3, #8]\n" 107 | : 108 | : "r" (in), "r" (consts), 109 | "r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out), 110 | "r" (SBC_PROTO_FIXED4_SCALE) 111 | : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", 112 | "wr8", "wr9", "wcgr0", "memory"); 113 | } 114 | 115 | static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out, 116 | const FIXED_T *consts) 117 | { 118 | asm volatile ( 119 | "wldrd wr0, [%0]\n" 120 | "tbcstw wr15, %2\n" 121 | "wldrd wr1, [%0, #8]\n" 122 | "wldrd wr2, [%0, #16]\n" 123 | "wldrd wr3, [%0, #24]\n" 124 | "wldrd wr4, [%1]\n" 125 | "wldrd wr5, [%1, #8]\n" 126 | "wldrd wr6, [%1, #16]\n" 127 | "wldrd wr7, [%1, #24]\n" 128 | "wmadds wr0, wr0, wr4\n" 129 | " wldrd wr8, [%1, #32]\n" 130 | "wmadds wr1, wr1, wr5\n" 131 | " wldrd wr9, [%1, #40]\n" 132 | "wmadds wr2, wr2, wr6\n" 133 | " wldrd wr10, [%1, #48]\n" 134 | "wmadds wr3, wr3, wr7\n" 135 | " wldrd wr11, [%1, #56]\n" 136 | "waddwss wr0, wr0, wr15\n" 137 | " wldrd wr4, [%0, #32]\n" 138 | "waddwss wr1, wr1, wr15\n" 139 | " wldrd wr5, [%0, #40]\n" 140 | "waddwss wr2, wr2, wr15\n" 141 | " wldrd wr6, [%0, #48]\n" 142 | "waddwss wr3, wr3, wr15\n" 143 | " wldrd wr7, [%0, #56]\n" 144 | " wmadds wr4, wr4, wr8\n" 145 | " wldrd wr12, [%0, #64]\n" 146 | " wmadds wr5, wr5, wr9\n" 147 | " wldrd wr13, [%0, #72]\n" 148 | " wmadds wr6, wr6, wr10\n" 149 | " wldrd wr14, [%0, #80]\n" 150 | " wmadds wr7, wr7, wr11\n" 151 | " wldrd wr15, [%0, #88]\n" 152 | " waddwss wr0, wr4, wr0\n" 153 | " wldrd wr8, [%1, #64]\n" 154 | " waddwss wr1, wr5, wr1\n" 155 | " wldrd wr9, [%1, #72]\n" 156 | " waddwss wr2, wr6, wr2\n" 157 | " wldrd wr10, [%1, #80]\n" 158 | " waddwss wr3, wr7, wr3\n" 159 | " wldrd wr11, [%1, #88]\n" 160 | " wmadds wr12, wr12, wr8\n" 161 | "wldrd wr4, [%0, #96]\n" 162 | " wmadds wr13, wr13, wr9\n" 163 | "wldrd wr5, [%0, #104]\n" 164 | " wmadds wr14, wr14, wr10\n" 165 | "wldrd wr6, [%0, #112]\n" 166 | " wmadds wr15, wr15, wr11\n" 167 | "wldrd wr7, [%0, #120]\n" 168 | " waddwss wr0, wr12, wr0\n" 169 | "wldrd wr8, [%1, #96]\n" 170 | " waddwss wr1, wr13, wr1\n" 171 | "wldrd wr9, [%1, #104]\n" 172 | " waddwss wr2, wr14, wr2\n" 173 | "wldrd wr10, [%1, #112]\n" 174 | " waddwss wr3, wr15, wr3\n" 175 | "wldrd wr11, [%1, #120]\n" 176 | "wmadds wr4, wr4, wr8\n" 177 | " wldrd wr12, [%0, #128]\n" 178 | "wmadds wr5, wr5, wr9\n" 179 | " wldrd wr13, [%0, #136]\n" 180 | "wmadds wr6, wr6, wr10\n" 181 | " wldrd wr14, [%0, #144]\n" 182 | "wmadds wr7, wr7, wr11\n" 183 | " wldrd wr15, [%0, #152]\n" 184 | "waddwss wr0, wr4, wr0\n" 185 | " wldrd wr8, [%1, #128]\n" 186 | "waddwss wr1, wr5, wr1\n" 187 | " wldrd wr9, [%1, #136]\n" 188 | "waddwss wr2, wr6, wr2\n" 189 | " wldrd wr10, [%1, #144]\n" 190 | " waddwss wr3, wr7, wr3\n" 191 | " wldrd wr11, [%1, #152]\n" 192 | " wmadds wr12, wr12, wr8\n" 193 | "tmcr wcgr0, %4\n" 194 | " wmadds wr13, wr13, wr9\n" 195 | " wmadds wr14, wr14, wr10\n" 196 | " wmadds wr15, wr15, wr11\n" 197 | " waddwss wr0, wr12, wr0\n" 198 | " waddwss wr1, wr13, wr1\n" 199 | " waddwss wr2, wr14, wr2\n" 200 | " waddwss wr3, wr15, wr3\n" 201 | "\n" 202 | "wsrawg wr0, wr0, wcgr0\n" 203 | "wsrawg wr1, wr1, wcgr0\n" 204 | "wsrawg wr2, wr2, wcgr0\n" 205 | "wsrawg wr3, wr3, wcgr0\n" 206 | "\n" 207 | "wpackwss wr0, wr0, wr0\n" 208 | "wpackwss wr1, wr1, wr1\n" 209 | " wldrd wr4, [%1, #160]\n" 210 | "wpackwss wr2, wr2, wr2\n" 211 | " wldrd wr5, [%1, #168]\n" 212 | "wpackwss wr3, wr3, wr3\n" 213 | " wldrd wr6, [%1, #192]\n" 214 | " wmadds wr4, wr4, wr0\n" 215 | " wldrd wr7, [%1, #200]\n" 216 | " wmadds wr5, wr5, wr0\n" 217 | " wldrd wr8, [%1, #224]\n" 218 | " wmadds wr6, wr6, wr1\n" 219 | " wldrd wr9, [%1, #232]\n" 220 | " wmadds wr7, wr7, wr1\n" 221 | " waddwss wr4, wr6, wr4\n" 222 | " waddwss wr5, wr7, wr5\n" 223 | " wmadds wr8, wr8, wr2\n" 224 | "wldrd wr6, [%1, #256]\n" 225 | " wmadds wr9, wr9, wr2\n" 226 | "wldrd wr7, [%1, #264]\n" 227 | "waddwss wr4, wr8, wr4\n" 228 | " waddwss wr5, wr9, wr5\n" 229 | "wmadds wr6, wr6, wr3\n" 230 | "wmadds wr7, wr7, wr3\n" 231 | "waddwss wr4, wr6, wr4\n" 232 | "waddwss wr5, wr7, wr5\n" 233 | "\n" 234 | "wstrd wr4, [%3]\n" 235 | "wstrd wr5, [%3, #8]\n" 236 | "\n" 237 | "wldrd wr6, [%1, #176]\n" 238 | "wldrd wr5, [%1, #184]\n" 239 | "wmadds wr5, wr5, wr0\n" 240 | "wldrd wr8, [%1, #208]\n" 241 | "wmadds wr0, wr6, wr0\n" 242 | "wldrd wr9, [%1, #216]\n" 243 | "wmadds wr9, wr9, wr1\n" 244 | "wldrd wr6, [%1, #240]\n" 245 | "wmadds wr1, wr8, wr1\n" 246 | "wldrd wr7, [%1, #248]\n" 247 | "waddwss wr0, wr1, wr0\n" 248 | "waddwss wr5, wr9, wr5\n" 249 | "wmadds wr7, wr7, wr2\n" 250 | "wldrd wr8, [%1, #272]\n" 251 | "wmadds wr2, wr6, wr2\n" 252 | "wldrd wr9, [%1, #280]\n" 253 | "waddwss wr0, wr2, wr0\n" 254 | "waddwss wr5, wr7, wr5\n" 255 | "wmadds wr9, wr9, wr3\n" 256 | "wmadds wr3, wr8, wr3\n" 257 | "waddwss wr0, wr3, wr0\n" 258 | "waddwss wr5, wr9, wr5\n" 259 | "\n" 260 | "wstrd wr0, [%3, #16]\n" 261 | "wstrd wr5, [%3, #24]\n" 262 | : 263 | : "r" (in), "r" (consts), 264 | "r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out), 265 | "r" (SBC_PROTO_FIXED8_SCALE) 266 | : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", 267 | "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15", 268 | "wcgr0", "memory"); 269 | } 270 | 271 | static inline void sbc_analyze_4b_4s_iwmmxt(int16_t *x, int32_t *out, 272 | int out_stride) 273 | { 274 | /* Analyze blocks */ 275 | sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd); 276 | out += out_stride; 277 | sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even); 278 | out += out_stride; 279 | sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd); 280 | out += out_stride; 281 | sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even); 282 | } 283 | 284 | static inline void sbc_analyze_4b_8s_iwmmxt(int16_t *x, int32_t *out, 285 | int out_stride) 286 | { 287 | /* Analyze blocks */ 288 | sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd); 289 | out += out_stride; 290 | sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even); 291 | out += out_stride; 292 | sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd); 293 | out += out_stride; 294 | sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even); 295 | } 296 | 297 | void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state) 298 | { 299 | state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_iwmmxt; 300 | state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_iwmmxt; 301 | state->implementation_info = "IWMMXT"; 302 | } 303 | 304 | #endif 305 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_iwmmxt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2010 Keith Mok 6 | * Copyright (C) 2008-2010 Nokia Corporation 7 | * Copyright (C) 2004-2010 Marcel Holtmann 8 | * Copyright (C) 2004-2005 Henryk Ploetz 9 | * Copyright (C) 2005-2006 Brad Midgley 10 | * 11 | * 12 | * This library is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public 14 | * License as published by the Free Software Foundation; either 15 | * version 2.1 of the License, or (at your option) any later version. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | * Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public 23 | * License along with this library; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | * 26 | */ 27 | 28 | #ifndef __SBC_PRIMITIVES_IWMMXT_H 29 | #define __SBC_PRIMITIVES_IWMMXT_H 30 | 31 | #include "sbc_primitives.h" 32 | 33 | #if defined(__GNUC__) && defined(__IWMMXT__) && \ 34 | !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) 35 | 36 | #define SBC_BUILD_WITH_IWMMXT_SUPPORT 37 | 38 | void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state); 39 | 40 | #endif 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_mmx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | #include "sbc.h" 30 | #include "sbc_math.h" 31 | #include "sbc_tables.h" 32 | 33 | #include "sbc_primitives_mmx.h" 34 | 35 | /* 36 | * MMX optimizations 37 | */ 38 | 39 | #ifdef SBC_BUILD_WITH_MMX_SUPPORT 40 | 41 | static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out, 42 | const FIXED_T *consts) 43 | { 44 | static const SBC_ALIGNED int32_t round_c[2] = { 45 | 1 << (SBC_PROTO_FIXED4_SCALE - 1), 46 | 1 << (SBC_PROTO_FIXED4_SCALE - 1), 47 | }; 48 | asm volatile ( 49 | "movq (%0), %%mm0\n" 50 | "movq 8(%0), %%mm1\n" 51 | "pmaddwd (%1), %%mm0\n" 52 | "pmaddwd 8(%1), %%mm1\n" 53 | "paddd (%2), %%mm0\n" 54 | "paddd (%2), %%mm1\n" 55 | "\n" 56 | "movq 16(%0), %%mm2\n" 57 | "movq 24(%0), %%mm3\n" 58 | "pmaddwd 16(%1), %%mm2\n" 59 | "pmaddwd 24(%1), %%mm3\n" 60 | "paddd %%mm2, %%mm0\n" 61 | "paddd %%mm3, %%mm1\n" 62 | "\n" 63 | "movq 32(%0), %%mm2\n" 64 | "movq 40(%0), %%mm3\n" 65 | "pmaddwd 32(%1), %%mm2\n" 66 | "pmaddwd 40(%1), %%mm3\n" 67 | "paddd %%mm2, %%mm0\n" 68 | "paddd %%mm3, %%mm1\n" 69 | "\n" 70 | "movq 48(%0), %%mm2\n" 71 | "movq 56(%0), %%mm3\n" 72 | "pmaddwd 48(%1), %%mm2\n" 73 | "pmaddwd 56(%1), %%mm3\n" 74 | "paddd %%mm2, %%mm0\n" 75 | "paddd %%mm3, %%mm1\n" 76 | "\n" 77 | "movq 64(%0), %%mm2\n" 78 | "movq 72(%0), %%mm3\n" 79 | "pmaddwd 64(%1), %%mm2\n" 80 | "pmaddwd 72(%1), %%mm3\n" 81 | "paddd %%mm2, %%mm0\n" 82 | "paddd %%mm3, %%mm1\n" 83 | "\n" 84 | "psrad %4, %%mm0\n" 85 | "psrad %4, %%mm1\n" 86 | "packssdw %%mm0, %%mm0\n" 87 | "packssdw %%mm1, %%mm1\n" 88 | "\n" 89 | "movq %%mm0, %%mm2\n" 90 | "pmaddwd 80(%1), %%mm0\n" 91 | "pmaddwd 88(%1), %%mm2\n" 92 | "\n" 93 | "movq %%mm1, %%mm3\n" 94 | "pmaddwd 96(%1), %%mm1\n" 95 | "pmaddwd 104(%1), %%mm3\n" 96 | "paddd %%mm1, %%mm0\n" 97 | "paddd %%mm3, %%mm2\n" 98 | "\n" 99 | "movq %%mm0, (%3)\n" 100 | "movq %%mm2, 8(%3)\n" 101 | : 102 | : "r" (in), "r" (consts), "r" (&round_c), "r" (out), 103 | "i" (SBC_PROTO_FIXED4_SCALE) 104 | : "cc", "memory"); 105 | } 106 | 107 | static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out, 108 | const FIXED_T *consts) 109 | { 110 | static const SBC_ALIGNED int32_t round_c[2] = { 111 | 1 << (SBC_PROTO_FIXED8_SCALE - 1), 112 | 1 << (SBC_PROTO_FIXED8_SCALE - 1), 113 | }; 114 | asm volatile ( 115 | "movq (%0), %%mm0\n" 116 | "movq 8(%0), %%mm1\n" 117 | "movq 16(%0), %%mm2\n" 118 | "movq 24(%0), %%mm3\n" 119 | "pmaddwd (%1), %%mm0\n" 120 | "pmaddwd 8(%1), %%mm1\n" 121 | "pmaddwd 16(%1), %%mm2\n" 122 | "pmaddwd 24(%1), %%mm3\n" 123 | "paddd (%2), %%mm0\n" 124 | "paddd (%2), %%mm1\n" 125 | "paddd (%2), %%mm2\n" 126 | "paddd (%2), %%mm3\n" 127 | "\n" 128 | "movq 32(%0), %%mm4\n" 129 | "movq 40(%0), %%mm5\n" 130 | "movq 48(%0), %%mm6\n" 131 | "movq 56(%0), %%mm7\n" 132 | "pmaddwd 32(%1), %%mm4\n" 133 | "pmaddwd 40(%1), %%mm5\n" 134 | "pmaddwd 48(%1), %%mm6\n" 135 | "pmaddwd 56(%1), %%mm7\n" 136 | "paddd %%mm4, %%mm0\n" 137 | "paddd %%mm5, %%mm1\n" 138 | "paddd %%mm6, %%mm2\n" 139 | "paddd %%mm7, %%mm3\n" 140 | "\n" 141 | "movq 64(%0), %%mm4\n" 142 | "movq 72(%0), %%mm5\n" 143 | "movq 80(%0), %%mm6\n" 144 | "movq 88(%0), %%mm7\n" 145 | "pmaddwd 64(%1), %%mm4\n" 146 | "pmaddwd 72(%1), %%mm5\n" 147 | "pmaddwd 80(%1), %%mm6\n" 148 | "pmaddwd 88(%1), %%mm7\n" 149 | "paddd %%mm4, %%mm0\n" 150 | "paddd %%mm5, %%mm1\n" 151 | "paddd %%mm6, %%mm2\n" 152 | "paddd %%mm7, %%mm3\n" 153 | "\n" 154 | "movq 96(%0), %%mm4\n" 155 | "movq 104(%0), %%mm5\n" 156 | "movq 112(%0), %%mm6\n" 157 | "movq 120(%0), %%mm7\n" 158 | "pmaddwd 96(%1), %%mm4\n" 159 | "pmaddwd 104(%1), %%mm5\n" 160 | "pmaddwd 112(%1), %%mm6\n" 161 | "pmaddwd 120(%1), %%mm7\n" 162 | "paddd %%mm4, %%mm0\n" 163 | "paddd %%mm5, %%mm1\n" 164 | "paddd %%mm6, %%mm2\n" 165 | "paddd %%mm7, %%mm3\n" 166 | "\n" 167 | "movq 128(%0), %%mm4\n" 168 | "movq 136(%0), %%mm5\n" 169 | "movq 144(%0), %%mm6\n" 170 | "movq 152(%0), %%mm7\n" 171 | "pmaddwd 128(%1), %%mm4\n" 172 | "pmaddwd 136(%1), %%mm5\n" 173 | "pmaddwd 144(%1), %%mm6\n" 174 | "pmaddwd 152(%1), %%mm7\n" 175 | "paddd %%mm4, %%mm0\n" 176 | "paddd %%mm5, %%mm1\n" 177 | "paddd %%mm6, %%mm2\n" 178 | "paddd %%mm7, %%mm3\n" 179 | "\n" 180 | "psrad %4, %%mm0\n" 181 | "psrad %4, %%mm1\n" 182 | "psrad %4, %%mm2\n" 183 | "psrad %4, %%mm3\n" 184 | "\n" 185 | "packssdw %%mm0, %%mm0\n" 186 | "packssdw %%mm1, %%mm1\n" 187 | "packssdw %%mm2, %%mm2\n" 188 | "packssdw %%mm3, %%mm3\n" 189 | "\n" 190 | "movq %%mm0, %%mm4\n" 191 | "movq %%mm0, %%mm5\n" 192 | "pmaddwd 160(%1), %%mm4\n" 193 | "pmaddwd 168(%1), %%mm5\n" 194 | "\n" 195 | "movq %%mm1, %%mm6\n" 196 | "movq %%mm1, %%mm7\n" 197 | "pmaddwd 192(%1), %%mm6\n" 198 | "pmaddwd 200(%1), %%mm7\n" 199 | "paddd %%mm6, %%mm4\n" 200 | "paddd %%mm7, %%mm5\n" 201 | "\n" 202 | "movq %%mm2, %%mm6\n" 203 | "movq %%mm2, %%mm7\n" 204 | "pmaddwd 224(%1), %%mm6\n" 205 | "pmaddwd 232(%1), %%mm7\n" 206 | "paddd %%mm6, %%mm4\n" 207 | "paddd %%mm7, %%mm5\n" 208 | "\n" 209 | "movq %%mm3, %%mm6\n" 210 | "movq %%mm3, %%mm7\n" 211 | "pmaddwd 256(%1), %%mm6\n" 212 | "pmaddwd 264(%1), %%mm7\n" 213 | "paddd %%mm6, %%mm4\n" 214 | "paddd %%mm7, %%mm5\n" 215 | "\n" 216 | "movq %%mm4, (%3)\n" 217 | "movq %%mm5, 8(%3)\n" 218 | "\n" 219 | "movq %%mm0, %%mm5\n" 220 | "pmaddwd 176(%1), %%mm0\n" 221 | "pmaddwd 184(%1), %%mm5\n" 222 | "\n" 223 | "movq %%mm1, %%mm7\n" 224 | "pmaddwd 208(%1), %%mm1\n" 225 | "pmaddwd 216(%1), %%mm7\n" 226 | "paddd %%mm1, %%mm0\n" 227 | "paddd %%mm7, %%mm5\n" 228 | "\n" 229 | "movq %%mm2, %%mm7\n" 230 | "pmaddwd 240(%1), %%mm2\n" 231 | "pmaddwd 248(%1), %%mm7\n" 232 | "paddd %%mm2, %%mm0\n" 233 | "paddd %%mm7, %%mm5\n" 234 | "\n" 235 | "movq %%mm3, %%mm7\n" 236 | "pmaddwd 272(%1), %%mm3\n" 237 | "pmaddwd 280(%1), %%mm7\n" 238 | "paddd %%mm3, %%mm0\n" 239 | "paddd %%mm7, %%mm5\n" 240 | "\n" 241 | "movq %%mm0, 16(%3)\n" 242 | "movq %%mm5, 24(%3)\n" 243 | : 244 | : "r" (in), "r" (consts), "r" (&round_c), "r" (out), 245 | "i" (SBC_PROTO_FIXED8_SCALE) 246 | : "cc", "memory"); 247 | } 248 | 249 | static inline void sbc_analyze_4b_4s_mmx(int16_t *x, int32_t *out, 250 | int out_stride) 251 | { 252 | /* Analyze blocks */ 253 | sbc_analyze_four_mmx(x + 12, out, analysis_consts_fixed4_simd_odd); 254 | out += out_stride; 255 | sbc_analyze_four_mmx(x + 8, out, analysis_consts_fixed4_simd_even); 256 | out += out_stride; 257 | sbc_analyze_four_mmx(x + 4, out, analysis_consts_fixed4_simd_odd); 258 | out += out_stride; 259 | sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even); 260 | 261 | asm volatile ("emms\n"); 262 | } 263 | 264 | static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out, 265 | int out_stride) 266 | { 267 | /* Analyze blocks */ 268 | sbc_analyze_eight_mmx(x + 24, out, analysis_consts_fixed8_simd_odd); 269 | out += out_stride; 270 | sbc_analyze_eight_mmx(x + 16, out, analysis_consts_fixed8_simd_even); 271 | out += out_stride; 272 | sbc_analyze_eight_mmx(x + 8, out, analysis_consts_fixed8_simd_odd); 273 | out += out_stride; 274 | sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even); 275 | 276 | asm volatile ("emms\n"); 277 | } 278 | 279 | static void sbc_calc_scalefactors_mmx( 280 | int32_t sb_sample_f[16][2][8], 281 | uint32_t scale_factor[2][8], 282 | int blocks, int channels, int subbands) 283 | { 284 | static const SBC_ALIGNED int32_t consts[2] = { 285 | 1 << SCALE_OUT_BITS, 286 | 1 << SCALE_OUT_BITS, 287 | }; 288 | int ch, sb; 289 | intptr_t blk; 290 | for (ch = 0; ch < channels; ch++) { 291 | for (sb = 0; sb < subbands; sb += 2) { 292 | blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] - 293 | (char *) &sb_sample_f[0][0][0])); 294 | asm volatile ( 295 | "movq (%4), %%mm0\n" 296 | "1:\n" 297 | "movq (%1, %0), %%mm1\n" 298 | "pxor %%mm2, %%mm2\n" 299 | "pcmpgtd %%mm2, %%mm1\n" 300 | "paddd (%1, %0), %%mm1\n" 301 | "pcmpgtd %%mm1, %%mm2\n" 302 | "pxor %%mm2, %%mm1\n" 303 | 304 | "por %%mm1, %%mm0\n" 305 | 306 | "sub %2, %0\n" 307 | "jns 1b\n" 308 | 309 | "movd %%mm0, %k0\n" 310 | "psrlq $32, %%mm0\n" 311 | "bsrl %k0, %k0\n" 312 | "subl %5, %k0\n" 313 | "movl %k0, (%3)\n" 314 | 315 | "movd %%mm0, %k0\n" 316 | "bsrl %k0, %k0\n" 317 | "subl %5, %k0\n" 318 | "movl %k0, 4(%3)\n" 319 | : "+r" (blk) 320 | : "r" (&sb_sample_f[0][ch][sb]), 321 | "i" ((char *) &sb_sample_f[1][0][0] - 322 | (char *) &sb_sample_f[0][0][0]), 323 | "r" (&scale_factor[ch][sb]), 324 | "r" (&consts), 325 | "i" (SCALE_OUT_BITS) 326 | : "cc", "memory"); 327 | } 328 | } 329 | asm volatile ("emms\n"); 330 | } 331 | 332 | static int check_mmx_support(void) 333 | { 334 | #ifdef __amd64__ 335 | return 1; /* We assume that all 64-bit processors have MMX support */ 336 | #else 337 | int cpuid_feature_information; 338 | asm volatile ( 339 | /* According to Intel manual, CPUID instruction is supported 340 | * if the value of ID bit (bit 21) in EFLAGS can be modified */ 341 | "pushf\n" 342 | "movl (%%esp), %0\n" 343 | "xorl $0x200000, (%%esp)\n" /* try to modify ID bit */ 344 | "popf\n" 345 | "pushf\n" 346 | "xorl (%%esp), %0\n" /* check if ID bit changed */ 347 | "jz 1f\n" 348 | "push %%eax\n" 349 | "push %%ebx\n" 350 | "push %%ecx\n" 351 | "mov $1, %%eax\n" 352 | "cpuid\n" 353 | "pop %%ecx\n" 354 | "pop %%ebx\n" 355 | "pop %%eax\n" 356 | "1:\n" 357 | "popf\n" 358 | : "=d" (cpuid_feature_information) 359 | : 360 | : "cc"); 361 | return cpuid_feature_information & (1 << 23); 362 | #endif 363 | } 364 | 365 | void sbc_init_primitives_mmx(struct sbc_encoder_state *state) 366 | { 367 | if (check_mmx_support()) { 368 | state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx; 369 | state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx; 370 | state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx; 371 | state->implementation_info = "MMX"; 372 | } 373 | } 374 | 375 | #endif 376 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_mmx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __SBC_PRIMITIVES_MMX_H 28 | #define __SBC_PRIMITIVES_MMX_H 29 | 30 | #include "sbc_primitives.h" 31 | 32 | #if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) && \ 33 | !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) 34 | 35 | #define SBC_BUILD_WITH_MMX_SUPPORT 36 | 37 | void sbc_init_primitives_mmx(struct sbc_encoder_state *encoder_state); 38 | 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_neon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | #include "sbc.h" 30 | #include "sbc_math.h" 31 | #include "sbc_tables.h" 32 | 33 | #include "sbc_primitives_neon.h" 34 | 35 | /* 36 | * ARM NEON optimizations 37 | */ 38 | 39 | #ifdef SBC_BUILD_WITH_NEON_SUPPORT 40 | 41 | static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out, 42 | const FIXED_T *consts) 43 | { 44 | /* TODO: merge even and odd cases (or even merge all four calls to this 45 | * function) in order to have only aligned reads from 'in' array 46 | * and reduce number of load instructions */ 47 | asm volatile ( 48 | "vld1.16 {d4, d5}, [%0, :64]!\n" 49 | "vld1.16 {d8, d9}, [%1, :128]!\n" 50 | 51 | "vmull.s16 q0, d4, d8\n" 52 | "vld1.16 {d6, d7}, [%0, :64]!\n" 53 | "vmull.s16 q1, d5, d9\n" 54 | "vld1.16 {d10, d11}, [%1, :128]!\n" 55 | 56 | "vmlal.s16 q0, d6, d10\n" 57 | "vld1.16 {d4, d5}, [%0, :64]!\n" 58 | "vmlal.s16 q1, d7, d11\n" 59 | "vld1.16 {d8, d9}, [%1, :128]!\n" 60 | 61 | "vmlal.s16 q0, d4, d8\n" 62 | "vld1.16 {d6, d7}, [%0, :64]!\n" 63 | "vmlal.s16 q1, d5, d9\n" 64 | "vld1.16 {d10, d11}, [%1, :128]!\n" 65 | 66 | "vmlal.s16 q0, d6, d10\n" 67 | "vld1.16 {d4, d5}, [%0, :64]!\n" 68 | "vmlal.s16 q1, d7, d11\n" 69 | "vld1.16 {d8, d9}, [%1, :128]!\n" 70 | 71 | "vmlal.s16 q0, d4, d8\n" 72 | "vmlal.s16 q1, d5, d9\n" 73 | 74 | "vpadd.s32 d0, d0, d1\n" 75 | "vpadd.s32 d1, d2, d3\n" 76 | 77 | "vrshrn.s32 d0, q0, %3\n" 78 | 79 | "vld1.16 {d2, d3, d4, d5}, [%1, :128]!\n" 80 | 81 | "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */ 82 | "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */ 83 | 84 | "vmull.s16 q3, d2, d0\n" 85 | "vmull.s16 q4, d3, d0\n" 86 | "vmlal.s16 q3, d4, d1\n" 87 | "vmlal.s16 q4, d5, d1\n" 88 | 89 | "vpadd.s32 d0, d6, d7\n" /* TODO: can be eliminated */ 90 | "vpadd.s32 d1, d8, d9\n" /* TODO: can be eliminated */ 91 | 92 | "vst1.32 {d0, d1}, [%2, :128]\n" 93 | : "+r" (in), "+r" (consts) 94 | : "r" (out), 95 | "i" (SBC_PROTO_FIXED4_SCALE) 96 | : "memory", 97 | "d0", "d1", "d2", "d3", "d4", "d5", 98 | "d6", "d7", "d8", "d9", "d10", "d11"); 99 | } 100 | 101 | static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out, 102 | const FIXED_T *consts) 103 | { 104 | /* TODO: merge even and odd cases (or even merge all four calls to this 105 | * function) in order to have only aligned reads from 'in' array 106 | * and reduce number of load instructions */ 107 | asm volatile ( 108 | "vld1.16 {d4, d5}, [%0, :64]!\n" 109 | "vld1.16 {d8, d9}, [%1, :128]!\n" 110 | 111 | "vmull.s16 q6, d4, d8\n" 112 | "vld1.16 {d6, d7}, [%0, :64]!\n" 113 | "vmull.s16 q7, d5, d9\n" 114 | "vld1.16 {d10, d11}, [%1, :128]!\n" 115 | "vmull.s16 q8, d6, d10\n" 116 | "vld1.16 {d4, d5}, [%0, :64]!\n" 117 | "vmull.s16 q9, d7, d11\n" 118 | "vld1.16 {d8, d9}, [%1, :128]!\n" 119 | 120 | "vmlal.s16 q6, d4, d8\n" 121 | "vld1.16 {d6, d7}, [%0, :64]!\n" 122 | "vmlal.s16 q7, d5, d9\n" 123 | "vld1.16 {d10, d11}, [%1, :128]!\n" 124 | "vmlal.s16 q8, d6, d10\n" 125 | "vld1.16 {d4, d5}, [%0, :64]!\n" 126 | "vmlal.s16 q9, d7, d11\n" 127 | "vld1.16 {d8, d9}, [%1, :128]!\n" 128 | 129 | "vmlal.s16 q6, d4, d8\n" 130 | "vld1.16 {d6, d7}, [%0, :64]!\n" 131 | "vmlal.s16 q7, d5, d9\n" 132 | "vld1.16 {d10, d11}, [%1, :128]!\n" 133 | "vmlal.s16 q8, d6, d10\n" 134 | "vld1.16 {d4, d5}, [%0, :64]!\n" 135 | "vmlal.s16 q9, d7, d11\n" 136 | "vld1.16 {d8, d9}, [%1, :128]!\n" 137 | 138 | "vmlal.s16 q6, d4, d8\n" 139 | "vld1.16 {d6, d7}, [%0, :64]!\n" 140 | "vmlal.s16 q7, d5, d9\n" 141 | "vld1.16 {d10, d11}, [%1, :128]!\n" 142 | "vmlal.s16 q8, d6, d10\n" 143 | "vld1.16 {d4, d5}, [%0, :64]!\n" 144 | "vmlal.s16 q9, d7, d11\n" 145 | "vld1.16 {d8, d9}, [%1, :128]!\n" 146 | 147 | "vmlal.s16 q6, d4, d8\n" 148 | "vld1.16 {d6, d7}, [%0, :64]!\n" 149 | "vmlal.s16 q7, d5, d9\n" 150 | "vld1.16 {d10, d11}, [%1, :128]!\n" 151 | 152 | "vmlal.s16 q8, d6, d10\n" 153 | "vmlal.s16 q9, d7, d11\n" 154 | 155 | "vpadd.s32 d0, d12, d13\n" 156 | "vpadd.s32 d1, d14, d15\n" 157 | "vpadd.s32 d2, d16, d17\n" 158 | "vpadd.s32 d3, d18, d19\n" 159 | 160 | "vrshr.s32 q0, q0, %3\n" 161 | "vrshr.s32 q1, q1, %3\n" 162 | "vmovn.s32 d0, q0\n" 163 | "vmovn.s32 d1, q1\n" 164 | 165 | "vdup.i32 d3, d1[1]\n" /* TODO: can be eliminated */ 166 | "vdup.i32 d2, d1[0]\n" /* TODO: can be eliminated */ 167 | "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */ 168 | "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */ 169 | 170 | "vld1.16 {d4, d5}, [%1, :128]!\n" 171 | "vmull.s16 q6, d4, d0\n" 172 | "vld1.16 {d6, d7}, [%1, :128]!\n" 173 | "vmull.s16 q7, d5, d0\n" 174 | "vmull.s16 q8, d6, d0\n" 175 | "vmull.s16 q9, d7, d0\n" 176 | 177 | "vld1.16 {d4, d5}, [%1, :128]!\n" 178 | "vmlal.s16 q6, d4, d1\n" 179 | "vld1.16 {d6, d7}, [%1, :128]!\n" 180 | "vmlal.s16 q7, d5, d1\n" 181 | "vmlal.s16 q8, d6, d1\n" 182 | "vmlal.s16 q9, d7, d1\n" 183 | 184 | "vld1.16 {d4, d5}, [%1, :128]!\n" 185 | "vmlal.s16 q6, d4, d2\n" 186 | "vld1.16 {d6, d7}, [%1, :128]!\n" 187 | "vmlal.s16 q7, d5, d2\n" 188 | "vmlal.s16 q8, d6, d2\n" 189 | "vmlal.s16 q9, d7, d2\n" 190 | 191 | "vld1.16 {d4, d5}, [%1, :128]!\n" 192 | "vmlal.s16 q6, d4, d3\n" 193 | "vld1.16 {d6, d7}, [%1, :128]!\n" 194 | "vmlal.s16 q7, d5, d3\n" 195 | "vmlal.s16 q8, d6, d3\n" 196 | "vmlal.s16 q9, d7, d3\n" 197 | 198 | "vpadd.s32 d0, d12, d13\n" /* TODO: can be eliminated */ 199 | "vpadd.s32 d1, d14, d15\n" /* TODO: can be eliminated */ 200 | "vpadd.s32 d2, d16, d17\n" /* TODO: can be eliminated */ 201 | "vpadd.s32 d3, d18, d19\n" /* TODO: can be eliminated */ 202 | 203 | "vst1.32 {d0, d1, d2, d3}, [%2, :128]\n" 204 | : "+r" (in), "+r" (consts) 205 | : "r" (out), 206 | "i" (SBC_PROTO_FIXED8_SCALE) 207 | : "memory", 208 | "d0", "d1", "d2", "d3", "d4", "d5", 209 | "d6", "d7", "d8", "d9", "d10", "d11", 210 | "d12", "d13", "d14", "d15", "d16", "d17", 211 | "d18", "d19"); 212 | } 213 | 214 | static inline void sbc_analyze_4b_4s_neon(int16_t *x, 215 | int32_t *out, int out_stride) 216 | { 217 | /* Analyze blocks */ 218 | _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd); 219 | out += out_stride; 220 | _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even); 221 | out += out_stride; 222 | _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd); 223 | out += out_stride; 224 | _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even); 225 | } 226 | 227 | static inline void sbc_analyze_4b_8s_neon(int16_t *x, 228 | int32_t *out, int out_stride) 229 | { 230 | /* Analyze blocks */ 231 | _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd); 232 | out += out_stride; 233 | _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even); 234 | out += out_stride; 235 | _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd); 236 | out += out_stride; 237 | _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even); 238 | } 239 | 240 | static void sbc_calc_scalefactors_neon( 241 | int32_t sb_sample_f[16][2][8], 242 | uint32_t scale_factor[2][8], 243 | int blocks, int channels, int subbands) 244 | { 245 | int ch, sb; 246 | for (ch = 0; ch < channels; ch++) { 247 | for (sb = 0; sb < subbands; sb += 4) { 248 | int blk = blocks; 249 | int32_t *in = &sb_sample_f[0][ch][sb]; 250 | asm volatile ( 251 | "vmov.s32 q0, #0\n" 252 | "vmov.s32 q1, %[c1]\n" 253 | "vmov.s32 q14, #1\n" 254 | "vmov.s32 q15, %[c2]\n" 255 | "vadd.s32 q1, q1, q14\n" 256 | "1:\n" 257 | "vld1.32 {d16, d17}, [%[in], :128], %[inc]\n" 258 | "vabs.s32 q8, q8\n" 259 | "vld1.32 {d18, d19}, [%[in], :128], %[inc]\n" 260 | "vabs.s32 q9, q9\n" 261 | "vld1.32 {d20, d21}, [%[in], :128], %[inc]\n" 262 | "vabs.s32 q10, q10\n" 263 | "vld1.32 {d22, d23}, [%[in], :128], %[inc]\n" 264 | "vabs.s32 q11, q11\n" 265 | "vmax.s32 q0, q0, q8\n" 266 | "vmax.s32 q1, q1, q9\n" 267 | "vmax.s32 q0, q0, q10\n" 268 | "vmax.s32 q1, q1, q11\n" 269 | "subs %[blk], %[blk], #4\n" 270 | "bgt 1b\n" 271 | "vmax.s32 q0, q0, q1\n" 272 | "vsub.s32 q0, q0, q14\n" 273 | "vclz.s32 q0, q0\n" 274 | "vsub.s32 q0, q15, q0\n" 275 | "vst1.32 {d0, d1}, [%[out], :128]\n" 276 | : 277 | [blk] "+r" (blk), 278 | [in] "+r" (in) 279 | : 280 | [inc] "r" ((char *) &sb_sample_f[1][0][0] - 281 | (char *) &sb_sample_f[0][0][0]), 282 | [out] "r" (&scale_factor[ch][sb]), 283 | [c1] "i" (1 << SCALE_OUT_BITS), 284 | [c2] "i" (31 - SCALE_OUT_BITS) 285 | : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19", 286 | "d20", "d21", "d22", "d23", "d24", "d25", "d26", 287 | "d27", "d28", "d29", "d30", "d31", "cc", "memory"); 288 | } 289 | } 290 | } 291 | 292 | int sbc_calc_scalefactors_j_neon( 293 | int32_t sb_sample_f[16][2][8], 294 | uint32_t scale_factor[2][8], 295 | int blocks, int subbands) 296 | { 297 | static SBC_ALIGNED int32_t joint_bits_mask[8] = { 298 | 8, 4, 2, 1, 128, 64, 32, 16 299 | }; 300 | int joint, i; 301 | int32_t *in0, *in1; 302 | int32_t *in = &sb_sample_f[0][0][0]; 303 | uint32_t *out0, *out1; 304 | uint32_t *out = &scale_factor[0][0]; 305 | int32_t *consts = joint_bits_mask; 306 | 307 | i = subbands; 308 | 309 | asm volatile ( 310 | /* 311 | * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1 312 | * input: q0 = ((1 << SCALE_OUT_BITS) + 1) 313 | * %[in0] - samples for channel 0 314 | * %[in1] - samples for shannel 1 315 | * output: q0, q1 - scale factors without joint stereo 316 | * q2, q3 - scale factors with joint stereo 317 | * q15 - joint stereo selection mask 318 | */ 319 | ".macro calc_scalefactors\n" 320 | "vmov.s32 q1, q0\n" 321 | "vmov.s32 q2, q0\n" 322 | "vmov.s32 q3, q0\n" 323 | "mov %[i], %[blocks]\n" 324 | "1:\n" 325 | "vld1.32 {d18, d19}, [%[in1], :128], %[inc]\n" 326 | "vbic.s32 q11, q9, q14\n" 327 | "vld1.32 {d16, d17}, [%[in0], :128], %[inc]\n" 328 | "vhadd.s32 q10, q8, q11\n" 329 | "vhsub.s32 q11, q8, q11\n" 330 | "vabs.s32 q8, q8\n" 331 | "vabs.s32 q9, q9\n" 332 | "vabs.s32 q10, q10\n" 333 | "vabs.s32 q11, q11\n" 334 | "vmax.s32 q0, q0, q8\n" 335 | "vmax.s32 q1, q1, q9\n" 336 | "vmax.s32 q2, q2, q10\n" 337 | "vmax.s32 q3, q3, q11\n" 338 | "subs %[i], %[i], #1\n" 339 | "bgt 1b\n" 340 | "vsub.s32 q0, q0, q14\n" 341 | "vsub.s32 q1, q1, q14\n" 342 | "vsub.s32 q2, q2, q14\n" 343 | "vsub.s32 q3, q3, q14\n" 344 | "vclz.s32 q0, q0\n" 345 | "vclz.s32 q1, q1\n" 346 | "vclz.s32 q2, q2\n" 347 | "vclz.s32 q3, q3\n" 348 | "vsub.s32 q0, q13, q0\n" 349 | "vsub.s32 q1, q13, q1\n" 350 | "vsub.s32 q2, q13, q2\n" 351 | "vsub.s32 q3, q13, q3\n" 352 | ".endm\n" 353 | /* 354 | * constants: q14 = 1 355 | * input: q15 - joint stereo selection mask 356 | * %[in0] - value set by calc_scalefactors macro 357 | * %[in1] - value set by calc_scalefactors macro 358 | */ 359 | ".macro update_joint_stereo_samples\n" 360 | "sub %[out1], %[in1], %[inc]\n" 361 | "sub %[out0], %[in0], %[inc]\n" 362 | "sub %[in1], %[in1], %[inc], asl #1\n" 363 | "sub %[in0], %[in0], %[inc], asl #1\n" 364 | "vld1.32 {d18, d19}, [%[in1], :128]\n" 365 | "vbic.s32 q11, q9, q14\n" 366 | "vld1.32 {d16, d17}, [%[in0], :128]\n" 367 | "vld1.32 {d2, d3}, [%[out1], :128]\n" 368 | "vbic.s32 q3, q1, q14\n" 369 | "vld1.32 {d0, d1}, [%[out0], :128]\n" 370 | "vhsub.s32 q10, q8, q11\n" 371 | "vhadd.s32 q11, q8, q11\n" 372 | "vhsub.s32 q2, q0, q3\n" 373 | "vhadd.s32 q3, q0, q3\n" 374 | "vbif.s32 q10, q9, q15\n" 375 | "vbif.s32 d22, d16, d30\n" 376 | "sub %[inc], %[zero], %[inc], asl #1\n" 377 | "sub %[i], %[blocks], #2\n" 378 | "2:\n" 379 | "vbif.s32 d23, d17, d31\n" 380 | "vst1.32 {d20, d21}, [%[in1], :128], %[inc]\n" 381 | "vbif.s32 d4, d2, d30\n" 382 | "vld1.32 {d18, d19}, [%[in1], :128]\n" 383 | "vbif.s32 d5, d3, d31\n" 384 | "vst1.32 {d22, d23}, [%[in0], :128], %[inc]\n" 385 | "vbif.s32 d6, d0, d30\n" 386 | "vld1.32 {d16, d17}, [%[in0], :128]\n" 387 | "vbif.s32 d7, d1, d31\n" 388 | "vst1.32 {d4, d5}, [%[out1], :128], %[inc]\n" 389 | "vbic.s32 q11, q9, q14\n" 390 | "vld1.32 {d2, d3}, [%[out1], :128]\n" 391 | "vst1.32 {d6, d7}, [%[out0], :128], %[inc]\n" 392 | "vbic.s32 q3, q1, q14\n" 393 | "vld1.32 {d0, d1}, [%[out0], :128]\n" 394 | "vhsub.s32 q10, q8, q11\n" 395 | "vhadd.s32 q11, q8, q11\n" 396 | "vhsub.s32 q2, q0, q3\n" 397 | "vhadd.s32 q3, q0, q3\n" 398 | "vbif.s32 q10, q9, q15\n" 399 | "vbif.s32 d22, d16, d30\n" 400 | "subs %[i], %[i], #2\n" 401 | "bgt 2b\n" 402 | "sub %[inc], %[zero], %[inc], asr #1\n" 403 | "vbif.s32 d23, d17, d31\n" 404 | "vst1.32 {d20, d21}, [%[in1], :128]\n" 405 | "vbif.s32 q2, q1, q15\n" 406 | "vst1.32 {d22, d23}, [%[in0], :128]\n" 407 | "vbif.s32 q3, q0, q15\n" 408 | "vst1.32 {d4, d5}, [%[out1], :128]\n" 409 | "vst1.32 {d6, d7}, [%[out0], :128]\n" 410 | ".endm\n" 411 | 412 | "vmov.s32 q14, #1\n" 413 | "vmov.s32 q13, %[c2]\n" 414 | 415 | "cmp %[i], #4\n" 416 | "bne 8f\n" 417 | 418 | "4:\n" /* 4 subbands */ 419 | "add %[in0], %[in], #0\n" 420 | "add %[in1], %[in], #32\n" 421 | "add %[out0], %[out], #0\n" 422 | "add %[out1], %[out], #32\n" 423 | "vmov.s32 q0, %[c1]\n" 424 | "vadd.s32 q0, q0, q14\n" 425 | 426 | "calc_scalefactors\n" 427 | 428 | /* check whether to use joint stereo for subbands 0, 1, 2 */ 429 | "vadd.s32 q15, q0, q1\n" 430 | "vadd.s32 q9, q2, q3\n" 431 | "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */ 432 | "vld1.32 {d16, d17}, [%[consts], :128]!\n" 433 | "vcgt.s32 q15, q15, q9\n" 434 | 435 | /* calculate and save to memory 'joint' variable */ 436 | /* update and save scale factors to memory */ 437 | " vand.s32 q8, q8, q15\n" 438 | "vbit.s32 q0, q2, q15\n" 439 | " vpadd.s32 d16, d16, d17\n" 440 | "vbit.s32 q1, q3, q15\n" 441 | " vpadd.s32 d16, d16, d16\n" 442 | "vst1.32 {d0, d1}, [%[out0], :128]\n" 443 | "vst1.32 {d2, d3}, [%[out1], :128]\n" 444 | " vst1.32 {d16[0]}, [%[joint]]\n" 445 | 446 | "update_joint_stereo_samples\n" 447 | "b 9f\n" 448 | 449 | "8:\n" /* 8 subbands */ 450 | "add %[in0], %[in], #16\n\n" 451 | "add %[in1], %[in], #48\n" 452 | "add %[out0], %[out], #16\n\n" 453 | "add %[out1], %[out], #48\n" 454 | "vmov.s32 q0, %[c1]\n" 455 | "vadd.s32 q0, q0, q14\n" 456 | 457 | "calc_scalefactors\n" 458 | 459 | /* check whether to use joint stereo for subbands 4, 5, 6 */ 460 | "vadd.s32 q15, q0, q1\n" 461 | "vadd.s32 q9, q2, q3\n" 462 | "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */ 463 | "vld1.32 {d16, d17}, [%[consts], :128]!\n" 464 | "vcgt.s32 q15, q15, q9\n" 465 | 466 | /* calculate part of 'joint' variable and save it to d24 */ 467 | /* update and save scale factors to memory */ 468 | " vand.s32 q8, q8, q15\n" 469 | "vbit.s32 q0, q2, q15\n" 470 | " vpadd.s32 d16, d16, d17\n" 471 | "vbit.s32 q1, q3, q15\n" 472 | "vst1.32 {d0, d1}, [%[out0], :128]\n" 473 | "vst1.32 {d2, d3}, [%[out1], :128]\n" 474 | " vpadd.s32 d24, d16, d16\n" 475 | 476 | "update_joint_stereo_samples\n" 477 | 478 | "add %[in0], %[in], #0\n" 479 | "add %[in1], %[in], #32\n" 480 | "add %[out0], %[out], #0\n\n" 481 | "add %[out1], %[out], #32\n" 482 | "vmov.s32 q0, %[c1]\n" 483 | "vadd.s32 q0, q0, q14\n" 484 | 485 | "calc_scalefactors\n" 486 | 487 | /* check whether to use joint stereo for subbands 0, 1, 2, 3 */ 488 | "vadd.s32 q15, q0, q1\n" 489 | "vadd.s32 q9, q2, q3\n" 490 | "vld1.32 {d16, d17}, [%[consts], :128]!\n" 491 | "vcgt.s32 q15, q15, q9\n" 492 | 493 | /* combine last part of 'joint' with d24 and save to memory */ 494 | /* update and save scale factors to memory */ 495 | " vand.s32 q8, q8, q15\n" 496 | "vbit.s32 q0, q2, q15\n" 497 | " vpadd.s32 d16, d16, d17\n" 498 | "vbit.s32 q1, q3, q15\n" 499 | " vpadd.s32 d16, d16, d16\n" 500 | "vst1.32 {d0, d1}, [%[out0], :128]\n" 501 | " vadd.s32 d16, d16, d24\n" 502 | "vst1.32 {d2, d3}, [%[out1], :128]\n" 503 | " vst1.32 {d16[0]}, [%[joint]]\n" 504 | 505 | "update_joint_stereo_samples\n" 506 | "9:\n" 507 | ".purgem calc_scalefactors\n" 508 | ".purgem update_joint_stereo_samples\n" 509 | : 510 | [i] "+&r" (i), 511 | [in] "+&r" (in), 512 | [in0] "=&r" (in0), 513 | [in1] "=&r" (in1), 514 | [out] "+&r" (out), 515 | [out0] "=&r" (out0), 516 | [out1] "=&r" (out1), 517 | [consts] "+&r" (consts) 518 | : 519 | [inc] "r" ((char *) &sb_sample_f[1][0][0] - 520 | (char *) &sb_sample_f[0][0][0]), 521 | [blocks] "r" (blocks), 522 | [joint] "r" (&joint), 523 | [c1] "i" (1 << SCALE_OUT_BITS), 524 | [c2] "i" (31 - SCALE_OUT_BITS), 525 | [zero] "r" (0) 526 | : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 527 | "d16", "d17", "d18", "d19", "d20", "d21", "d22", 528 | "d23", "d24", "d25", "d26", "d27", "d28", "d29", 529 | "d30", "d31", "cc", "memory"); 530 | 531 | return joint; 532 | } 533 | 534 | #define PERM_BE(a, b, c, d) { \ 535 | (a * 2) + 1, (a * 2) + 0, \ 536 | (b * 2) + 1, (b * 2) + 0, \ 537 | (c * 2) + 1, (c * 2) + 0, \ 538 | (d * 2) + 1, (d * 2) + 0 \ 539 | } 540 | #define PERM_LE(a, b, c, d) { \ 541 | (a * 2) + 0, (a * 2) + 1, \ 542 | (b * 2) + 0, (b * 2) + 1, \ 543 | (c * 2) + 0, (c * 2) + 1, \ 544 | (d * 2) + 0, (d * 2) + 1 \ 545 | } 546 | 547 | static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal( 548 | int position, 549 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 550 | int nsamples, int nchannels, int big_endian) 551 | { 552 | static SBC_ALIGNED uint8_t perm_be[2][8] = { 553 | PERM_BE(7, 3, 6, 4), 554 | PERM_BE(0, 2, 1, 5) 555 | }; 556 | static SBC_ALIGNED uint8_t perm_le[2][8] = { 557 | PERM_LE(7, 3, 6, 4), 558 | PERM_LE(0, 2, 1, 5) 559 | }; 560 | /* handle X buffer wraparound */ 561 | if (position < nsamples) { 562 | int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40]; 563 | int16_t *src = &X[0][position]; 564 | asm volatile ( 565 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 566 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 567 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 568 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 569 | "vld1.16 {d0}, [%[src], :64]!\n" 570 | "vst1.16 {d0}, [%[dst], :64]!\n" 571 | : 572 | [dst] "+r" (dst), 573 | [src] "+r" (src) 574 | : : "memory", "d0", "d1", "d2", "d3"); 575 | if (nchannels > 1) { 576 | dst = &X[1][SBC_X_BUFFER_SIZE - 40]; 577 | src = &X[1][position]; 578 | asm volatile ( 579 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 580 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 581 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 582 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 583 | "vld1.16 {d0}, [%[src], :64]!\n" 584 | "vst1.16 {d0}, [%[dst], :64]!\n" 585 | : 586 | [dst] "+r" (dst), 587 | [src] "+r" (src) 588 | : : "memory", "d0", "d1", "d2", "d3"); 589 | } 590 | position = SBC_X_BUFFER_SIZE - 40; 591 | } 592 | 593 | if ((nchannels > 1) && ((uintptr_t)pcm & 1)) { 594 | /* poor 'pcm' alignment */ 595 | int16_t *x = &X[0][position]; 596 | int16_t *y = &X[1][position]; 597 | asm volatile ( 598 | "vld1.8 {d0, d1}, [%[perm], :128]\n" 599 | "1:\n" 600 | "sub %[x], %[x], #16\n" 601 | "sub %[y], %[y], #16\n" 602 | "sub %[position], %[position], #8\n" 603 | "vld1.8 {d4, d5}, [%[pcm]]!\n" 604 | "vuzp.16 d4, d5\n" 605 | "vld1.8 {d20, d21}, [%[pcm]]!\n" 606 | "vuzp.16 d20, d21\n" 607 | "vswp d5, d20\n" 608 | "vtbl.8 d16, {d4, d5}, d0\n" 609 | "vtbl.8 d17, {d4, d5}, d1\n" 610 | "vtbl.8 d18, {d20, d21}, d0\n" 611 | "vtbl.8 d19, {d20, d21}, d1\n" 612 | "vst1.16 {d16, d17}, [%[x], :128]\n" 613 | "vst1.16 {d18, d19}, [%[y], :128]\n" 614 | "subs %[nsamples], %[nsamples], #8\n" 615 | "bgt 1b\n" 616 | : 617 | [x] "+r" (x), 618 | [y] "+r" (y), 619 | [pcm] "+r" (pcm), 620 | [nsamples] "+r" (nsamples), 621 | [position] "+r" (position) 622 | : 623 | [perm] "r" (big_endian ? perm_be : perm_le) 624 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 625 | "d5", "d6", "d7", "d16", "d17", "d18", "d19", 626 | "d20", "d21", "d22", "d23"); 627 | } else if (nchannels > 1) { 628 | /* proper 'pcm' alignment */ 629 | int16_t *x = &X[0][position]; 630 | int16_t *y = &X[1][position]; 631 | asm volatile ( 632 | "vld1.8 {d0, d1}, [%[perm], :128]\n" 633 | "1:\n" 634 | "sub %[x], %[x], #16\n" 635 | "sub %[y], %[y], #16\n" 636 | "sub %[position], %[position], #8\n" 637 | "vld2.16 {d4, d5}, [%[pcm]]!\n" 638 | "vld2.16 {d20, d21}, [%[pcm]]!\n" 639 | "vswp d5, d20\n" 640 | "vtbl.8 d16, {d4, d5}, d0\n" 641 | "vtbl.8 d17, {d4, d5}, d1\n" 642 | "vtbl.8 d18, {d20, d21}, d0\n" 643 | "vtbl.8 d19, {d20, d21}, d1\n" 644 | "vst1.16 {d16, d17}, [%[x], :128]\n" 645 | "vst1.16 {d18, d19}, [%[y], :128]\n" 646 | "subs %[nsamples], %[nsamples], #8\n" 647 | "bgt 1b\n" 648 | : 649 | [x] "+r" (x), 650 | [y] "+r" (y), 651 | [pcm] "+r" (pcm), 652 | [nsamples] "+r" (nsamples), 653 | [position] "+r" (position) 654 | : 655 | [perm] "r" (big_endian ? perm_be : perm_le) 656 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 657 | "d5", "d6", "d7", "d16", "d17", "d18", "d19", 658 | "d20", "d21", "d22", "d23"); 659 | } else { 660 | int16_t *x = &X[0][position]; 661 | asm volatile ( 662 | "vld1.8 {d0, d1}, [%[perm], :128]\n" 663 | "1:\n" 664 | "sub %[x], %[x], #16\n" 665 | "sub %[position], %[position], #8\n" 666 | "vld1.8 {d4, d5}, [%[pcm]]!\n" 667 | "vtbl.8 d16, {d4, d5}, d0\n" 668 | "vtbl.8 d17, {d4, d5}, d1\n" 669 | "vst1.16 {d16, d17}, [%[x], :128]\n" 670 | "subs %[nsamples], %[nsamples], #8\n" 671 | "bgt 1b\n" 672 | : 673 | [x] "+r" (x), 674 | [pcm] "+r" (pcm), 675 | [nsamples] "+r" (nsamples), 676 | [position] "+r" (position) 677 | : 678 | [perm] "r" (big_endian ? perm_be : perm_le) 679 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 680 | "d5", "d6", "d7", "d16", "d17", "d18", "d19"); 681 | } 682 | return position; 683 | } 684 | 685 | static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal( 686 | int position, 687 | const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], 688 | int nsamples, int nchannels, int big_endian) 689 | { 690 | static SBC_ALIGNED uint8_t perm_be[4][8] = { 691 | PERM_BE(15, 7, 14, 8), 692 | PERM_BE(13, 9, 12, 10), 693 | PERM_BE(11, 3, 6, 0), 694 | PERM_BE(5, 1, 4, 2) 695 | }; 696 | static SBC_ALIGNED uint8_t perm_le[4][8] = { 697 | PERM_LE(15, 7, 14, 8), 698 | PERM_LE(13, 9, 12, 10), 699 | PERM_LE(11, 3, 6, 0), 700 | PERM_LE(5, 1, 4, 2) 701 | }; 702 | /* handle X buffer wraparound */ 703 | if (position < nsamples) { 704 | int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72]; 705 | int16_t *src = &X[0][position]; 706 | asm volatile ( 707 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 708 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 709 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 710 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 711 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 712 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 713 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 714 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 715 | "vld1.16 {d0, d1}, [%[src], :128]!\n" 716 | "vst1.16 {d0, d1}, [%[dst], :128]!\n" 717 | : 718 | [dst] "+r" (dst), 719 | [src] "+r" (src) 720 | : : "memory", "d0", "d1", "d2", "d3"); 721 | if (nchannels > 1) { 722 | dst = &X[1][SBC_X_BUFFER_SIZE - 72]; 723 | src = &X[1][position]; 724 | asm volatile ( 725 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 726 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 727 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 728 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 729 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 730 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 731 | "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" 732 | "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" 733 | "vld1.16 {d0, d1}, [%[src], :128]!\n" 734 | "vst1.16 {d0, d1}, [%[dst], :128]!\n" 735 | : 736 | [dst] "+r" (dst), 737 | [src] "+r" (src) 738 | : : "memory", "d0", "d1", "d2", "d3"); 739 | } 740 | position = SBC_X_BUFFER_SIZE - 72; 741 | } 742 | 743 | if ((nchannels > 1) && ((uintptr_t)pcm & 1)) { 744 | /* poor 'pcm' alignment */ 745 | int16_t *x = &X[0][position]; 746 | int16_t *y = &X[1][position]; 747 | asm volatile ( 748 | "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" 749 | "1:\n" 750 | "sub %[x], %[x], #32\n" 751 | "sub %[y], %[y], #32\n" 752 | "sub %[position], %[position], #16\n" 753 | "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n" 754 | "vuzp.16 q2, q3\n" 755 | "vld1.8 {d20, d21, d22, d23}, [%[pcm]]!\n" 756 | "vuzp.16 q10, q11\n" 757 | "vswp q3, q10\n" 758 | "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" 759 | "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" 760 | "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" 761 | "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" 762 | "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" 763 | "vtbl.8 d16, {d20, d21, d22, d23}, d0\n" 764 | "vtbl.8 d17, {d20, d21, d22, d23}, d1\n" 765 | "vtbl.8 d18, {d20, d21, d22, d23}, d2\n" 766 | "vtbl.8 d19, {d20, d21, d22, d23}, d3\n" 767 | "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n" 768 | "subs %[nsamples], %[nsamples], #16\n" 769 | "bgt 1b\n" 770 | : 771 | [x] "+r" (x), 772 | [y] "+r" (y), 773 | [pcm] "+r" (pcm), 774 | [nsamples] "+r" (nsamples), 775 | [position] "+r" (position) 776 | : 777 | [perm] "r" (big_endian ? perm_be : perm_le) 778 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 779 | "d5", "d6", "d7", "d16", "d17", "d18", "d19", 780 | "d20", "d21", "d22", "d23"); 781 | } else if (nchannels > 1) { 782 | /* proper 'pcm' alignment */ 783 | int16_t *x = &X[0][position]; 784 | int16_t *y = &X[1][position]; 785 | asm volatile ( 786 | "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" 787 | "1:\n" 788 | "sub %[x], %[x], #32\n" 789 | "sub %[y], %[y], #32\n" 790 | "sub %[position], %[position], #16\n" 791 | "vld2.16 {d4, d5, d6, d7}, [%[pcm]]!\n" 792 | "vld2.16 {d20, d21, d22, d23}, [%[pcm]]!\n" 793 | "vswp q3, q10\n" 794 | "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" 795 | "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" 796 | "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" 797 | "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" 798 | "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" 799 | "vtbl.8 d16, {d20, d21, d22, d23}, d0\n" 800 | "vtbl.8 d17, {d20, d21, d22, d23}, d1\n" 801 | "vtbl.8 d18, {d20, d21, d22, d23}, d2\n" 802 | "vtbl.8 d19, {d20, d21, d22, d23}, d3\n" 803 | "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n" 804 | "subs %[nsamples], %[nsamples], #16\n" 805 | "bgt 1b\n" 806 | : 807 | [x] "+r" (x), 808 | [y] "+r" (y), 809 | [pcm] "+r" (pcm), 810 | [nsamples] "+r" (nsamples), 811 | [position] "+r" (position) 812 | : 813 | [perm] "r" (big_endian ? perm_be : perm_le) 814 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 815 | "d5", "d6", "d7", "d16", "d17", "d18", "d19", 816 | "d20", "d21", "d22", "d23"); 817 | } else { 818 | int16_t *x = &X[0][position]; 819 | asm volatile ( 820 | "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" 821 | "1:\n" 822 | "sub %[x], %[x], #32\n" 823 | "sub %[position], %[position], #16\n" 824 | "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n" 825 | "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" 826 | "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" 827 | "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" 828 | "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" 829 | "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" 830 | "subs %[nsamples], %[nsamples], #16\n" 831 | "bgt 1b\n" 832 | : 833 | [x] "+r" (x), 834 | [pcm] "+r" (pcm), 835 | [nsamples] "+r" (nsamples), 836 | [position] "+r" (position) 837 | : 838 | [perm] "r" (big_endian ? perm_be : perm_le) 839 | : "cc", "memory", "d0", "d1", "d2", "d3", "d4", 840 | "d5", "d6", "d7", "d16", "d17", "d18", "d19"); 841 | } 842 | return position; 843 | } 844 | 845 | #undef PERM_BE 846 | #undef PERM_LE 847 | 848 | static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm, 849 | int16_t X[2][SBC_X_BUFFER_SIZE], 850 | int nsamples, int nchannels) 851 | { 852 | return sbc_enc_process_input_4s_neon_internal( 853 | position, pcm, X, nsamples, nchannels, 1); 854 | } 855 | 856 | static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm, 857 | int16_t X[2][SBC_X_BUFFER_SIZE], 858 | int nsamples, int nchannels) 859 | { 860 | return sbc_enc_process_input_4s_neon_internal( 861 | position, pcm, X, nsamples, nchannels, 0); 862 | } 863 | 864 | static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm, 865 | int16_t X[2][SBC_X_BUFFER_SIZE], 866 | int nsamples, int nchannels) 867 | { 868 | return sbc_enc_process_input_8s_neon_internal( 869 | position, pcm, X, nsamples, nchannels, 1); 870 | } 871 | 872 | static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm, 873 | int16_t X[2][SBC_X_BUFFER_SIZE], 874 | int nsamples, int nchannels) 875 | { 876 | return sbc_enc_process_input_8s_neon_internal( 877 | position, pcm, X, nsamples, nchannels, 0); 878 | } 879 | 880 | void sbc_init_primitives_neon(struct sbc_encoder_state *state) 881 | { 882 | state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon; 883 | state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon; 884 | state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon; 885 | state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon; 886 | state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon; 887 | state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon; 888 | state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon; 889 | state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon; 890 | state->implementation_info = "NEON"; 891 | } 892 | 893 | #endif 894 | -------------------------------------------------------------------------------- /src/sbc/sbc_primitives_neon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __SBC_PRIMITIVES_NEON_H 28 | #define __SBC_PRIMITIVES_NEON_H 29 | 30 | #include "sbc_primitives.h" 31 | 32 | #if defined(__GNUC__) && defined(__ARM_NEON__) && \ 33 | !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) 34 | 35 | #define SBC_BUILD_WITH_NEON_SUPPORT 36 | 37 | void sbc_init_primitives_neon(struct sbc_encoder_state *encoder_state); 38 | 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/sbc/sbc_tables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * Copyright (C) 2004-2005 Henryk Ploetz 8 | * Copyright (C) 2005-2006 Brad Midgley 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | /* A2DP specification: Appendix B, page 69 */ 28 | static const int sbc_offset4[4][4] = { 29 | { -1, 0, 0, 0 }, 30 | { -2, 0, 0, 1 }, 31 | { -2, 0, 0, 1 }, 32 | { -2, 0, 0, 1 } 33 | }; 34 | 35 | /* A2DP specification: Appendix B, page 69 */ 36 | static const int sbc_offset8[4][8] = { 37 | { -2, 0, 0, 0, 0, 0, 0, 1 }, 38 | { -3, 0, 0, 0, 0, 0, 1, 2 }, 39 | { -4, 0, 0, 0, 0, 0, 1, 2 }, 40 | { -4, 0, 0, 0, 0, 0, 1, 2 } 41 | }; 42 | 43 | 44 | #define SS4(val) ASR(val, SCALE_SPROTO4_TBL) 45 | #define SS8(val) ASR(val, SCALE_SPROTO8_TBL) 46 | #define SN4(val) ASR(val, SCALE_NPROTO4_TBL) 47 | #define SN8(val) ASR(val, SCALE_NPROTO8_TBL) 48 | 49 | static const int32_t sbc_proto_4_40m0[] = { 50 | SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), 51 | SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), 52 | SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), 53 | SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), 54 | SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) 55 | }; 56 | 57 | static const int32_t sbc_proto_4_40m1[] = { 58 | SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), 59 | SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), 60 | SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), 61 | SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), 62 | SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) 63 | }; 64 | 65 | static const int32_t sbc_proto_8_80m0[] = { 66 | SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), 67 | SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), 68 | SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), 69 | SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), 70 | SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), 71 | SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), 72 | SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), 73 | SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), 74 | SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), 75 | SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) 76 | }; 77 | 78 | static const int32_t sbc_proto_8_80m1[] = { 79 | SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), 80 | SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), 81 | SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), 82 | SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), 83 | SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), 84 | SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), 85 | SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), 86 | SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), 87 | SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), 88 | SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) 89 | }; 90 | 91 | static const int32_t synmatrix4[8][4] = { 92 | { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, 93 | { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, 94 | { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, 95 | { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, 96 | { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, 97 | { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, 98 | { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, 99 | { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } 100 | }; 101 | 102 | static const int32_t synmatrix8[16][8] = { 103 | { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), 104 | SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, 105 | { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), 106 | SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, 107 | { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), 108 | SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, 109 | { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), 110 | SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, 111 | { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), 112 | SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, 113 | { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), 114 | SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, 115 | { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), 116 | SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, 117 | { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), 118 | SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, 119 | { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), 120 | SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, 121 | { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), 122 | SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, 123 | { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), 124 | SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, 125 | { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), 126 | SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, 127 | { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), 128 | SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, 129 | { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), 130 | SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, 131 | { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), 132 | SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, 133 | { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), 134 | SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } 135 | }; 136 | 137 | /* Uncomment the following line to enable high precision build of SBC encoder */ 138 | 139 | /* #define SBC_HIGH_PRECISION */ 140 | 141 | #ifdef SBC_HIGH_PRECISION 142 | #define FIXED_A int64_t /* data type for fixed point accumulator */ 143 | #define FIXED_T int32_t /* data type for fixed point constants */ 144 | #define SBC_FIXED_EXTRA_BITS 16 145 | #else 146 | #define FIXED_A int32_t /* data type for fixed point accumulator */ 147 | #define FIXED_T int16_t /* data type for fixed point constants */ 148 | #define SBC_FIXED_EXTRA_BITS 0 149 | #endif 150 | 151 | /* A2DP specification: Section 12.8 Tables 152 | * 153 | * Original values are premultiplied by 2 for better precision (that is the 154 | * maximum which is possible without overflows) 155 | * 156 | * Note: in each block of 8 numbers sign was changed for elements 2 and 7 157 | * in order to compensate the same change applied to cos_table_fixed_4 158 | */ 159 | #define SBC_PROTO_FIXED4_SCALE \ 160 | ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) 161 | #define F_PROTO4(x) (FIXED_A) ((x * 2) * \ 162 | ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) 163 | #define F(x) F_PROTO4(x) 164 | static const FIXED_T _sbc_proto_fixed4[40] = { 165 | F(0.00000000E+00), F(5.36548976E-04), 166 | -F(1.49188357E-03), F(2.73370904E-03), 167 | F(3.83720193E-03), F(3.89205149E-03), 168 | F(1.86581691E-03), F(3.06012286E-03), 169 | 170 | F(1.09137620E-02), F(2.04385087E-02), 171 | -F(2.88757392E-02), F(3.21939290E-02), 172 | F(2.58767811E-02), F(6.13245186E-03), 173 | -F(2.88217274E-02), F(7.76463494E-02), 174 | 175 | F(1.35593274E-01), F(1.94987841E-01), 176 | -F(2.46636662E-01), F(2.81828203E-01), 177 | F(2.94315332E-01), F(2.81828203E-01), 178 | F(2.46636662E-01), -F(1.94987841E-01), 179 | 180 | -F(1.35593274E-01), -F(7.76463494E-02), 181 | F(2.88217274E-02), F(6.13245186E-03), 182 | F(2.58767811E-02), F(3.21939290E-02), 183 | F(2.88757392E-02), -F(2.04385087E-02), 184 | 185 | -F(1.09137620E-02), -F(3.06012286E-03), 186 | -F(1.86581691E-03), F(3.89205149E-03), 187 | F(3.83720193E-03), F(2.73370904E-03), 188 | F(1.49188357E-03), -F(5.36548976E-04), 189 | }; 190 | #undef F 191 | 192 | /* 193 | * To produce this cosine matrix in Octave: 194 | * 195 | * b = zeros(4, 8); 196 | * for i = 0:3 197 | * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4)) 198 | * endfor 199 | * endfor; 200 | * printf("%.10f, ", b'); 201 | * 202 | * Note: in each block of 8 numbers sign was changed for elements 2 and 7 203 | * 204 | * Change of sign for element 2 allows to replace constant 1.0 (not 205 | * representable in Q15 format) with -1.0 (fine with Q15). 206 | * Changed sign for element 7 allows to have more similar constants 207 | * and simplify subband filter function code. 208 | */ 209 | #define SBC_COS_TABLE_FIXED4_SCALE \ 210 | ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) 211 | #define F_COS4(x) (FIXED_A) ((x) * \ 212 | ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) 213 | #define F(x) F_COS4(x) 214 | static const FIXED_T cos_table_fixed_4[32] = { 215 | F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), 216 | F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), 217 | 218 | -F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324), 219 | -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325), 220 | 221 | -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324), 222 | -F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325), 223 | 224 | F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325), 225 | F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324), 226 | }; 227 | #undef F 228 | 229 | /* A2DP specification: Section 12.8 Tables 230 | * 231 | * Original values are premultiplied by 4 for better precision (that is the 232 | * maximum which is possible without overflows) 233 | * 234 | * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 235 | * in order to compensate the same change applied to cos_table_fixed_8 236 | */ 237 | #define SBC_PROTO_FIXED8_SCALE \ 238 | ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) 239 | #define F_PROTO8(x) (FIXED_A) ((x * 2) * \ 240 | ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) 241 | #define F(x) F_PROTO8(x) 242 | static const FIXED_T _sbc_proto_fixed8[80] = { 243 | F(0.00000000E+00), F(1.56575398E-04), 244 | F(3.43256425E-04), F(5.54620202E-04), 245 | -F(8.23919506E-04), F(1.13992507E-03), 246 | F(1.47640169E-03), F(1.78371725E-03), 247 | F(2.01182542E-03), F(2.10371989E-03), 248 | F(1.99454554E-03), F(1.61656283E-03), 249 | F(9.02154502E-04), F(1.78805361E-04), 250 | F(1.64973098E-03), F(3.49717454E-03), 251 | 252 | F(5.65949473E-03), F(8.02941163E-03), 253 | F(1.04584443E-02), F(1.27472335E-02), 254 | -F(1.46525263E-02), F(1.59045603E-02), 255 | F(1.62208471E-02), F(1.53184106E-02), 256 | F(1.29371806E-02), F(8.85757540E-03), 257 | F(2.92408442E-03), -F(4.91578024E-03), 258 | -F(1.46404076E-02), F(2.61098752E-02), 259 | F(3.90751381E-02), F(5.31873032E-02), 260 | 261 | F(6.79989431E-02), F(8.29847578E-02), 262 | F(9.75753918E-02), F(1.11196689E-01), 263 | -F(1.23264548E-01), F(1.33264415E-01), 264 | F(1.40753505E-01), F(1.45389847E-01), 265 | F(1.46955068E-01), F(1.45389847E-01), 266 | F(1.40753505E-01), F(1.33264415E-01), 267 | F(1.23264548E-01), -F(1.11196689E-01), 268 | -F(9.75753918E-02), -F(8.29847578E-02), 269 | 270 | -F(6.79989431E-02), -F(5.31873032E-02), 271 | -F(3.90751381E-02), -F(2.61098752E-02), 272 | F(1.46404076E-02), -F(4.91578024E-03), 273 | F(2.92408442E-03), F(8.85757540E-03), 274 | F(1.29371806E-02), F(1.53184106E-02), 275 | F(1.62208471E-02), F(1.59045603E-02), 276 | F(1.46525263E-02), -F(1.27472335E-02), 277 | -F(1.04584443E-02), -F(8.02941163E-03), 278 | 279 | -F(5.65949473E-03), -F(3.49717454E-03), 280 | -F(1.64973098E-03), -F(1.78805361E-04), 281 | -F(9.02154502E-04), F(1.61656283E-03), 282 | F(1.99454554E-03), F(2.10371989E-03), 283 | F(2.01182542E-03), F(1.78371725E-03), 284 | F(1.47640169E-03), F(1.13992507E-03), 285 | F(8.23919506E-04), -F(5.54620202E-04), 286 | -F(3.43256425E-04), -F(1.56575398E-04), 287 | }; 288 | #undef F 289 | 290 | /* 291 | * To produce this cosine matrix in Octave: 292 | * 293 | * b = zeros(8, 16); 294 | * for i = 0:7 295 | * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8)) 296 | * endfor endfor; 297 | * printf("%.10f, ", b'); 298 | * 299 | * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 300 | * 301 | * Change of sign for element 4 allows to replace constant 1.0 (not 302 | * representable in Q15 format) with -1.0 (fine with Q15). 303 | * Changed signs for elements 13, 14, 15 allow to have more similar constants 304 | * and simplify subband filter function code. 305 | */ 306 | #define SBC_COS_TABLE_FIXED8_SCALE \ 307 | ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) 308 | #define F_COS8(x) (FIXED_A) ((x) * \ 309 | ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) 310 | #define F(x) F_COS8(x) 311 | static const FIXED_T cos_table_fixed_8[128] = { 312 | F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), 313 | -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), 314 | F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), 315 | F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330), 316 | 317 | -F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123), 318 | -F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220), 319 | -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330), 320 | -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804), 321 | 322 | -F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330), 323 | -F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804), 324 | -F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123), 325 | F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220), 326 | 327 | F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220), 328 | -F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330), 329 | F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804), 330 | -F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123), 331 | 332 | F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220), 333 | -F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330), 334 | F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804), 335 | F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123), 336 | 337 | -F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330), 338 | -F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804), 339 | -F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123), 340 | -F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220), 341 | 342 | -F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123), 343 | -F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220), 344 | -F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330), 345 | -F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804), 346 | 347 | F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804), 348 | -F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123), 349 | F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220), 350 | -F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330), 351 | }; 352 | #undef F 353 | 354 | /* 355 | * Enforce 16 byte alignment for the data, which is supposed to be used 356 | * with SIMD optimized code. 357 | */ 358 | 359 | #define SBC_ALIGN_BITS 4 360 | #define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1) 361 | 362 | #ifdef __GNUC__ 363 | #define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS)))) 364 | #else 365 | #define SBC_ALIGNED 366 | #endif 367 | 368 | /* 369 | * Constant tables for the use in SIMD optimized analysis filters 370 | * Each table consists of two parts: 371 | * 1. reordered "proto" table 372 | * 2. reordered "cos" table 373 | * 374 | * Due to non-symmetrical reordering, separate tables for "even" 375 | * and "odd" cases are needed 376 | */ 377 | 378 | static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = { 379 | #define C0 1.0932568993 380 | #define C1 1.3056875580 381 | #define C2 1.3056875580 382 | #define C3 1.6772280856 383 | 384 | #define F(x) F_PROTO4(x) 385 | F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), 386 | F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), 387 | F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), 388 | F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), 389 | F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), 390 | F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), 391 | F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), 392 | F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), 393 | F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), 394 | F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), 395 | -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), 396 | F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), 397 | -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), 398 | -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), 399 | -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), 400 | F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), 401 | -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), 402 | -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), 403 | -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), 404 | F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), 405 | #undef F 406 | #define F(x) F_COS4(x) 407 | F(0.7071067812 / C0), F(0.9238795325 / C1), 408 | -F(0.7071067812 / C0), F(0.3826834324 / C1), 409 | -F(0.7071067812 / C0), -F(0.3826834324 / C1), 410 | F(0.7071067812 / C0), -F(0.9238795325 / C1), 411 | F(0.3826834324 / C2), -F(1.0000000000 / C3), 412 | -F(0.9238795325 / C2), -F(1.0000000000 / C3), 413 | F(0.9238795325 / C2), -F(1.0000000000 / C3), 414 | -F(0.3826834324 / C2), -F(1.0000000000 / C3), 415 | #undef F 416 | 417 | #undef C0 418 | #undef C1 419 | #undef C2 420 | #undef C3 421 | }; 422 | 423 | static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = { 424 | #define C0 1.3056875580 425 | #define C1 1.6772280856 426 | #define C2 1.0932568993 427 | #define C3 1.3056875580 428 | 429 | #define F(x) F_PROTO4(x) 430 | F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), 431 | -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), 432 | F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), 433 | F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), 434 | F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), 435 | -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), 436 | F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), 437 | F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), 438 | F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), 439 | -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), 440 | F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), 441 | F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), 442 | F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), 443 | F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), 444 | F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), 445 | F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), 446 | F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), 447 | -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), 448 | F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), 449 | F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), 450 | #undef F 451 | #define F(x) F_COS4(x) 452 | F(0.9238795325 / C0), -F(1.0000000000 / C1), 453 | F(0.3826834324 / C0), -F(1.0000000000 / C1), 454 | -F(0.3826834324 / C0), -F(1.0000000000 / C1), 455 | -F(0.9238795325 / C0), -F(1.0000000000 / C1), 456 | F(0.7071067812 / C2), F(0.3826834324 / C3), 457 | -F(0.7071067812 / C2), -F(0.9238795325 / C3), 458 | -F(0.7071067812 / C2), F(0.9238795325 / C3), 459 | F(0.7071067812 / C2), -F(0.3826834324 / C3), 460 | #undef F 461 | 462 | #undef C0 463 | #undef C1 464 | #undef C2 465 | #undef C3 466 | }; 467 | 468 | static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = { 469 | #define C0 2.7906148894 470 | #define C1 2.4270044280 471 | #define C2 2.8015616024 472 | #define C3 3.1710363741 473 | #define C4 2.5377944043 474 | #define C5 2.4270044280 475 | #define C6 2.8015616024 476 | #define C7 3.1710363741 477 | 478 | #define F(x) F_PROTO8(x) 479 | F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), 480 | F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), 481 | F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), 482 | F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), 483 | -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), 484 | F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), 485 | F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), 486 | F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), 487 | F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), 488 | F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), 489 | F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), 490 | F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), 491 | -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), 492 | F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), 493 | F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), 494 | -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), 495 | F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), 496 | F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), 497 | F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), 498 | F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), 499 | -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), 500 | F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), 501 | F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), 502 | F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), 503 | -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), 504 | -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), 505 | -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), 506 | -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), 507 | F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), 508 | F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), 509 | F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), 510 | F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), 511 | -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), 512 | -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), 513 | -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), 514 | -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), 515 | -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), 516 | F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), 517 | F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), 518 | F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), 519 | #undef F 520 | #define F(x) F_COS8(x) 521 | F(0.7071067812 / C0), F(0.8314696123 / C1), 522 | -F(0.7071067812 / C0), -F(0.1950903220 / C1), 523 | -F(0.7071067812 / C0), -F(0.9807852804 / C1), 524 | F(0.7071067812 / C0), -F(0.5555702330 / C1), 525 | F(0.7071067812 / C0), F(0.5555702330 / C1), 526 | -F(0.7071067812 / C0), F(0.9807852804 / C1), 527 | -F(0.7071067812 / C0), F(0.1950903220 / C1), 528 | F(0.7071067812 / C0), -F(0.8314696123 / C1), 529 | F(0.9238795325 / C2), F(0.9807852804 / C3), 530 | F(0.3826834324 / C2), F(0.8314696123 / C3), 531 | -F(0.3826834324 / C2), F(0.5555702330 / C3), 532 | -F(0.9238795325 / C2), F(0.1950903220 / C3), 533 | -F(0.9238795325 / C2), -F(0.1950903220 / C3), 534 | -F(0.3826834324 / C2), -F(0.5555702330 / C3), 535 | F(0.3826834324 / C2), -F(0.8314696123 / C3), 536 | F(0.9238795325 / C2), -F(0.9807852804 / C3), 537 | -F(1.0000000000 / C4), F(0.5555702330 / C5), 538 | -F(1.0000000000 / C4), -F(0.9807852804 / C5), 539 | -F(1.0000000000 / C4), F(0.1950903220 / C5), 540 | -F(1.0000000000 / C4), F(0.8314696123 / C5), 541 | -F(1.0000000000 / C4), -F(0.8314696123 / C5), 542 | -F(1.0000000000 / C4), -F(0.1950903220 / C5), 543 | -F(1.0000000000 / C4), F(0.9807852804 / C5), 544 | -F(1.0000000000 / C4), -F(0.5555702330 / C5), 545 | F(0.3826834324 / C6), F(0.1950903220 / C7), 546 | -F(0.9238795325 / C6), -F(0.5555702330 / C7), 547 | F(0.9238795325 / C6), F(0.8314696123 / C7), 548 | -F(0.3826834324 / C6), -F(0.9807852804 / C7), 549 | -F(0.3826834324 / C6), F(0.9807852804 / C7), 550 | F(0.9238795325 / C6), -F(0.8314696123 / C7), 551 | -F(0.9238795325 / C6), F(0.5555702330 / C7), 552 | F(0.3826834324 / C6), -F(0.1950903220 / C7), 553 | #undef F 554 | 555 | #undef C0 556 | #undef C1 557 | #undef C2 558 | #undef C3 559 | #undef C4 560 | #undef C5 561 | #undef C6 562 | #undef C7 563 | }; 564 | 565 | static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = { 566 | #define C0 2.5377944043 567 | #define C1 2.4270044280 568 | #define C2 2.8015616024 569 | #define C3 3.1710363741 570 | #define C4 2.7906148894 571 | #define C5 2.4270044280 572 | #define C6 2.8015616024 573 | #define C7 3.1710363741 574 | 575 | #define F(x) F_PROTO8(x) 576 | F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), 577 | F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), 578 | F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), 579 | F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), 580 | F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), 581 | F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), 582 | F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), 583 | F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), 584 | F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), 585 | F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), 586 | F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), 587 | F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), 588 | F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), 589 | F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), 590 | F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), 591 | -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), 592 | F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), 593 | F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), 594 | F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), 595 | F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), 596 | F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), 597 | F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), 598 | F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), 599 | F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), 600 | F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), 601 | -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), 602 | -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), 603 | -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), 604 | F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), 605 | F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), 606 | F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), 607 | F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), 608 | F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), 609 | -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), 610 | -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), 611 | -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), 612 | F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), 613 | F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), 614 | F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), 615 | F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), 616 | #undef F 617 | #define F(x) F_COS8(x) 618 | -F(1.0000000000 / C0), F(0.8314696123 / C1), 619 | -F(1.0000000000 / C0), -F(0.1950903220 / C1), 620 | -F(1.0000000000 / C0), -F(0.9807852804 / C1), 621 | -F(1.0000000000 / C0), -F(0.5555702330 / C1), 622 | -F(1.0000000000 / C0), F(0.5555702330 / C1), 623 | -F(1.0000000000 / C0), F(0.9807852804 / C1), 624 | -F(1.0000000000 / C0), F(0.1950903220 / C1), 625 | -F(1.0000000000 / C0), -F(0.8314696123 / C1), 626 | F(0.9238795325 / C2), F(0.9807852804 / C3), 627 | F(0.3826834324 / C2), F(0.8314696123 / C3), 628 | -F(0.3826834324 / C2), F(0.5555702330 / C3), 629 | -F(0.9238795325 / C2), F(0.1950903220 / C3), 630 | -F(0.9238795325 / C2), -F(0.1950903220 / C3), 631 | -F(0.3826834324 / C2), -F(0.5555702330 / C3), 632 | F(0.3826834324 / C2), -F(0.8314696123 / C3), 633 | F(0.9238795325 / C2), -F(0.9807852804 / C3), 634 | F(0.7071067812 / C4), F(0.5555702330 / C5), 635 | -F(0.7071067812 / C4), -F(0.9807852804 / C5), 636 | -F(0.7071067812 / C4), F(0.1950903220 / C5), 637 | F(0.7071067812 / C4), F(0.8314696123 / C5), 638 | F(0.7071067812 / C4), -F(0.8314696123 / C5), 639 | -F(0.7071067812 / C4), -F(0.1950903220 / C5), 640 | -F(0.7071067812 / C4), F(0.9807852804 / C5), 641 | F(0.7071067812 / C4), -F(0.5555702330 / C5), 642 | F(0.3826834324 / C6), F(0.1950903220 / C7), 643 | -F(0.9238795325 / C6), -F(0.5555702330 / C7), 644 | F(0.9238795325 / C6), F(0.8314696123 / C7), 645 | -F(0.3826834324 / C6), -F(0.9807852804 / C7), 646 | -F(0.3826834324 / C6), F(0.9807852804 / C7), 647 | F(0.9238795325 / C6), -F(0.8314696123 / C7), 648 | -F(0.9238795325 / C6), F(0.5555702330 / C7), 649 | F(0.3826834324 / C6), -F(0.1950903220 / C7), 650 | #undef F 651 | 652 | #undef C0 653 | #undef C1 654 | #undef C2 655 | #undef C3 656 | #undef C4 657 | #undef C5 658 | #undef C6 659 | #undef C7 660 | }; 661 | -------------------------------------------------------------------------------- /src/sbc/sbcdec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) decoder 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | #ifndef ARDUINO 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "sbc.h" 42 | #include "formats.h" 43 | 44 | #define BUF_SIZE 8192 45 | 46 | static int verbose = 0; 47 | 48 | static void decode(char *filename, char *output, int tofile) 49 | { 50 | unsigned char buf[BUF_SIZE], *stream; 51 | struct stat st; 52 | sbc_t sbc; 53 | int fd, ad, pos, streamlen, framelen, count; 54 | size_t len; 55 | int format = AFMT_S16_BE, frequency, channels; 56 | ssize_t written; 57 | 58 | if (stat(filename, &st) < 0) { 59 | fprintf(stderr, "Can't get size of file %s: %s\n", 60 | filename, strerror(errno)); 61 | return; 62 | } 63 | 64 | stream = malloc(st.st_size); 65 | 66 | if (!stream) { 67 | fprintf(stderr, "Can't allocate memory for %s: %s\n", 68 | filename, strerror(errno)); 69 | return; 70 | } 71 | 72 | fd = open(filename, O_RDONLY); 73 | if (fd < 0) { 74 | fprintf(stderr, "Can't open file %s: %s\n", 75 | filename, strerror(errno)); 76 | goto free; 77 | } 78 | 79 | if (read(fd, stream, st.st_size) != st.st_size) { 80 | fprintf(stderr, "Can't read content of %s: %s\n", 81 | filename, strerror(errno)); 82 | close(fd); 83 | goto free; 84 | } 85 | 86 | close(fd); 87 | 88 | pos = 0; 89 | streamlen = st.st_size; 90 | 91 | if (tofile) 92 | ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644); 93 | else 94 | ad = open(output, O_WRONLY, 0); 95 | 96 | if (ad < 0) { 97 | fprintf(stderr, "Can't open output %s: %s\n", 98 | output, strerror(errno)); 99 | goto free; 100 | } 101 | 102 | sbc_init(&sbc, 0L); 103 | sbc.endian = SBC_BE; 104 | 105 | framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len); 106 | channels = sbc.mode == SBC_MODE_MONO ? 1 : 2; 107 | switch (sbc.frequency) { 108 | case SBC_FREQ_16000: 109 | frequency = 16000; 110 | break; 111 | 112 | case SBC_FREQ_32000: 113 | frequency = 32000; 114 | break; 115 | 116 | case SBC_FREQ_44100: 117 | frequency = 44100; 118 | break; 119 | 120 | case SBC_FREQ_48000: 121 | frequency = 48000; 122 | break; 123 | default: 124 | frequency = 0; 125 | } 126 | 127 | if (verbose) { 128 | fprintf(stderr,"decoding %s with rate %d, %d subbands, " 129 | "%d bits, allocation method %s and mode %s\n", 130 | filename, frequency, sbc.subbands * 4 + 4, sbc.bitpool, 131 | sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS", 132 | sbc.mode == SBC_MODE_MONO ? "MONO" : 133 | sbc.mode == SBC_MODE_STEREO ? 134 | "STEREO" : "JOINTSTEREO"); 135 | } 136 | 137 | if (tofile) { 138 | struct au_header au_hdr; 139 | 140 | au_hdr.magic = AU_MAGIC; 141 | au_hdr.hdr_size = BE_INT(24); 142 | au_hdr.data_size = BE_INT(0); 143 | au_hdr.encoding = BE_INT(AU_FMT_LIN16); 144 | au_hdr.sample_rate = BE_INT(frequency); 145 | au_hdr.channels = BE_INT(channels); 146 | 147 | written = write(ad, &au_hdr, sizeof(au_hdr)); 148 | if (written < (ssize_t) sizeof(au_hdr)) { 149 | fprintf(stderr, "Failed to write header\n"); 150 | goto close; 151 | } 152 | } else { 153 | if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) { 154 | fprintf(stderr, "Can't set audio format on %s: %s\n", 155 | output, strerror(errno)); 156 | goto close; 157 | } 158 | 159 | if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) { 160 | fprintf(stderr, "Can't set number of channels on %s: %s\n", 161 | output, strerror(errno)); 162 | goto close; 163 | } 164 | 165 | if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) { 166 | fprintf(stderr, "Can't set audio rate on %s: %s\n", 167 | output, strerror(errno)); 168 | goto close; 169 | } 170 | } 171 | 172 | count = len; 173 | 174 | while (framelen > 0) { 175 | /* we have completed an sbc_decode at this point sbc.len is the 176 | * length of the frame we just decoded count is the number of 177 | * decoded bytes yet to be written */ 178 | 179 | if (count + len >= BUF_SIZE) { 180 | /* buffer is too full to stuff decoded audio in so it 181 | * must be written to the device */ 182 | written = write(ad, buf, count); 183 | if (written > 0) 184 | count -= written; 185 | } 186 | 187 | /* sanity check */ 188 | if (count + len >= BUF_SIZE) { 189 | fprintf(stderr, 190 | "buffer size of %d is too small for decoded" 191 | " data (%lu)\n", BUF_SIZE, (unsigned long) (len + count)); 192 | exit(1); 193 | } 194 | 195 | /* push the pointer in the file forward to the next bit to be 196 | * decoded tell the decoder to decode up to the remaining 197 | * length of the file (!) */ 198 | pos += framelen; 199 | framelen = sbc_decode(&sbc, stream + pos, streamlen - pos, 200 | buf + count, sizeof(buf) - count, &len); 201 | 202 | /* increase the count */ 203 | count += len; 204 | } 205 | 206 | if (count > 0) { 207 | written = write(ad, buf, count); 208 | if (written > 0) 209 | count -= written; 210 | } 211 | 212 | close: 213 | sbc_finish(&sbc); 214 | 215 | close(ad); 216 | 217 | free: 218 | free(stream); 219 | } 220 | 221 | static void usage(void) 222 | { 223 | printf("SBC decoder utility ver %s\n", VERSION); 224 | printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n"); 225 | 226 | printf("Usage:\n" 227 | "\tsbcdec [options] file(s)\n" 228 | "\n"); 229 | 230 | printf("Options:\n" 231 | "\t-h, --help Display help\n" 232 | "\t-v, --verbose Verbose mode\n" 233 | "\t-d, --device Sound device\n" 234 | "\t-f, --file Decode to a file\n" 235 | "\n"); 236 | } 237 | 238 | static struct option main_options[] = { 239 | { "help", 0, 0, 'h' }, 240 | { "device", 1, 0, 'd' }, 241 | { "verbose", 0, 0, 'v' }, 242 | { "file", 1, 0, 'f' }, 243 | { 0, 0, 0, 0 } 244 | }; 245 | 246 | int main(int argc, char *argv[]) 247 | { 248 | char *output = NULL; 249 | int i, opt, tofile = 0; 250 | 251 | while ((opt = getopt_long(argc, argv, "+hvd:f:", 252 | main_options, NULL)) != -1) { 253 | switch(opt) { 254 | case 'h': 255 | usage(); 256 | exit(0); 257 | 258 | case 'v': 259 | verbose = 1; 260 | break; 261 | 262 | case 'd': 263 | free(output); 264 | output = strdup(optarg); 265 | tofile = 0; 266 | break; 267 | 268 | case 'f' : 269 | free(output); 270 | output = strdup(optarg); 271 | tofile = 1; 272 | break; 273 | 274 | default: 275 | exit(1); 276 | } 277 | } 278 | 279 | argc -= optind; 280 | argv += optind; 281 | optind = 0; 282 | 283 | if (argc < 1) { 284 | usage(); 285 | exit(1); 286 | } 287 | 288 | for (i = 0; i < argc; i++) 289 | decode(argv[i], output ? output : "/dev/dsp", tofile); 290 | 291 | free(output); 292 | 293 | return 0; 294 | } 295 | 296 | #endif 297 | -------------------------------------------------------------------------------- /src/sbc/sbcenc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) encoder 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef ARDUINO 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "sbc.h" 42 | #include "formats.h" 43 | 44 | static int verbose = 0; 45 | 46 | #define BUF_SIZE 32768 47 | static unsigned char input[BUF_SIZE], output[BUF_SIZE + BUF_SIZE / 4]; 48 | 49 | static void encode(char *filename, int subbands, int bitpool, int joint, 50 | int dualchannel, int snr, int blocks) 51 | { 52 | struct au_header au_hdr; 53 | sbc_t sbc; 54 | int fd, size, srate, codesize, nframes; 55 | ssize_t encoded; 56 | ssize_t len; 57 | 58 | if (sizeof(au_hdr) != 24) { 59 | /* Sanity check just in case */ 60 | fprintf(stderr, "FIXME: sizeof(au_hdr) != 24\n"); 61 | return; 62 | } 63 | 64 | if (strcmp(filename, "-")) { 65 | fd = open(filename, O_RDONLY); 66 | if (fd < 0) { 67 | fprintf(stderr, "Can't open file %s: %s\n", 68 | filename, strerror(errno)); 69 | return; 70 | } 71 | } else 72 | fd = fileno(stdin); 73 | 74 | len = read(fd, &au_hdr, sizeof(au_hdr)); 75 | if (len < (ssize_t) sizeof(au_hdr)) { 76 | if (fd > fileno(stderr)) 77 | fprintf(stderr, "Can't read header from file %s: %s\n", 78 | filename, strerror(errno)); 79 | else 80 | perror("Can't read audio header"); 81 | goto done; 82 | } 83 | 84 | if (au_hdr.magic != AU_MAGIC || 85 | BE_INT(au_hdr.hdr_size) > 128 || 86 | BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) || 87 | BE_INT(au_hdr.encoding) != AU_FMT_LIN16) { 88 | fprintf(stderr, "Not in Sun/NeXT audio S16_BE format\n"); 89 | goto done; 90 | } 91 | 92 | sbc_init(&sbc, 0L); 93 | 94 | switch (BE_INT(au_hdr.sample_rate)) { 95 | case 16000: 96 | sbc.frequency = SBC_FREQ_16000; 97 | break; 98 | case 32000: 99 | sbc.frequency = SBC_FREQ_32000; 100 | break; 101 | case 44100: 102 | sbc.frequency = SBC_FREQ_44100; 103 | break; 104 | case 48000: 105 | sbc.frequency = SBC_FREQ_48000; 106 | break; 107 | } 108 | 109 | srate = BE_INT(au_hdr.sample_rate); 110 | 111 | sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8; 112 | 113 | if (BE_INT(au_hdr.channels) == 1) { 114 | sbc.mode = SBC_MODE_MONO; 115 | if (joint || dualchannel) { 116 | fprintf(stderr, "Audio is mono but joint or " 117 | "dualchannel mode has been specified\n"); 118 | goto done; 119 | } 120 | } else if (joint && !dualchannel) 121 | sbc.mode = SBC_MODE_JOINT_STEREO; 122 | else if (!joint && dualchannel) 123 | sbc.mode = SBC_MODE_DUAL_CHANNEL; 124 | else if (!joint && !dualchannel) 125 | sbc.mode = SBC_MODE_STEREO; 126 | else { 127 | fprintf(stderr, "Both joint and dualchannel mode have been " 128 | "specified\n"); 129 | goto done; 130 | } 131 | 132 | sbc.endian = SBC_BE; 133 | /* Skip extra bytes of the header if any */ 134 | if (read(fd, input, BE_INT(au_hdr.hdr_size) - len) < 0) 135 | goto done; 136 | 137 | sbc.bitpool = bitpool; 138 | sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS; 139 | sbc.blocks = blocks == 4 ? SBC_BLK_4 : 140 | blocks == 8 ? SBC_BLK_8 : 141 | blocks == 12 ? SBC_BLK_12 : SBC_BLK_16; 142 | 143 | if (verbose) { 144 | fprintf(stderr, "encoding %s with rate %d, %d blocks, " 145 | "%d subbands, %d bits, allocation method %s, " 146 | "and mode %s\n", 147 | filename, srate, blocks, subbands, bitpool, 148 | sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS", 149 | sbc.mode == SBC_MODE_MONO ? "MONO" : 150 | sbc.mode == SBC_MODE_STEREO ? 151 | "STEREO" : "JOINTSTEREO"); 152 | } 153 | 154 | codesize = sbc_get_codesize(&sbc); 155 | nframes = sizeof(input) / codesize; 156 | while (1) { 157 | unsigned char *inp, *outp; 158 | /* read data for up to 'nframes' frames of input data */ 159 | size = read(fd, input, codesize * nframes); 160 | if (size < 0) { 161 | /* Something really bad happened */ 162 | perror("Can't read audio data"); 163 | break; 164 | } 165 | if (size < codesize) { 166 | /* Not enough data for encoding even a single frame */ 167 | break; 168 | } 169 | /* encode all the data from the input buffer in a loop */ 170 | inp = input; 171 | outp = output; 172 | while (size >= codesize) { 173 | len = sbc_encode(&sbc, inp, codesize, 174 | outp, sizeof(output) - (outp - output), 175 | &encoded); 176 | if (len != codesize || encoded <= 0) { 177 | fprintf(stderr, 178 | "sbc_encode fail, len=%zd, encoded=%lu\n", 179 | len, (unsigned long) encoded); 180 | break; 181 | } 182 | size -= len; 183 | inp += len; 184 | outp += encoded; 185 | } 186 | len = write(fileno(stdout), output, outp - output); 187 | if (len != outp - output) { 188 | perror("Can't write SBC output"); 189 | break; 190 | } 191 | if (size != 0) { 192 | /* 193 | * sbc_encode failure has been detected earlier or end 194 | * of file reached (have trailing partial data which is 195 | * insufficient to encode SBC frame) 196 | */ 197 | break; 198 | } 199 | } 200 | 201 | sbc_finish(&sbc); 202 | 203 | done: 204 | if (fd > fileno(stderr)) 205 | close(fd); 206 | } 207 | 208 | static void usage(void) 209 | { 210 | printf("SBC encoder utility ver %s\n", VERSION); 211 | printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n"); 212 | 213 | printf("Usage:\n" 214 | "\tsbcenc [options] file(s)\n" 215 | "\n"); 216 | 217 | printf("Options:\n" 218 | "\t-h, --help Display help\n" 219 | "\t-v, --verbose Verbose mode\n" 220 | "\t-s, --subbands Number of subbands to use (4 or 8)\n" 221 | "\t-b, --bitpool Bitpool value (default is 32)\n" 222 | "\t-j, --joint Joint stereo\n" 223 | "\t-d, --dualchannel Dual channel\n" 224 | "\t-S, --snr Use SNR mode (default is loudness)\n" 225 | "\t-B, --blocks Number of blocks (4, 8, 12 or 16)\n" 226 | "\n"); 227 | } 228 | 229 | static struct option main_options[] = { 230 | { "help", 0, 0, 'h' }, 231 | { "verbose", 0, 0, 'v' }, 232 | { "subbands", 1, 0, 's' }, 233 | { "bitpool", 1, 0, 'b' }, 234 | { "joint", 0, 0, 'j' }, 235 | { "dualchannel",0, 0, 'd' }, 236 | { "snr", 0, 0, 'S' }, 237 | { "blocks", 1, 0, 'B' }, 238 | { 0, 0, 0, 0 } 239 | }; 240 | 241 | int main(int argc, char *argv[]) 242 | { 243 | int i, opt, subbands = 8, bitpool = 32, joint = 0, dualchannel = 0; 244 | int snr = 0, blocks = 16; 245 | 246 | while ((opt = getopt_long(argc, argv, "+hvs:b:jdSB:", 247 | main_options, NULL)) != -1) { 248 | switch(opt) { 249 | case 'h': 250 | usage(); 251 | exit(0); 252 | 253 | case 'v': 254 | verbose = 1; 255 | break; 256 | 257 | case 's': 258 | subbands = atoi(optarg); 259 | if (subbands != 8 && subbands != 4) { 260 | fprintf(stderr, "Invalid subbands\n"); 261 | exit(1); 262 | } 263 | break; 264 | 265 | case 'b': 266 | bitpool = atoi(optarg); 267 | break; 268 | 269 | case 'j': 270 | joint = 1; 271 | break; 272 | 273 | case 'd': 274 | dualchannel = 1; 275 | break; 276 | 277 | case 'S': 278 | snr = 1; 279 | break; 280 | 281 | case 'B': 282 | blocks = atoi(optarg); 283 | if (blocks != 16 && blocks != 12 && 284 | blocks != 8 && blocks != 4) { 285 | fprintf(stderr, "Invalid blocks\n"); 286 | exit(1); 287 | } 288 | break; 289 | 290 | default: 291 | usage(); 292 | exit(1); 293 | } 294 | } 295 | 296 | argc -= optind; 297 | argv += optind; 298 | optind = 0; 299 | 300 | if (argc < 1) { 301 | usage(); 302 | exit(1); 303 | } 304 | 305 | for (i = 0; i < argc; i++) 306 | encode(argv[i], subbands, bitpool, joint, dualchannel, 307 | snr, blocks); 308 | 309 | return 0; 310 | } 311 | 312 | #endif 313 | -------------------------------------------------------------------------------- /src/sbc/sbcinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2004-2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef ARDUINO 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #if __BYTE_ORDER == __LITTLE_ENDIAN 41 | struct sbc_frame_hdr { 42 | uint8_t syncword:8; /* Sync word */ 43 | uint8_t subbands:1; /* Subbands */ 44 | uint8_t allocation_method:1; /* Allocation method */ 45 | uint8_t channel_mode:2; /* Channel mode */ 46 | uint8_t blocks:2; /* Blocks */ 47 | uint8_t sampling_frequency:2; /* Sampling frequency */ 48 | uint8_t bitpool:8; /* Bitpool */ 49 | uint8_t crc_check:8; /* CRC check */ 50 | } __attribute__ ((packed)); 51 | #elif __BYTE_ORDER == __BIG_ENDIAN 52 | struct sbc_frame_hdr { 53 | uint8_t syncword:8; /* Sync word */ 54 | uint8_t sampling_frequency:2; /* Sampling frequency */ 55 | uint8_t blocks:2; /* Blocks */ 56 | uint8_t channel_mode:2; /* Channel mode */ 57 | uint8_t allocation_method:1; /* Allocation method */ 58 | uint8_t subbands:1; /* Subbands */ 59 | uint8_t bitpool:8; /* Bitpool */ 60 | uint8_t crc_check:8; /* CRC check */ 61 | } __attribute__ ((packed)); 62 | #else 63 | #error "Unknown byte order" 64 | #endif 65 | 66 | static int calc_frame_len(struct sbc_frame_hdr *hdr) 67 | { 68 | int tmp, nrof_subbands, nrof_blocks; 69 | 70 | nrof_subbands = (hdr->subbands + 1) * 4; 71 | nrof_blocks = (hdr->blocks + 1) * 4; 72 | 73 | switch (hdr->channel_mode) { 74 | case 0x00: 75 | nrof_subbands /= 2; 76 | tmp = nrof_blocks * hdr->bitpool; 77 | break; 78 | case 0x01: 79 | tmp = nrof_blocks * hdr->bitpool * 2; 80 | break; 81 | case 0x02: 82 | tmp = nrof_blocks * hdr->bitpool; 83 | break; 84 | case 0x03: 85 | tmp = nrof_blocks * hdr->bitpool + nrof_subbands; 86 | break; 87 | default: 88 | return 0; 89 | } 90 | 91 | return (nrof_subbands + ((tmp + 7) / 8)); 92 | } 93 | 94 | static double calc_bit_rate(struct sbc_frame_hdr *hdr) 95 | { 96 | int nrof_subbands, nrof_blocks; 97 | double f; 98 | 99 | nrof_subbands = (hdr->subbands + 1) * 4; 100 | nrof_blocks = (hdr->blocks + 1) * 4; 101 | 102 | switch (hdr->sampling_frequency) { 103 | case 0: 104 | f = 16; 105 | break; 106 | case 1: 107 | f = 32; 108 | break; 109 | case 2: 110 | f = 44.1; 111 | break; 112 | case 3: 113 | f = 48; 114 | break; 115 | default: 116 | return 0; 117 | } 118 | 119 | return ((8 * (calc_frame_len(hdr) + 4) * f) / 120 | (nrof_subbands * nrof_blocks)); 121 | } 122 | 123 | static char *freq2str(uint8_t freq) 124 | { 125 | switch (freq) { 126 | case 0: 127 | return "16 kHz"; 128 | case 1: 129 | return "32 kHz"; 130 | case 2: 131 | return "44.1 kHz"; 132 | case 3: 133 | return "48 kHz"; 134 | default: 135 | return "Unknown"; 136 | } 137 | } 138 | 139 | static char *mode2str(uint8_t mode) 140 | { 141 | switch (mode) { 142 | case 0: 143 | return "Mono"; 144 | case 1: 145 | return "Dual Channel"; 146 | case 2: 147 | return "Stereo"; 148 | case 3: 149 | return "Joint Stereo"; 150 | default: 151 | return "Unknown"; 152 | } 153 | } 154 | 155 | static ssize_t __read(int fd, void *buf, size_t count) 156 | { 157 | ssize_t len, pos = 0; 158 | 159 | while (count > 0) { 160 | len = read(fd, buf + pos, count); 161 | if (len <= 0) 162 | return len; 163 | 164 | count -= len; 165 | pos += len; 166 | } 167 | 168 | return pos; 169 | } 170 | 171 | #define SIZE 32 172 | 173 | static int analyze_file(char *filename) 174 | { 175 | struct sbc_frame_hdr hdr; 176 | unsigned char buf[64]; 177 | double rate; 178 | int bitpool[SIZE], frame_len[SIZE]; 179 | int subbands, blocks, freq, method; 180 | int n, p1, p2, fd, size, num; 181 | ssize_t len; 182 | unsigned int count; 183 | 184 | if (strcmp(filename, "-")) { 185 | printf("Filename\t\t%s\n", basename(filename)); 186 | 187 | fd = open(filename, O_RDONLY); 188 | if (fd < 0) { 189 | perror("Can't open file"); 190 | return -1; 191 | } 192 | } else 193 | fd = fileno(stdin); 194 | 195 | len = __read(fd, &hdr, sizeof(hdr)); 196 | if (len != sizeof(hdr) || hdr.syncword != 0x9c) { 197 | fprintf(stderr, "Not a SBC audio file\n"); 198 | return -1; 199 | } 200 | 201 | subbands = (hdr.subbands + 1) * 4; 202 | blocks = (hdr.blocks + 1) * 4; 203 | freq = hdr.sampling_frequency; 204 | method = hdr.allocation_method; 205 | 206 | count = calc_frame_len(&hdr); 207 | 208 | bitpool[0] = hdr.bitpool; 209 | frame_len[0] = count + 4; 210 | 211 | for (n = 1; n < SIZE; n++) { 212 | bitpool[n] = 0; 213 | frame_len[n] = 0; 214 | } 215 | 216 | if (lseek(fd, 0, SEEK_SET) < 0) { 217 | num = 1; 218 | rate = calc_bit_rate(&hdr); 219 | while (count) { 220 | size = count > sizeof(buf) ? sizeof(buf) : count; 221 | len = __read(fd, buf, size); 222 | if (len < 0) 223 | break; 224 | count -= len; 225 | } 226 | } else { 227 | num = 0; 228 | rate = 0; 229 | } 230 | 231 | while (1) { 232 | len = __read(fd, &hdr, sizeof(hdr)); 233 | if (len < 0) { 234 | fprintf(stderr, "Unable to read frame header" 235 | " (error %d)\n", errno); 236 | break; 237 | } 238 | 239 | if (len == 0) 240 | break; 241 | 242 | if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) { 243 | fprintf(stderr, "Corrupted SBC stream " 244 | "(len %zd syncword 0x%02x)\n", 245 | len, hdr.syncword); 246 | break; 247 | } 248 | 249 | count = calc_frame_len(&hdr); 250 | len = count + 4; 251 | 252 | p1 = -1; 253 | p2 = -1; 254 | for (n = 0; n < SIZE; n++) { 255 | if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool)) 256 | p1 = n; 257 | if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len)) 258 | p2 = n; 259 | } 260 | if (p1 >= 0) 261 | bitpool[p1] = hdr.bitpool; 262 | if (p2 >= 0) 263 | frame_len[p2] = len; 264 | 265 | while (count) { 266 | size = count > sizeof(buf) ? sizeof(buf) : count; 267 | 268 | len = __read(fd, buf, size); 269 | if (len != size) { 270 | fprintf(stderr, "Unable to read frame data " 271 | "(error %d)\n", errno); 272 | break; 273 | } 274 | 275 | count -= len; 276 | } 277 | 278 | rate += calc_bit_rate(&hdr); 279 | num++; 280 | } 281 | 282 | printf("Subbands\t\t%d\n", subbands); 283 | printf("Block length\t\t%d\n", blocks); 284 | printf("Sampling frequency\t%s\n", freq2str(freq)); 285 | printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode)); 286 | printf("Allocation method\t%s\n", method ? "SNR" : "Loudness"); 287 | printf("Bitpool\t\t\t%d", bitpool[0]); 288 | for (n = 1; n < SIZE; n++) 289 | if (bitpool[n] > 0) 290 | printf(", %d", bitpool[n]); 291 | printf("\n"); 292 | printf("Number of frames\t%d\n", num); 293 | printf("Frame length\t\t%d", frame_len[0]); 294 | for (n = 1; n < SIZE; n++) 295 | if (frame_len[n] > 0) 296 | printf(", %d", frame_len[n]); 297 | printf(" Bytes\n"); 298 | if (num > 0) 299 | printf("Bit rate\t\t%.3f kbps\n", rate / num); 300 | 301 | if (fd > fileno(stderr)) 302 | close(fd); 303 | 304 | printf("\n"); 305 | 306 | return 0; 307 | } 308 | 309 | 310 | int main(int argc, char *argv[]) 311 | { 312 | int i; 313 | 314 | if (argc < 2) { 315 | fprintf(stderr, "Usage: sbcinfo \n"); 316 | exit(1); 317 | } 318 | 319 | for (i = 0; i < argc - 1; i++) 320 | if (analyze_file(argv[i + 1]) < 0) 321 | exit(1); 322 | 323 | return 0; 324 | } 325 | 326 | #endif 327 | -------------------------------------------------------------------------------- /src/sbc/sbctester.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Bluetooth low-complexity, subband codec (SBC) library 4 | * 5 | * Copyright (C) 2008-2010 Nokia Corporation 6 | * Copyright (C) 2007-2010 Marcel Holtmann 7 | * Copyright (C) 2007-2008 Frederic Dalleau 8 | * 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | #ifndef ARDUINO 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #define MAXCHANNELS 2 38 | #define DEFACCURACY 7 39 | 40 | static double sampletobits(short sample16, int verbose) 41 | { 42 | double bits = 0; 43 | unsigned short bit; 44 | int i; 45 | 46 | if (verbose) 47 | printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16); 48 | 49 | /* Bit 0 is MSB */ 50 | if (sample16 < 0) 51 | bits = -1; 52 | 53 | if (verbose) 54 | printf("%d", (sample16 < 0) ? 1 : 0); 55 | 56 | /* Bit 15 is LSB */ 57 | for (i = 1; i < 16; i++) { 58 | bit = (unsigned short) sample16; 59 | bit >>= 15 - i; 60 | bit %= 2; 61 | 62 | if (verbose) 63 | printf("%d", bit); 64 | 65 | if (bit) 66 | bits += (1.0 / pow(2.0, i)); 67 | } 68 | 69 | if (verbose) 70 | printf("\n"); 71 | 72 | return bits; 73 | } 74 | 75 | static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref, 76 | SNDFILE * sndtst, SF_INFO * infostst, 77 | int accuracy, char *csvname) 78 | { 79 | short refsample[MAXCHANNELS], tstsample[MAXCHANNELS]; 80 | double refbits, tstbits; 81 | double rms_accu[MAXCHANNELS]; 82 | double rms_level[MAXCHANNELS]; 83 | double rms_limit = 1.0 / (pow(2.0, accuracy - 1) * pow(12.0, 0.5)); 84 | FILE *csv = NULL; 85 | int i, j, r1, r2, verdict; 86 | 87 | if (csvname) 88 | csv = fopen(csvname, "wt"); 89 | 90 | if (csv) { 91 | fprintf(csv, "num;"); 92 | for (j = 0; j < infostst->channels; j++) 93 | fprintf(csv, "ref channel %d;tst channel %d;", j, j); 94 | fprintf(csv, "\r\n"); 95 | } 96 | 97 | sf_seek(sndref, 0, SEEK_SET); 98 | sf_seek(sndtst, 0, SEEK_SET); 99 | 100 | memset(rms_accu, 0, sizeof(rms_accu)); 101 | memset(rms_level, 0, sizeof(rms_level)); 102 | 103 | for (i = 0; i < infostst->frames; i++) { 104 | if (csv) 105 | fprintf(csv, "%d;", i); 106 | 107 | r1 = sf_read_short(sndref, refsample, infostst->channels); 108 | if (r1 != infostst->channels) { 109 | printf("Failed to read reference data: %s " 110 | "(r1=%d, channels=%d)", 111 | sf_strerror(sndref), r1, 112 | infostst->channels); 113 | if (csv) 114 | fclose(csv); 115 | return -1; 116 | } 117 | 118 | r2 = sf_read_short(sndtst, tstsample, infostst->channels); 119 | if (r2 != infostst->channels) { 120 | printf("Failed to read test data: %s " 121 | "(r2=%d, channels=%d)\n", 122 | sf_strerror(sndtst), r2, 123 | infostst->channels); 124 | if (csv) 125 | fclose(csv); 126 | return -1; 127 | } 128 | 129 | for (j = 0; j < infostst->channels; j++) { 130 | if (csv) 131 | fprintf(csv, "%d;%d;", refsample[j], 132 | tstsample[j]); 133 | 134 | refbits = sampletobits(refsample[j], 0); 135 | tstbits = sampletobits(tstsample[j], 0); 136 | 137 | rms_accu[j] += pow(tstbits - refbits, 2.0); 138 | } 139 | 140 | if (csv) 141 | fprintf(csv, "\r\n"); 142 | } 143 | 144 | printf("Limit: %f\n", rms_limit); 145 | 146 | for (j = 0; j < infostst->channels; j++) { 147 | printf("Channel %d\n", j); 148 | printf("Accumulated %f\n", rms_accu[j]); 149 | rms_accu[j] /= (double) infostst->frames; 150 | printf("Accumulated / %f = %f\n", (double) infostst->frames, 151 | rms_accu[j]); 152 | rms_level[j] = sqrt(rms_accu[j]); 153 | printf("Level = %f (%f x %f = %f)\n", 154 | rms_level[j], rms_level[j], rms_level[j], 155 | rms_level[j] * rms_level[j]); 156 | } 157 | 158 | verdict = 1; 159 | 160 | for (j = 0; j < infostst->channels; j++) { 161 | printf("Channel %d: %f\n", j, rms_level[j]); 162 | 163 | if (rms_level[j] > rms_limit) 164 | verdict = 0; 165 | } 166 | 167 | printf("%s return %d\n", __FUNCTION__, verdict); 168 | 169 | return verdict; 170 | } 171 | 172 | static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref, 173 | SNDFILE * sndtst, SF_INFO * infostst, 174 | int accuracy) 175 | { 176 | short refsample[MAXCHANNELS], tstsample[MAXCHANNELS]; 177 | short refmax[MAXCHANNELS], tstmax[MAXCHANNELS]; 178 | double refbits, tstbits; 179 | double rms_absolute = 1.0 / (pow(2, accuracy - 2)); 180 | double calc_max[MAXCHANNELS]; 181 | int calc_count = 0; 182 | short r1, r2; 183 | double cur_diff; 184 | int i, j, verdict; 185 | 186 | memset(&refmax, 0, sizeof(refmax)); 187 | memset(&tstmax, 0, sizeof(tstmax)); 188 | memset(&calc_max, 0, sizeof(calc_max)); 189 | memset(&refsample, 0, sizeof(refsample)); 190 | memset(&tstsample, 0, sizeof(tstsample)); 191 | 192 | sf_seek(sndref, 0, SEEK_SET); 193 | sf_seek(sndtst, 0, SEEK_SET); 194 | 195 | verdict = 1; 196 | 197 | printf("Absolute max: %f\n", rms_absolute); 198 | for (i = 0; i < infostst->frames; i++) { 199 | r1 = sf_read_short(sndref, refsample, infostst->channels); 200 | 201 | if (r1 != infostst->channels) { 202 | printf("Failed to read reference data: %s " 203 | "(r1=%d, channels=%d)", 204 | sf_strerror(sndref), r1, 205 | infostst->channels); 206 | return -1; 207 | } 208 | 209 | r2 = sf_read_short(sndtst, tstsample, infostst->channels); 210 | if (r2 != infostst->channels) { 211 | printf("Failed to read test data: %s " 212 | "(r2=%d, channels=%d)\n", 213 | sf_strerror(sndtst), r2, 214 | infostst->channels); 215 | return -1; 216 | } 217 | 218 | for (j = 0; j < infostst->channels; j++) { 219 | refbits = sampletobits(refsample[j], 0); 220 | tstbits = sampletobits(tstsample[j], 0); 221 | 222 | cur_diff = fabs(tstbits - refbits); 223 | 224 | if (cur_diff > rms_absolute) { 225 | calc_count++; 226 | /* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */ 227 | verdict = 0; 228 | } 229 | 230 | if (cur_diff > calc_max[j]) { 231 | calc_max[j] = cur_diff; 232 | refmax[j] = refsample[j]; 233 | tstmax[j] = tstsample[j]; 234 | } 235 | } 236 | } 237 | 238 | for (j = 0; j < infostst->channels; j++) { 239 | printf("Calculated max: %f (%hd-%hd=%hd)\n", 240 | calc_max[j], tstmax[j], refmax[j], 241 | tstmax[j] - refmax[j]); 242 | } 243 | 244 | printf("%s return %d\n", __FUNCTION__, verdict); 245 | 246 | return verdict; 247 | } 248 | 249 | static void usage(void) 250 | { 251 | printf("SBC conformance test ver %s\n", VERSION); 252 | printf("Copyright (c) 2007-2010 Marcel Holtmann\n"); 253 | printf("Copyright (c) 2007-2008 Frederic Dalleau\n\n"); 254 | 255 | printf("Usage:\n" 256 | "\tsbctester reference.wav checkfile.wav\n" 257 | "\tsbctester integer\n" 258 | "\n"); 259 | 260 | printf("To test the encoder:\n"); 261 | printf("\tUse a reference codec to encode original.wav to reference.sbc\n"); 262 | printf("\tUse sbcenc to encode original.wav to checkfile.sbc\n"); 263 | printf("\tDecode both file using the reference decoder\n"); 264 | printf("\tRun sbctester with these two wav files to get the result\n\n"); 265 | 266 | printf("\tA file called out.csv is generated to use the data in a\n"); 267 | printf("\tspreadsheet application or database.\n\n"); 268 | } 269 | 270 | int main(int argc, char *argv[]) 271 | { 272 | SNDFILE *sndref = NULL; 273 | SNDFILE *sndtst = NULL; 274 | SF_INFO infosref; 275 | SF_INFO infostst; 276 | char *ref; 277 | char *tst; 278 | int pass_rms, pass_absolute, pass, accuracy; 279 | 280 | if (argc == 2) { 281 | double db; 282 | 283 | printf("Test sampletobits\n"); 284 | db = sampletobits((short) atoi(argv[1]), 1); 285 | printf("db = %f\n", db); 286 | exit(0); 287 | } 288 | 289 | if (argc < 3) { 290 | usage(); 291 | exit(1); 292 | } 293 | 294 | ref = argv[1]; 295 | tst = argv[2]; 296 | 297 | printf("opening reference %s\n", ref); 298 | 299 | sndref = sf_open(ref, SFM_READ, &infosref); 300 | if (!sndref) { 301 | printf("Failed to open reference file\n"); 302 | exit(1); 303 | } 304 | 305 | printf("opening testfile %s\n", tst); 306 | sndtst = sf_open(tst, SFM_READ, &infostst); 307 | if (!sndtst) { 308 | printf("Failed to open test file\n"); 309 | sf_close(sndref); 310 | exit(1); 311 | } 312 | 313 | printf("reference:\n\t%d frames,\n\t%d hz,\n\t%d channels\n", 314 | (int) infosref.frames, (int) infosref.samplerate, 315 | (int) infosref.channels); 316 | printf("testfile:\n\t%d frames,\n\t%d hz,\n\t%d channels\n", 317 | (int) infostst.frames, (int) infostst.samplerate, 318 | (int) infostst.channels); 319 | 320 | /* check number of channels */ 321 | if (infosref.channels > 2 || infostst.channels > 2) { 322 | printf("Too many channels\n"); 323 | goto error; 324 | } 325 | 326 | /* compare number of samples */ 327 | if (infosref.samplerate != infostst.samplerate || 328 | infosref.channels != infostst.channels) { 329 | printf("Cannot compare files with different charasteristics\n"); 330 | goto error; 331 | } 332 | 333 | accuracy = DEFACCURACY; 334 | printf("Accuracy: %d\n", accuracy); 335 | 336 | /* Condition 1 rms level */ 337 | pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst, 338 | accuracy, "out.csv"); 339 | if (pass_rms < 0) 340 | goto error; 341 | 342 | /* Condition 2 absolute difference */ 343 | pass_absolute = check_absolute_diff(sndref, &infosref, sndtst, 344 | &infostst, accuracy); 345 | if (pass_absolute < 0) 346 | goto error; 347 | 348 | /* Verdict */ 349 | pass = pass_rms && pass_absolute; 350 | printf("Verdict: %s\n", pass ? "pass" : "fail"); 351 | 352 | return 0; 353 | 354 | error: 355 | sf_close(sndref); 356 | sf_close(sndtst); 357 | 358 | exit(1); 359 | } 360 | 361 | #endif 362 | --------------------------------------------------------------------------------