diff --git a/aubio/COPYING b/aubio/COPYING
new file mode 100644
index 00000000..94a9ed02
--- /dev/null
+++ b/aubio/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/aubio/src/aubio.h b/aubio/src/aubio.h
new file mode 100644
index 00000000..3c9216d0
--- /dev/null
+++ b/aubio/src/aubio.h
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \mainpage
+
+ \section introduction Introduction
+
+ aubio is a library to extract annotations from audio signals: it provides a
+ set of functions that take an input audio signal, and output pitch estimates,
+ attack times (onset), beat location estimates, and other annotation tasks.
+
+ \section basics Basics
+
+ All object structures in aubio share the same function prefixes and suffixes:
+
+ - \p new_aubio_foo creates the object \p foo
+ - \p aubio_foo_do executes the object \p foo
+ - \p del_aubio_foo destroys the object \p foo
+
+ All memory allocation and deallocation take place in the \p new_ and \p del_
+ functions. Optionally, more than one \p _do methods are available.
+ Additional parameters can be adjusted and observed using:
+
+ - \p aubio_foo_get_param, getter function, gets the value of a parameter
+ - \p aubio_foo_set_param, setter function, changes the value of a parameter
+
+ Unless specified in its documentation, no memory operations take place in the
+ getter functions. However, memory resizing can take place in setter
+ functions.
+
+ \subsection vectors Vectors
+
+ Two basic structures are being used in aubio: ::fvec_t and ::cvec_t. The
+ ::fvec_t structures are used to store vectors of floating pointer number.
+ ::cvec_t are used to store complex number, as two vectors of norm and phase
+ elements.
+
+ Additionally, the ::lvec_t structure can be used to store floating point
+ numbers in double precision. They are mostly used to store filter
+ coefficients, to avoid instability.
+
+ \subsection objects Available objects
+
+ Here is a list of some of the most common objects for aubio:
+
+ \code
+
+ // fast Fourier transform (FFT)
+ aubio_fft_t *fft = new_aubio_fft (winsize);
+ // phase vocoder
+ aubio_pvoc_t *pv = new_aubio_pvoc (winsize, stepsize);
+ // onset detection
+ aubio_onset_t *onset = new_aubio_onset (method, winsize, stepsize, samplerate);
+ // pitch detection
+ aubio_pitch_t *pitch = new_aubio_pitch (method, winsize, stepsize, samplerate);
+ // beat tracking
+ aubio_tempo_t *tempo = new_aubio_tempo (method, winsize, stepsize, samplerate);
+
+ \endcode
+
+ See the list of typedefs for a complete list.
+
+ \subsection example Example
+
+ Here is a simple example that creates an A-Weighting filter and applies it to a
+ vector.
+
+ \code
+
+ // set window size, and sampling rate
+ uint_t winsize = 1024, sr = 44100;
+ // create a vector
+ fvec_t *this_buffer = new_fvec (winsize);
+ // create the a-weighting filter
+ aubio_filter_t *this_filter = new_aubio_filter_a_weighting (sr);
+
+ while (running) {
+ // here some code to put some data in this_buffer
+ // ...
+
+ // apply the filter, in place
+ aubio_filter_do (this_filter, this_buffer);
+
+ // here some code to get some data from this_buffer
+ // ...
+ }
+
+ // and free the structures
+ del_aubio_filter (this_filter);
+ del_fvec (this_buffer);
+
+ \endcode
+
+ Several examples of C programs are available in the \p examples/ and \p tests/src
+ directories of the source tree.
+
+ Some examples:
+ - @ref spectral/test-fft.c
+ - @ref spectral/test-phasevoc.c
+ - @ref onset/test-onset.c
+ - @ref pitch/test-pitch.c
+ - @ref tempo/test-tempo.c
+ - @ref test-fvec.c
+ - @ref test-cvec.c
+
+ \subsection unstable_api Unstable API
+
+ Several more functions are available and used within aubio, but not
+ documented here, either because they are not considered useful to the user,
+ or because they may need to be changed in the future. However, they can still
+ be used by defining AUBIO_UNSTABLE to 1 before including the aubio header:
+
+ \code
+ #define AUBIO_UNSTABLE 1
+ #include
+ \endcode
+
+ Future versions of aubio could break API compatibility with these functions
+ without warning. If you choose to use functions in AUBIO_UNSTABLE, you are on
+ your own.
+
+ \section download Download
+
+ Latest versions, further documentation, examples, wiki, and mailing lists can
+ be found at https://aubio.org .
+
+ */
+
+#ifndef AUBIO_H
+#define AUBIO_H
+
+/** @file aubio.h Global aubio include file.
+
+ You will want to include this file as:
+
+ @code
+ #include
+ @endcode
+
+ To access headers with unstable prototypes, use:
+
+ @code
+ #define AUBIO_UNSTABLE 1
+ #include
+ @endcode
+
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* in this order */
+#include "types.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "lvec.h"
+#include "fmat.h"
+#include "musicutils.h"
+#include "vecutils.h"
+#include "temporal/resampler.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+#include "temporal/a_weighting.h"
+#include "temporal/c_weighting.h"
+#include "spectral/fft.h"
+#include "spectral/dct.h"
+#include "spectral/phasevoc.h"
+#include "spectral/filterbank.h"
+#include "spectral/filterbank_mel.h"
+#include "spectral/mfcc.h"
+#include "spectral/specdesc.h"
+#include "spectral/awhitening.h"
+#include "spectral/tss.h"
+#include "pitch/pitch.h"
+#include "onset/onset.h"
+#include "tempo/tempo.h"
+#include "notes/notes.h"
+#include "io/source.h"
+#include "io/sink.h"
+#include "synth/sampler.h"
+#include "synth/wavetable.h"
+#include "utils/parameter.h"
+#include "utils/log.h"
+
+#if AUBIO_UNSTABLE
+#include "mathutils.h"
+#include "io/source_sndfile.h"
+#include "io/source_apple_audio.h"
+#include "io/source_avcodec.h"
+#include "io/source_wavread.h"
+#include "io/sink_sndfile.h"
+#include "io/sink_apple_audio.h"
+#include "io/sink_wavwrite.h"
+#include "io/audio_unit.h"
+#include "onset/peakpicker.h"
+#include "pitch/pitchmcomb.h"
+#include "pitch/pitchyin.h"
+#include "pitch/pitchyinfft.h"
+#include "pitch/pitchyinfast.h"
+#include "pitch/pitchschmitt.h"
+#include "pitch/pitchfcomb.h"
+#include "pitch/pitchspecacf.h"
+#include "tempo/beattracking.h"
+#include "effects/pitchshift.h"
+#include "effects/timestretch.h"
+#include "utils/scale.h"
+#include "utils/hist.h"
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/aubio/src/aubio_priv.h b/aubio/src/aubio_priv.h
new file mode 100644
index 00000000..955f63c6
--- /dev/null
+++ b/aubio/src/aubio_priv.h
@@ -0,0 +1,414 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** @file
+ * Private include file
+ *
+ * This file is for inclusion from _within_ the library only.
+ */
+
+#ifndef AUBIO_PRIV_H
+#define AUBIO_PRIV_H
+
+/*********************
+ *
+ * External includes
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include
+#endif
+
+#ifdef HAVE_STDIO_H
+#include
+#endif
+
+/* must be included before fftw3.h */
+#ifdef HAVE_COMPLEX_H
+#include
+#endif
+
+#if defined(HAVE_FFTW3) || defined(HAVE_FFTW3F)
+#include
+#endif
+
+#ifdef HAVE_MATH_H
+#include
+#endif
+
+#ifdef HAVE_STRING_H
+#include
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include // for CHAR_BIT, in C99 standard
+#endif
+
+#ifdef HAVE_STDARG_H
+#include
+#endif
+
+#if defined(HAVE_BLAS) // --enable-blas=true
+// check which cblas header we found
+#if defined(HAVE_ATLAS_CBLAS_H)
+#define HAVE_ATLAS 1
+#include
+#elif defined(HAVE_OPENBLAS_CBLAS_H)
+#include
+#elif defined(HAVE_CBLAS_H)
+#include
+#elif !defined(HAVE_ACCELERATE)
+#error "HAVE_BLAS was defined, but no blas header was found"
+#endif /* end of cblas includes */
+#endif
+
+#if defined(HAVE_ACCELERATE)
+// include accelerate framework after blas
+#define HAVE_ATLAS 1
+#define HAVE_BLAS 1
+#define ACCELERATE_NEW_LAPACK 1
+#define ACCELERATE_LAPACK_ILP6 1
+#include
+
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_vDSP_mmov vDSP_mmov
+#define aubio_vDSP_vmul vDSP_vmul
+#define aubio_vDSP_vsmul vDSP_vsmul
+#define aubio_vDSP_vsadd vDSP_vsadd
+#define aubio_vDSP_vfill vDSP_vfill
+#define aubio_vDSP_meanv vDSP_meanv
+#define aubio_vDSP_sve vDSP_sve
+#define aubio_vDSP_maxv vDSP_maxv
+#define aubio_vDSP_maxvi vDSP_maxvi
+#define aubio_vDSP_minv vDSP_minv
+#define aubio_vDSP_minvi vDSP_minvi
+#define aubio_vDSP_dotpr vDSP_dotpr
+#define aubio_vDSP_vclr vDSP_vclr
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_vDSP_mmov vDSP_mmovD
+#define aubio_vDSP_vmul vDSP_vmulD
+#define aubio_vDSP_vsmul vDSP_vsmulD
+#define aubio_vDSP_vsadd vDSP_vsaddD
+#define aubio_vDSP_vfill vDSP_vfillD
+#define aubio_vDSP_meanv vDSP_meanvD
+#define aubio_vDSP_sve vDSP_sveD
+#define aubio_vDSP_maxv vDSP_maxvD
+#define aubio_vDSP_maxvi vDSP_maxviD
+#define aubio_vDSP_minv vDSP_minvD
+#define aubio_vDSP_minvi vDSP_minviD
+#define aubio_vDSP_dotpr vDSP_dotprD
+#define aubio_vDSP_vclr vDSP_vclrD
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_ACCELERATE */
+
+#if defined(HAVE_BLAS)
+#ifndef HAVE_AUBIO_DOUBLE
+#ifdef HAVE_ATLAS
+#define aubio_catlas_set catlas_sset
+#endif /* HAVE_ATLAS */
+#define aubio_cblas_copy cblas_scopy
+#define aubio_cblas_swap cblas_sswap
+#define aubio_cblas_dot cblas_sdot
+#else /* HAVE_AUBIO_DOUBLE */
+#ifdef HAVE_ATLAS
+#define aubio_catlas_set catlas_dset
+#endif /* HAVE_ATLAS */
+#define aubio_cblas_copy cblas_dcopy
+#define aubio_cblas_swap cblas_dswap
+#define aubio_cblas_dot cblas_ddot
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif /* HAVE_BLAS */
+
+#if defined HAVE_INTEL_IPP
+#include
+#include
+#include
+#ifndef HAVE_AUBIO_DOUBLE
+#define aubio_ippsSet ippsSet_32f
+#define aubio_ippsZero ippsZero_32f
+#define aubio_ippsCopy ippsCopy_32f
+#define aubio_ippsMul ippsMul_32f
+#define aubio_ippsMulC ippsMulC_32f
+#define aubio_ippsAddC ippsAddC_32f
+#define aubio_ippsLn ippsLn_32f_A21
+#define aubio_ippsMean(a,b,c) ippsMean_32f(a, b, c, ippAlgHintFast)
+#define aubio_ippsSum(a,b,c) ippsSum_32f(a, b, c, ippAlgHintFast)
+#define aubio_ippsMax ippsMax_32f
+#define aubio_ippsMin ippsMin_32f
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_ippsSet ippsSet_64f
+#define aubio_ippsZero ippsZero_64f
+#define aubio_ippsCopy ippsCopy_64f
+#define aubio_ippsMul ippsMul_64f
+#define aubio_ippsMulC ippsMulC_64f
+#define aubio_ippsAddC ippsAddC_64f
+#define aubio_ippsLn ippsLn_64f_A26
+#define aubio_ippsMean ippsMean_64f
+#define aubio_ippsSum ippsSum_64f
+#define aubio_ippsMax ippsMax_64f
+#define aubio_ippsMin ippsMin_64f
+#endif /* HAVE_AUBIO_DOUBLE */
+#endif
+
+#if !defined(HAVE_MEMCPY_HACKS) && !defined(HAVE_ACCELERATE) && !defined(HAVE_ATLAS) && !defined(HAVE_INTEL_IPP)
+#define HAVE_NOOPT 1
+#endif
+
+#include "types.h"
+
+#define AUBIO_UNSTABLE 1
+
+#include "mathutils.h"
+
+/****
+ *
+ * SYSTEM INTERFACE
+ *
+ */
+
+/* Memory management */
+#define AUBIO_MALLOC(_n) malloc(_n)
+#define AUBIO_REALLOC(_p,_n) realloc(_p,_n)
+#define AUBIO_NEW(_t) (_t*)calloc(sizeof(_t), 1)
+#define AUBIO_ARRAY(_t,_n) (_t*)calloc((_n)*sizeof(_t), 1)
+#define AUBIO_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
+#define AUBIO_MEMSET(_dst,_src,_t) memset(_dst,_src,_t)
+#define AUBIO_FREE(_p) free(_p)
+
+
+/* file interface */
+#define AUBIO_FOPEN(_f,_m) fopen(_f,_m)
+#define AUBIO_FCLOSE(_f) fclose(_f)
+#define AUBIO_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
+#define AUBIO_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
+
+/* strings */
+#define AUBIO_STRLEN(_s) strlen(_s)
+#define AUBIO_STRCMP(_s,_t) strcmp(_s,_t)
+#define AUBIO_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
+#define AUBIO_STRCPY(_dst,_src) strcpy(_dst,_src)
+#define AUBIO_STRCHR(_s,_c) strchr(_s,_c)
+#ifdef strdup
+#define AUBIO_STRDUP(s) strdup(s)
+#else
+#define AUBIO_STRDUP(s) AUBIO_STRCPY(AUBIO_MALLOC(AUBIO_STRLEN(s) + 1), s)
+#endif
+
+
+/* Error reporting */
+typedef enum {
+ AUBIO_OK = 0,
+ AUBIO_FAIL = 1
+} aubio_status;
+
+/* Logging */
+
+#include "utils/log.h"
+
+/** internal logging function, defined in utils/log.c */
+uint_t aubio_log(sint_t level, const char_t *fmt, ...);
+
+#ifdef HAVE_C99_VARARGS_MACROS
+#define AUBIO_ERR(...) aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " __VA_ARGS__)
+#define AUBIO_INF(...) aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " __VA_ARGS__)
+#define AUBIO_MSG(...) aubio_log(AUBIO_LOG_MSG, __VA_ARGS__)
+#define _AUBIO_DBG(...) aubio_log(AUBIO_LOG_DBG, __VA_ARGS__)
+#define AUBIO_WRN(...) aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " __VA_ARGS__)
+#else
+#define AUBIO_ERR(format, args...) aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " format , ##args)
+#define AUBIO_INF(format, args...) aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " format , ##args)
+#define AUBIO_MSG(format, args...) aubio_log(AUBIO_LOG_MSG, format , ##args)
+#define _AUBIO_DBG(format, args...) aubio_log(AUBIO_LOG_DBG, format , ##args)
+#define AUBIO_WRN(format, args...) aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " format, ##args)
+#endif
+
+#ifdef DEBUG
+#define AUBIO_DBG _AUBIO_DBG
+#else
+// disable debug output
+#ifdef HAVE_C99_VARARGS_MACROS
+#define AUBIO_DBG(...) {}
+#else
+#define AUBIO_DBG(format, args...) {}
+#endif
+#endif
+
+#define AUBIO_ERROR AUBIO_ERR
+
+#define AUBIO_QUIT(_s) exit(_s)
+#define AUBIO_SNPRINTF snprintf
+
+#define AUBIO_MAX_SAMPLERATE (192000*8)
+#define AUBIO_MAX_CHANNELS 1024
+
+/* pi and 2*pi */
+#ifndef M_PI
+#define PI (3.14159265358979323846)
+#else
+#define PI (M_PI)
+#endif
+#define TWO_PI (PI*2.)
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/* aliases to math.h functions */
+#if !HAVE_AUBIO_DOUBLE
+#define EXP expf
+#define COS cosf
+#define SIN sinf
+#define ABS fabsf
+#define POW powf
+#define SQRT sqrtf
+#define LOG10 log10f
+#define LOG logf
+#define FLOOR floorf
+#define CEIL ceilf
+#define ATAN atanf
+#define ATAN2 atan2f
+#else
+#define EXP exp
+#define COS cos
+#define SIN sin
+#define ABS fabs
+#define POW pow
+#define SQRT sqrt
+#define LOG10 log10
+#define LOG log
+#define FLOOR floor
+#define CEIL ceil
+#define ATAN atan
+#define ATAN2 atan2
+#endif
+#define ROUND(x) FLOOR(x+.5)
+
+/* aliases to complex.h functions */
+#if HAVE_AUBIO_DOUBLE || !defined(HAVE_COMPLEX_H) || defined(WIN32)
+/* mingw32 does not know about c*f functions */
+#define EXPC cexp
+/** complex = CEXPC(complex) */
+#define CEXPC cexp
+/** sample = ARGC(complex) */
+#define ARGC carg
+/** sample = ABSC(complex) norm */
+#define ABSC cabs
+/** sample = REAL(complex) */
+#define REAL creal
+/** sample = IMAG(complex) */
+#define IMAG cimag
+#else
+/** sample = EXPC(complex) */
+#define EXPC cexpf
+/** complex = CEXPC(complex) */
+#define CEXPC cexp
+/** sample = ARGC(complex) */
+#define ARGC cargf
+/** sample = ABSC(complex) norm */
+#define ABSC cabsf
+/** sample = REAL(complex) */
+#define REAL crealf
+/** sample = IMAG(complex) */
+#define IMAG cimagf
+#endif
+
+/* avoid unresolved symbol with msvc 9 */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define isnan _isnan
+#endif
+
+#if !defined(_WIN32)
+#define AUBIO_STRERROR(errno,buf,len) strerror_r(errno, buf, len)
+#else
+#define AUBIO_STRERROR(errno,buf,len) strerror_s(buf, len, errno)
+#endif
+
+#ifdef HAVE_C99_VARARGS_MACROS
+#define AUBIO_STRERR(...) \
+ char errorstr[256]; \
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr)); \
+ AUBIO_ERR(__VA_ARGS__)
+#else
+#define AUBIO_STRERR(format, args...) \
+ char errorstr[256]; \
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr)); \
+ AUBIO_ERR(format, ##args)
+#endif
+
+/* handy shortcuts */
+#define DB2LIN(g) (POW(10.0,(g)*0.05f))
+#define LIN2DB(v) (20.0*LOG10(v))
+#define SQR(_a) ((_a)*(_a))
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif /* MAX */
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif /* MIN */
+
+#define ELEM_SWAP(a,b) { register smpl_t t=(a);(a)=(b);(b)=t; }
+
+#define VERY_SMALL_NUMBER 2.e-42 //1.e-37
+
+/** if ABS(f) < VERY_SMALL_NUMBER, returns 1, else 0 */
+#define IS_DENORMAL(f) ABS(f) < VERY_SMALL_NUMBER
+
+/** if ABS(f) < VERY_SMALL_NUMBER, returns 0., else f */
+#define KILL_DENORMAL(f) IS_DENORMAL(f) ? 0. : f
+
+/** if f > VERY_SMALL_NUMBER, returns f, else returns VERY_SMALL_NUMBER */
+#define CEIL_DENORMAL(f) f < VERY_SMALL_NUMBER ? VERY_SMALL_NUMBER : f
+
+#define SAFE_LOG10(f) LOG10(CEIL_DENORMAL(f))
+#define SAFE_LOG(f) LOG(CEIL_DENORMAL(f))
+
+/** silence unused parameter warning by adding an attribute */
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+/* are we using gcc -std=c99 ? */
+#if defined(__STRICT_ANSI__)
+#define strnlen(a,b) MIN(strlen(a),b)
+#if !HAVE_AUBIO_DOUBLE
+#define floorf floor
+#endif
+#endif /* __STRICT_ANSI__ */
+
+#if defined(DEBUG)
+#include
+#define AUBIO_ASSERT(x) assert(x)
+#else
+#define AUBIO_ASSERT(x)
+#endif /* DEBUG */
+
+#endif /* AUBIO_PRIV_H */
diff --git a/aubio/src/config.h b/aubio/src/config.h
new file mode 100644
index 00000000..827971b9
--- /dev/null
+++ b/aubio/src/config.h
@@ -0,0 +1,22 @@
+#ifndef CMAKE_CONFIG_H
+#define CMAKE_CONFIG_H
+
+#define HAVE_C99_VARARGS_MACROS 1
+
+#define HAVE_STDLIB_H 1
+#define HAVE_STDIO_H 1
+#define HAVE_MATH_H 1
+#define HAVE_STRING_H 1
+#define HAVE_ERRNO_H 1
+#define HAVE_LIMITS_H 1
+#define HAVE_STDARG_H 1
+
+/* no FFTW3, no Accelerate, no Intel IPP — uses Ooura FFT */
+/* no SNDFILE, no SAMPLERATE, no libav — we supply our own samples */
+
+/* MSVC compatibility */
+#ifdef _MSC_VER
+#define strncasecmp _strnicmp
+#endif
+
+#endif /* CMAKE_CONFIG_H */
diff --git a/aubio/src/cvec.c b/aubio/src/cvec.c
new file mode 100644
index 00000000..00c43bee
--- /dev/null
+++ b/aubio/src/cvec.c
@@ -0,0 +1,169 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "cvec.h"
+
+cvec_t * new_cvec(uint_t length) {
+ cvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(cvec_t);
+ s->length = length/2 + 1;
+ s->norm = AUBIO_ARRAY(smpl_t,s->length);
+ s->phas = AUBIO_ARRAY(smpl_t,s->length);
+ return s;
+}
+
+void del_cvec(cvec_t *s) {
+ AUBIO_FREE(s->norm);
+ AUBIO_FREE(s->phas);
+ AUBIO_FREE(s);
+}
+
+void cvec_norm_set_sample (cvec_t *s, smpl_t data, uint_t position) {
+ s->norm[position] = data;
+}
+
+void cvec_phas_set_sample (cvec_t *s, smpl_t data, uint_t position) {
+ s->phas[position] = data;
+}
+
+smpl_t cvec_norm_get_sample (cvec_t *s, uint_t position) {
+ return s->norm[position];
+}
+
+smpl_t cvec_phas_get_sample (cvec_t *s, uint_t position) {
+ return s->phas[position];
+}
+
+smpl_t * cvec_norm_get_data (const cvec_t *s) {
+ return s->norm;
+}
+
+smpl_t * cvec_phas_get_data (const cvec_t *s) {
+ return s->phas;
+}
+
+/* helper functions */
+
+void cvec_print(const cvec_t *s) {
+ uint_t j;
+ AUBIO_MSG("norm: ");
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->norm[j]);
+ }
+ AUBIO_MSG("\n");
+ AUBIO_MSG("phas: ");
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->phas[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void cvec_copy(const cvec_t *s, cvec_t *t) {
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d elements to %d elements \n",
+ s->length, t->length);
+ return;
+ }
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsCopy(s->phas, t->phas, (int)s->length);
+ aubio_ippsCopy(s->norm, t->norm, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
+ memcpy(t->norm, s->norm, t->length * sizeof(smpl_t));
+ memcpy(t->phas, s->phas, t->length * sizeof(smpl_t));
+#else
+ uint_t j;
+ for (j=0; j< t->length; j++) {
+ t->norm[j] = s->norm[j];
+ t->phas[j] = s->phas[j];
+ }
+#endif
+}
+
+void cvec_norm_set_all(cvec_t *s, smpl_t val) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsSet(val, s->norm, (int)s->length);
+#else
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->norm[j] = val;
+ }
+#endif
+}
+
+void cvec_norm_zeros(cvec_t *s) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsZero(s->norm, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
+ memset(s->norm, 0, s->length * sizeof(smpl_t));
+#else
+ cvec_norm_set_all (s, 0.);
+#endif
+}
+
+void cvec_norm_ones(cvec_t *s) {
+ cvec_norm_set_all (s, 1.);
+}
+
+void cvec_phas_set_all (cvec_t *s, smpl_t val) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsSet(val, s->phas, (int)s->length);
+#else
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->phas[j] = val;
+ }
+#endif
+}
+
+void cvec_phas_zeros(cvec_t *s) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsZero(s->phas, (int)s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
+ memset(s->phas, 0, s->length * sizeof(smpl_t));
+#else
+ cvec_phas_set_all (s, 0.);
+#endif
+}
+
+void cvec_phas_ones(cvec_t *s) {
+ cvec_phas_set_all (s, 1.);
+}
+
+void cvec_zeros(cvec_t *s) {
+ cvec_norm_zeros(s);
+ cvec_phas_zeros(s);
+}
+
+void cvec_logmag(cvec_t *s, smpl_t lambda) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsMulC(s->norm, lambda, s->norm, (int)s->length);
+ aubio_ippsAddC(s->norm, 1.0, s->norm, (int)s->length);
+ aubio_ippsLn(s->norm, s->norm, (int)s->length);
+#else
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->norm[j] = LOG(lambda * s->norm[j] + 1);
+ }
+#endif
+}
diff --git a/aubio/src/cvec.h b/aubio/src/cvec.h
new file mode 100644
index 00000000..7c826b68
--- /dev/null
+++ b/aubio/src/cvec.h
@@ -0,0 +1,247 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_CVEC_H
+#define AUBIO_CVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of complex-valued data, stored in polar coordinates
+
+ This file specifies the ::cvec_t buffer type, which is used throughout aubio
+ to store complex data. Complex values are stored in terms of ::cvec_t.phas
+ and norm, within 2 vectors of ::smpl_t of size (size/2+1) each.
+
+ \example test-cvec.c
+
+*/
+
+/** Vector of real-valued phase and spectrum data
+
+ \code
+
+ uint_t buffer_size = 1024;
+
+ // create a complex vector of 512 values
+ cvec_t * input = new_cvec (buffer_size);
+
+ // set some values of the vector
+ input->norm[23] = 2.;
+ input->phas[23] = M_PI;
+ // ..
+
+ // compute the mean of the vector
+ mean = cvec_mean(input);
+
+ // destroy the vector
+ del_cvec (input);
+
+ \endcode
+
+ */
+typedef struct {
+ uint_t length; /**< length of buffer = (requested length)/2 + 1 */
+ smpl_t *norm; /**< norm array of size ::cvec_t.length */
+ smpl_t *phas; /**< phase array of size ::cvec_t.length */
+} cvec_t;
+
+/** cvec_t buffer creation function
+
+ This function creates a cvec_t structure holding two arrays of size
+ [length/2+1], corresponding to the norm and phase values of the
+ spectral frame. The length stored in the structure is the actual size of both
+ arrays, not the length of the complex and symmetrical vector, specified as
+ creation argument.
+
+ \param length the length of the buffer to create
+
+*/
+cvec_t * new_cvec(uint_t length);
+
+/** cvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_cvec()
+
+*/
+void del_cvec(cvec_t *s);
+
+/** write norm value in a complex buffer
+
+ This is equivalent to:
+ \code
+ s->norm[position] = val;
+ \endcode
+
+ \param s vector to write to
+ \param val norm value to write in s->norm[position]
+ \param position sample position to write to
+
+*/
+void cvec_norm_set_sample (cvec_t *s, smpl_t val, uint_t position);
+
+/** write phase value in a complex buffer
+
+ This is equivalent to:
+ \code
+ s->phas[position] = val;
+ \endcode
+
+ \param s vector to write to
+ \param val phase value to write in s->phas[position]
+ \param position sample position to write to
+
+*/
+void cvec_phas_set_sample (cvec_t *s, smpl_t val, uint_t position);
+
+/** read norm value from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t foo = s->norm[position];
+ \endcode
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+smpl_t cvec_norm_get_sample (cvec_t *s, uint_t position);
+
+/** read phase value from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t foo = s->phas[position];
+ \endcode
+
+ \param s vector to read from
+ \param position sample position to read from
+ \returns the value of the sample at position
+
+*/
+smpl_t cvec_phas_get_sample (cvec_t *s, uint_t position);
+
+/** read norm data from a complex buffer
+
+ \code
+ smpl_t *data = s->norm;
+ \endcode
+
+ \param s vector to read from
+
+*/
+smpl_t * cvec_norm_get_data (const cvec_t *s);
+
+/** read phase data from a complex buffer
+
+ This is equivalent to:
+ \code
+ smpl_t *data = s->phas;
+ \endcode
+
+ \param s vector to read from
+
+*/
+smpl_t * cvec_phas_get_data (const cvec_t *s);
+
+/** print out cvec data
+
+ \param s vector to print out
+
+*/
+void cvec_print(const cvec_t *s);
+
+/** make a copy of a vector
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void cvec_copy(const cvec_t *s, cvec_t *t);
+
+/** set all norm elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void cvec_norm_set_all (cvec_t *s, smpl_t val);
+
+/** set all norm elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_norm_zeros(cvec_t *s);
+
+/** set all norm elements to one
+
+ \param s vector to modify
+
+*/
+void cvec_norm_ones(cvec_t *s);
+
+/** set all phase elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void cvec_phas_set_all (cvec_t *s, smpl_t val);
+
+/** set all phase elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_phas_zeros(cvec_t *s);
+
+/** set all phase elements to one
+
+ \param s vector to modify
+
+*/
+void cvec_phas_ones(cvec_t *s);
+
+/** set all norm and phas elements to zero
+
+ \param s vector to modify
+
+*/
+void cvec_zeros(cvec_t *s);
+
+/** take logarithmic magnitude
+
+ \param s input cvec to compress
+ \param lambda value to use for normalisation
+
+ \f$ S_k = log( \lambda * S_k + 1 ) \f$
+
+*/
+void cvec_logmag(cvec_t *s, smpl_t lambda);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_CVEC_H */
diff --git a/aubio/src/effects/pitchshift.h b/aubio/src/effects/pitchshift.h
new file mode 100644
index 00000000..a67a6dcc
--- /dev/null
+++ b/aubio/src/effects/pitchshift.h
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_PITCHSHIFT_H
+#define AUBIO_PITCHSHIFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Pitch shifting object
+
+ ::aubio_pitchshift_t can be used to transpose a stream of blocks of frames.
+
+ \example effects/test-pitchshift.c
+
+*/
+
+/** pitch shifting object */
+typedef struct _aubio_pitchshift_t aubio_pitchshift_t;
+
+/** execute pitch shifting on an input signal frame
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param in input signal of size [hop_size]
+ \param out output pitch candidates of size [1]
+
+*/
+void aubio_pitchshift_do (aubio_pitchshift_t * o, const fvec_t * in,
+ fvec_t * out);
+
+/** deletion of the pitch shifting object
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+
+*/
+void del_aubio_pitchshift (aubio_pitchshift_t * o);
+
+/** creation of the pitch shifting object
+
+ \param method set pitch shifting algorithm ("default")
+ \param transpose initial pitch transposition
+ \param hop_size step size between two consecutive analysis instant
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_pitchshift_t
+
+*/
+aubio_pitchshift_t *new_aubio_pitchshift (const char_t * method,
+ smpl_t transpose, uint_t hop_size, uint_t samplerate);
+
+/** get the latency of the pitch shifting object, in samples
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return latency of the pitch shifting object in samples
+
+*/
+uint_t aubio_pitchshift_get_latency (aubio_pitchshift_t * o);
+
+/** set the pitch scale of the pitch shifting object
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param pitchscale new pitch scale of the pitch shifting object
+
+ pitchscale is a frequency ratio. It should be in the range [0.25, 4].
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_pitchshift_set_pitchscale (aubio_pitchshift_t * o,
+ smpl_t pitchscale);
+
+/** get the pitchscale of the pitch shifting object
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return pitchscale of the pitch shifting object
+
+*/
+smpl_t aubio_pitchshift_get_pitchscale (aubio_pitchshift_t * o);
+
+/** set the transposition of the pitch shifting object, in semitones
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param transpose new pitch transposition of the pitch shifting object,
+ expressed in semitones (should be in the range [-24;+24])
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_pitchshift_set_transpose (aubio_pitchshift_t * o,
+ smpl_t transpose);
+
+/** get the transposition of the pitch shifting object, in semitones
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return transposition of the pitch shifting object, in semitones
+
+*/
+smpl_t aubio_pitchshift_get_transpose (aubio_pitchshift_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSHIFT_H */
diff --git a/aubio/src/effects/timestretch.h b/aubio/src/effects/timestretch.h
new file mode 100644
index 00000000..52861c1c
--- /dev/null
+++ b/aubio/src/effects/timestretch.h
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_TIMESTRETCH_H
+#define AUBIO_TIMESTRETCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ time stretching object
+
+ ::aubio_timestretch_t can be used to open a source file, read samples from
+ it, time-stretch them, and write out the modified samples.
+
+ The time-stretching factor can be changed at any time using
+ aubio_timestretch_set_stretch().
+
+ A transposition can also be applied and changed at any time with
+ aubio_timestretch_set_transpose().
+
+ \example effects/test-timestretch.c
+
+*/
+
+/** time stretching object */
+typedef struct _aubio_timestretch_t aubio_timestretch_t;
+
+/** execute time stretching on an input signal frame
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param out timestretched output of size [hop_size]
+ \param read number of frames actually wrote out
+
+*/
+void aubio_timestretch_do (aubio_timestretch_t * o, fvec_t * out,
+ uint_t * read);
+
+/** deletion of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+*/
+void del_aubio_timestretch (aubio_timestretch_t * o);
+
+/** creation of the time stretching object
+
+ \param method time stretching algorithm ("default")
+ \param stretch initial time stretching factor
+ \param hop_size block size at which the frames should be produced
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_timestretch_t
+
+*/
+aubio_timestretch_t *new_aubio_timestretch (const char_t * method,
+ smpl_t stretch, uint_t hop_size, uint_t samplerate);
+
+/** push length samples from in to time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+ \param in input vector of new samples to push to time stretching object
+ \param length number of new samples to push from input vector
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_push(aubio_timestretch_t * o, fvec_t *in,
+ uint_t length);
+
+/** get number of currently available samples from time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_get_available(aubio_timestretch_t * o);
+
+/** get the latency of the time stretching object, in samples
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return latency of the time stretching object in samples
+
+*/
+uint_t aubio_timestretch_get_latency (aubio_timestretch_t * o);
+
+/** get the samplerate of the time stretching object
+
+ Call after new_aubio_timestretch() was called with 0 to match the original
+ samplerate of the input file.
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+ \return samplerate of the time stretching object
+
+ */
+uint_t aubio_timestretch_get_samplerate (aubio_timestretch_t * o);
+
+/** set the stretching ratio of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param stretch new time stretching ratio of the time stretching object
+ (should be in the range [0.025; 10.])
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_stretch (aubio_timestretch_t * o, smpl_t stretch);
+
+/** get the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return time stretching ratio of the time stretching object, in the range
+ [0.025; 10.]
+
+*/
+smpl_t aubio_timestretch_get_stretch (aubio_timestretch_t * o);
+
+/** set the pitch scale of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param pitchscale new pitch scale of the time stretching object
+
+ pitchscale is a frequency ratio. It should be in the range [0.25, 4].
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_pitchscale (aubio_timestretch_t * o,
+ smpl_t pitchscale);
+
+/** get the pitchscale of the time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return pitchscale of the time stretching object
+
+*/
+smpl_t aubio_timestretch_get_pitchscale (aubio_timestretch_t * o);
+
+/** set the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+ \param transpose new pitch transposition of the time stretching object,
+ expressed in semitones (should be in the range [-24;+24])
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_transpose (aubio_timestretch_t * o,
+ smpl_t transpose);
+
+/** get the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return transposition of the time stretching object, in semitones
+
+*/
+smpl_t aubio_timestretch_get_transpose (aubio_timestretch_t * o);
+
+/** reset the time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_reset(aubio_timestretch_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TIMESTRETCH_H */
diff --git a/aubio/src/fmat.c b/aubio/src/fmat.c
new file mode 100644
index 00000000..8dde20ce
--- /dev/null
+++ b/aubio/src/fmat.c
@@ -0,0 +1,186 @@
+/*
+ Copyright (C) 2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+
+fmat_t * new_fmat (uint_t height, uint_t length) {
+ fmat_t * s;
+ uint_t i,j;
+ if ((sint_t)length <= 0 || (sint_t)height <= 0 ) {
+ return NULL;
+ }
+ s = AUBIO_NEW(fmat_t);
+ s->height = height;
+ s->length = length;
+ s->data = AUBIO_ARRAY(smpl_t*,s->height);
+ for (i=0; i< s->height; i++) {
+ s->data[i] = AUBIO_ARRAY(smpl_t, s->length);
+ for (j=0; j< s->length; j++) {
+ s->data[i][j]=0.;
+ }
+ }
+ return s;
+}
+
+void del_fmat (fmat_t *s) {
+ uint_t i;
+ for (i=0; iheight; i++) {
+ AUBIO_FREE(s->data[i]);
+ }
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void fmat_set_sample(fmat_t *s, smpl_t data, uint_t channel, uint_t position) {
+ s->data[channel][position] = data;
+}
+
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position) {
+ return s->data[channel][position];
+}
+
+void fmat_get_channel(const fmat_t *s, uint_t channel, fvec_t *output) {
+ output->data = s->data[channel];
+ output->length = s->length;
+ return;
+}
+
+smpl_t * fmat_get_channel_data(const fmat_t *s, uint_t channel) {
+ return s->data[channel];
+}
+
+smpl_t ** fmat_get_data(const fmat_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void fmat_print(const fmat_t *s) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->data[i][j]);
+ }
+ AUBIO_MSG("\n");
+ }
+}
+
+void fmat_set(fmat_t *s, smpl_t val) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< s->length; j++) {
+ s->data[i][j] = val;
+ }
+ }
+}
+
+void fmat_zeros(fmat_t *s) {
+#ifdef HAVE_MEMCPY_HACKS
+ uint_t i;
+ for (i=0; i< s->height; i++) {
+ memset(s->data[i], 0, s->length * sizeof(smpl_t));
+ }
+#else /* HAVE_MEMCPY_HACKS */
+ fmat_set(s, 0.);
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void fmat_ones(fmat_t *s) {
+ fmat_set(s, 1.);
+}
+
+void fmat_rev(fmat_t *s) {
+ uint_t i,j;
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< FLOOR((smpl_t)s->length/2); j++) {
+ ELEM_SWAP(s->data[i][j], s->data[i][s->length-1-j]);
+ }
+ }
+}
+
+void fmat_weight(fmat_t *s, const fmat_t *weight) {
+ uint_t i,j;
+ uint_t length = MIN(s->length, weight->length);
+ for (i=0; i< s->height; i++) {
+ for (j=0; j< length; j++) {
+ s->data[i][j] *= weight->data[0][j];
+ }
+ }
+}
+
+void fmat_copy(const fmat_t *s, fmat_t *t) {
+ uint_t i;
+#ifndef HAVE_MEMCPY_HACKS
+ uint_t j;
+#endif /* HAVE_MEMCPY_HACKS */
+ if (s->height != t->height) {
+ AUBIO_ERR("trying to copy %d rows to %d rows \n",
+ s->height, t->height);
+ return;
+ }
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d columns to %d columns\n",
+ s->length, t->length);
+ return;
+ }
+#ifdef HAVE_MEMCPY_HACKS
+ for (i=0; i< s->height; i++) {
+ memcpy(t->data[i], s->data[i], t->length * sizeof(smpl_t));
+ }
+#else /* HAVE_MEMCPY_HACKS */
+ for (i=0; i< t->height; i++) {
+ for (j=0; j< t->length; j++) {
+ t->data[i][j] = s->data[i][j];
+ }
+ }
+#endif /* HAVE_MEMCPY_HACKS */
+}
+
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output) {
+ uint_t k;
+#if 0
+ assert(s->height == output->length);
+ assert(s->length == scale->length);
+#endif
+#if !defined(HAVE_ACCELERATE) && !defined(HAVE_BLAS)
+ uint_t j;
+ fvec_zeros(output);
+ for (j = 0; j < s->length; j++) {
+ for (k = 0; k < s->height; k++) {
+ output->data[k] += scale->data[j]
+ * s->data[k][j];
+ }
+ }
+#elif defined(HAVE_ACCELERATE)
+#if 0
+ // seems slower and less precise (and dangerous?)
+ vDSP_mmul (s->data[0], 1, scale->data, 1, output->data, 1, s->height, 1, s->length);
+#else
+ for (k = 0; k < s->height; k++) {
+ aubio_vDSP_dotpr( scale->data, 1, s->data[k], 1, &(output->data[k]), s->length);
+ }
+#endif
+#elif defined(HAVE_BLAS)
+ for (k = 0; k < s->height; k++) {
+ output->data[k] = aubio_cblas_dot( s->length, scale->data, 1, s->data[k], 1);
+ }
+#endif
+}
diff --git a/aubio/src/fmat.h b/aubio/src/fmat.h
new file mode 100644
index 00000000..8e65d110
--- /dev/null
+++ b/aubio/src/fmat.h
@@ -0,0 +1,172 @@
+/*
+ Copyright (C) 2009-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FMAT_H
+#define AUBIO_FMAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Matrix of real valued data
+
+ This file specifies the fmat_t type, which is used in aubio to store arrays
+ of floating point values.
+
+ \example test-fmat.c
+
+*/
+
+/** Buffer for real data */
+typedef struct {
+ uint_t length; /**< length of matrix */
+ uint_t height; /**< height of matrix */
+ smpl_t **data; /**< data array of size [length] * [height] */
+} fmat_t;
+
+/** fmat_t buffer creation function
+
+ \param length the length of the matrix to create
+ \param height the height of the matrix to create
+
+*/
+fmat_t * new_fmat(uint_t height, uint_t length);
+
+/** fmat_t buffer deletion function
+
+ \param s buffer to delete as returned by new_fmat()
+
+*/
+void del_fmat(fmat_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param channel channel to read from
+ \param position sample position to read from
+
+*/
+smpl_t fmat_get_sample(const fmat_t *s, uint_t channel, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[channel][position]
+ \param channel channel to write to
+ \param position sample position to write to
+
+*/
+void fmat_set_sample(fmat_t *s, smpl_t data, uint_t channel, uint_t position);
+
+/** read channel vector from a buffer
+
+ \param s vector to read from
+ \param channel channel to read from
+ \param output ::fvec_t to output to
+
+*/
+void fmat_get_channel (const fmat_t *s, uint_t channel, fvec_t *output);
+
+/** get vector buffer from an fmat data
+
+ \param s vector to read from
+ \param channel channel to read from
+
+*/
+smpl_t * fmat_get_channel_data (const fmat_t *s, uint_t channel);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+smpl_t ** fmat_get_data(const fmat_t *s);
+
+/** print out fmat data
+
+ \param s vector to print out
+
+*/
+void fmat_print(const fmat_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void fmat_set(fmat_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void fmat_zeros(fmat_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void fmat_ones(fmat_t *s);
+
+/** revert order of vector elements
+
+ \param s vector to revert
+
+*/
+void fmat_rev(fmat_t *s);
+
+/** apply weight to vector
+
+ If the weight vector is longer than s, only the first elements are used. If
+ the weight vector is shorter than s, the last elements of s are not weighted.
+
+ \param s vector to weight
+ \param weight weighting coefficients
+
+*/
+void fmat_weight(fmat_t *s, const fmat_t *weight);
+
+/** make a copy of a matrix
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void fmat_copy(const fmat_t *s, fmat_t *t);
+
+/** compute the product of a matrix by a vector
+
+ \param s matrix to compute product with
+ \param scale vector to compute product with
+ \param output vector to store restults in
+
+*/
+void fmat_vecmul(const fmat_t *s, const fvec_t *scale, fvec_t *output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FMAT_H */
diff --git a/aubio/src/fvec.c b/aubio/src/fvec.c
new file mode 100644
index 00000000..6b5681f5
--- /dev/null
+++ b/aubio/src/fvec.c
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+
+fvec_t * new_fvec(uint_t length) {
+ fvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(fvec_t);
+ s->length = length;
+ s->data = AUBIO_ARRAY(smpl_t, s->length);
+ return s;
+}
+
+void del_fvec(fvec_t *s) {
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void fvec_set_sample(fvec_t *s, smpl_t data, uint_t position) {
+ s->data[position] = data;
+}
+
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position) {
+ return s->data[position];
+}
+
+smpl_t * fvec_get_data(const fvec_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void fvec_print(const fvec_t *s) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_SMPL_FMT " ", s->data[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void fvec_set_all (fvec_t *s, smpl_t val) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsSet(val, s->data, (int)s->length);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_vfill(&val, s->data, 1, s->length);
+#elif defined(HAVE_ATLAS)
+ aubio_catlas_set(s->length, val, s->data, 1);
+#else
+ uint_t j;
+ for ( j = 0; j< s->length; j++ )
+ {
+ s->data[j] = val;
+ }
+#endif
+}
+
+void fvec_zeros(fvec_t *s) {
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsZero(s->data, (int)s->length);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_vclr(s->data, 1, s->length);
+#elif defined(HAVE_MEMCPY_HACKS)
+ memset(s->data, 0, s->length * sizeof(smpl_t));
+#else
+ fvec_set_all(s, 0.);
+#endif
+}
+
+void fvec_ones(fvec_t *s) {
+ fvec_set_all (s, 1.);
+}
+
+void fvec_rev(fvec_t *s) {
+ uint_t j;
+ for (j=0; j< FLOOR((smpl_t)s->length/2); j++) {
+ ELEM_SWAP(s->data[j], s->data[s->length-1-j]);
+ }
+}
+
+void fvec_weight(fvec_t *s, const fvec_t *weight) {
+ uint_t length = MIN(s->length, weight->length);
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsMul(s->data, weight->data, s->data, (int)length);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_vmul( s->data, 1, weight->data, 1, s->data, 1, length );
+#else
+ uint_t j;
+ for (j = 0; j < length; j++) {
+ s->data[j] *= weight->data[j];
+ }
+#endif /* HAVE_ACCELERATE */
+}
+
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out) {
+ uint_t length = MIN(in->length, MIN(out->length, weight->length));
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsMul(in->data, weight->data, out->data, (int)length);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_vmul(in->data, 1, weight->data, 1, out->data, 1, length);
+#else
+ uint_t j;
+ for (j = 0; j < length; j++) {
+ out->data[j] = in->data[j] * weight->data[j];
+ }
+#endif
+}
+
+void fvec_copy(const fvec_t *s, fvec_t *t) {
+ if (s->length != t->length) {
+ AUBIO_ERR("trying to copy %d elements to %d elements \n",
+ s->length, t->length);
+ return;
+ }
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsCopy(s->data, t->data, (int)s->length);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_mmov(s->data, t->data, 1, s->length, 1, 1);
+#elif defined(HAVE_BLAS)
+ aubio_cblas_copy(s->length, s->data, 1, t->data, 1);
+#elif defined(HAVE_MEMCPY_HACKS)
+ memcpy(t->data, s->data, t->length * sizeof(smpl_t));
+#else
+ uint_t j;
+ for (j = 0; j < t->length; j++) {
+ t->data[j] = s->data[j];
+ }
+#endif
+}
diff --git a/aubio/src/fvec.h b/aubio/src/fvec.h
new file mode 100644
index 00000000..bd8c5a60
--- /dev/null
+++ b/aubio/src/fvec.h
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FVEC_H
+#define AUBIO_FVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of real-valued data
+
+ This file specifies the ::fvec_t buffer type, which is used throughout aubio
+ to store vector of real-valued ::smpl_t.
+
+ \example test-fvec.c
+
+*/
+
+/** Buffer for real data
+
+ Vector of real-valued data
+
+ ::fvec_t is is the structure used to store vector of real-valued data, ::smpl_t .
+
+ \code
+
+ uint_t buffer_size = 1024;
+
+ // create a vector of 512 values
+ fvec_t * input = new_fvec (buffer_size);
+
+ // set some values of the vector
+ input->data[23] = 2.;
+ // ..
+
+ // compute the mean of the vector
+ mean = fvec_mean(a_vector);
+
+ // destroy the vector
+ del_fvec(a_vector);
+
+ \endcode
+
+ See `examples/` and `tests/src` directories for more examples.
+
+ */
+typedef struct {
+ uint_t length; /**< length of buffer */
+ smpl_t *data; /**< data vector of length ::fvec_t.length */
+} fvec_t;
+
+/** fvec_t buffer creation function
+
+ \param length the length of the buffer to create
+
+*/
+fvec_t * new_fvec(uint_t length);
+
+/** fvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_fvec()
+
+*/
+void del_fvec(fvec_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+smpl_t fvec_get_sample(const fvec_t *s, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[position]
+ \param position sample position to write to
+
+*/
+void fvec_set_sample(fvec_t *s, smpl_t data, uint_t position);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+smpl_t * fvec_get_data(const fvec_t *s);
+
+/** print out fvec data
+
+ \param s vector to print out
+
+*/
+void fvec_print(const fvec_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void fvec_set_all (fvec_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void fvec_zeros(fvec_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void fvec_ones(fvec_t *s);
+
+/** revert order of vector elements
+
+ \param s vector to revert
+
+*/
+void fvec_rev(fvec_t *s);
+
+/** apply weight to vector
+
+ If the weight vector is longer than s, only the first elements are used. If
+ the weight vector is shorter than s, the last elements of s are not weighted.
+
+ \param s vector to weight
+ \param weight weighting coefficients
+
+*/
+void fvec_weight(fvec_t *s, const fvec_t *weight);
+
+/** make a copy of a vector
+
+ \param s source vector
+ \param t vector to copy to
+
+*/
+void fvec_copy(const fvec_t *s, fvec_t *t);
+
+/** make a copy of a vector, applying weights to each element
+
+ \param in input vector
+ \param weight weights vector
+ \param out output vector
+
+*/
+void fvec_weighted_copy(const fvec_t *in, const fvec_t *weight, fvec_t *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FVEC_H */
diff --git a/aubio/src/io/audio_unit.h b/aubio/src/io/audio_unit.h
new file mode 100644
index 00000000..46f86b1e
--- /dev/null
+++ b/aubio/src/io/audio_unit.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_AUDIO_UNIT_H
+#define AUBIO_AUDIO_UNIT_H
+
+/** \file
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_audio_unit_t aubio_audio_unit_t;
+
+aubio_audio_unit_t * new_aubio_audio_unit(uint_t samplerate, uint_t inchannels,
+ uint_t outchannels, uint_t blocksize);
+
+typedef uint_t (*aubio_device_callback_t) (void * closure, fmat_t *ibuf, fmat_t *obuf);
+
+uint_t aubio_audio_unit_set_callback(aubio_audio_unit_t *o,
+ aubio_device_callback_t callback, void *closure);
+
+sint_t aubio_audio_unit_set_verbose (aubio_audio_unit_t *o, uint_t verbose);
+sint_t aubio_audio_unit_set_preferred_latency (aubio_audio_unit_t *o, smpl_t
+ latency);
+sint_t aubio_audio_unit_set_prevent_feedback (aubio_audio_unit_t *o, uint_t
+ prevent_feedback);
+
+sint_t aubio_audio_unit_get_info (aubio_audio_unit_t *o);
+
+sint_t aubio_audio_unit_init (aubio_audio_unit_t *o);
+
+sint_t aubio_audio_unit_start (aubio_audio_unit_t *o);
+sint_t aubio_audio_unit_stop (aubio_audio_unit_t *o);
+
+uint_t del_aubio_audio_unit(aubio_audio_unit_t *o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_AUDIO_UNIT_H */
diff --git a/aubio/src/io/ioutils.h b/aubio/src/io/ioutils.h
new file mode 100644
index 00000000..f3cdf927
--- /dev/null
+++ b/aubio/src/io/ioutils.h
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_IOUTILS_H
+#define AUBIO_IOUTILS_H
+
+/** \file
+
+ Simple utility functions to validate input parameters.
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** validate samplerate
+
+ \param kind the object kind to report on
+ \param path the object properties to report on
+ \param samplerate the object properties to report on
+ \return 0 if ok, non-zero if validation failed
+
+ */
+uint_t aubio_io_validate_samplerate(const char_t *kind, const char_t *path,
+ uint_t samplerate);
+
+/** validate number of channels
+
+ \param kind the object kind to report on
+ \param path the object properties to report on
+ \param channels the object properties to report on
+ \return 0 if ok, non-zero if validation failed
+
+ */
+uint_t aubio_io_validate_channels(const char_t *kind, const char_t *path,
+ uint_t channels);
+
+/** validate length of source output
+
+ \param kind the object kind to report on
+ \param path the path to report on
+ \param hop_size number of frames to be read
+ \param read_data_length actual length of input
+
+ \return hop_size or the maximum number of frames that can be written
+*/
+uint_t
+aubio_source_validate_input_length(const char_t *kind, const char_t *path,
+ uint_t hop_size, uint_t read_data_length);
+
+/** validate height of source output
+
+ \param kind the object kind to report on
+ \param path the path to report on
+ \param source_channels maximum number of channels that can be written
+ \param read_data_height actual height of input
+
+ \return write_data_height or the maximum number of channels
+*/
+uint_t
+aubio_source_validate_input_channels(const char_t *kind, const char_t *path,
+ uint_t source_channels, uint_t read_data_height);
+
+/** pad end of source output vector with zeroes
+
+ \param read_data output vector to pad
+ \param source_read number of frames read
+
+*/
+void
+aubio_source_pad_output (fvec_t *read_data, uint_t source_read);
+
+/** pad end of source output matrix with zeroes
+
+ \param read_data output matrix to pad
+ \param source_channels number of channels in the source
+ \param source_read number of frames read
+
+*/
+void
+aubio_source_pad_multi_output (fmat_t *read_data, uint_t source_channels,
+ uint_t source_read);
+
+/** validate length of sink input
+
+ \param kind the object kind to report on
+ \param path the path to report on
+ \param max_size maximum number of frames that can be written
+ \param write_data_length actual length of input
+ \param write number of samples asked
+
+ \return write or the maximum number of frames that can be written
+*/
+uint_t
+aubio_sink_validate_input_length(const char_t *kind, const char_t *path,
+ uint_t max_size, uint_t write_data_length, uint_t write);
+
+/** validate height of sink input
+
+ \param kind the object kind to report on
+ \param path the path to report on
+ \param sink_channels maximum number of channels that can be written
+ \param write_data_height actual height of input matrix
+
+ \return write_data_height or the maximum number of channels
+*/
+uint_t
+aubio_sink_validate_input_channels(const char_t *kind, const char_t *path,
+ uint_t sink_channels, uint_t write_data_height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_IOUTILS_H */
diff --git a/aubio/src/io/sink.h b/aubio/src/io/sink.h
new file mode 100644
index 00000000..ee0f5cf8
--- /dev/null
+++ b/aubio/src/io/sink.h
@@ -0,0 +1,181 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SINK_H
+#define AUBIO_SINK_H
+
+/** \file
+
+ Media sink to write blocks of consecutive audio samples to file.
+
+ To read from file, use ::aubio_source_t.
+
+ Depending on how aubio was compiled, the following sinks will be available.
+
+ When creating a new sink using ::new_aubio_sink, the new function of each of
+ the compiled-in sinks will be attempted, in the following order, until one of
+ them gets successfully created. If all sinks returned NULL, ::new_aubio_sink
+ will return NULL.
+
+ \b \p sink_apple_audio : ExtAudioFileRef
+
+ This sink uses CoreAudio [Extended Audio File Services]
+ (https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+ to write 16-bits encoded WAV files.
+
+ \b \p sink_sndfile : libsndfile
+
+ This sink uses [libsndfile](http://www.mega-nerd.com/libsndfile/) to write
+ 16-bits encoded WAV files.
+
+ \b \p sink_wavwrite : native WAV write
+
+ A simple sink to write 16-bits PCM RIFF encoded WAV files.
+
+ \example io/test-sink.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** media sink object */
+typedef struct _aubio_sink_t aubio_sink_t;
+
+/**
+
+ create new ::aubio_sink_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_samplerate(aubio_sink_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_preset_channels(aubio_sink_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_get_samplerate(const aubio_sink_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink
+ \return number of channels
+
+*/
+uint_t aubio_sink_get_channels(const aubio_sink_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_do(aubio_sink_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_do_multi(aubio_sink_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink object, created with ::new_aubio_sink
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_close(aubio_sink_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink object, created with ::new_aubio_sink
+
+*/
+void del_aubio_sink(aubio_sink_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_H */
diff --git a/aubio/src/io/sink_apple_audio.h b/aubio/src/io/sink_apple_audio.h
new file mode 100644
index 00000000..1e228bcf
--- /dev/null
+++ b/aubio/src/io/sink_apple_audio.h
@@ -0,0 +1,186 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SINK_APPLE_AUDIO_H
+#define AUBIO_SINK_APPLE_AUDIO_H
+
+/** \file
+
+ Write to file using Apple AudioToolbox's
+ [ExtAudioFileRef](https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_apple_audio.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_apple_audio object */
+typedef struct _aubio_sink_apple_audio_t aubio_sink_apple_audio_t;
+
+/**
+
+ create new ::aubio_sink_apple_audio_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_apple_audio_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_apple_audio_preset_samplerate(aubio_sink_apple_audio_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_apple_audio_preset_channels(aubio_sink_apple_audio_t *s, uint_t channels);
+
+/**
+
+ preset sink format
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param fmt format of the file to create
+
+ \return 0 on success, 1 on error
+
+ Preset the format of the sink. Supported format strings:
+ - "wav": WAVE, 16 bit (default)
+ - "aiff": AIFF, 16 bit
+ - "m4a" or "mp4": Apple Audio Lossless Codec (ALAC)
+ - "aac": Audio Advanced Codec, lossy
+
+ Full list of supported encoding format is available in Table 1-2 of
+ `Multimedia Programming Guide
+ `_.
+
+ */
+uint_t aubio_sink_apple_audio_preset_format(aubio_sink_apple_audio_t *s,
+ const char_t *fmt);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_apple_audio
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_apple_audio
+ \return number of channels
+
+*/
+uint_t aubio_sink_apple_audio_get_channels(const aubio_sink_apple_audio_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_apple_audio object, created with ::new_aubio_sink_apple_audio
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_apple_audio_close(aubio_sink_apple_audio_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+
+*/
+void del_aubio_sink_apple_audio(aubio_sink_apple_audio_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_APPLE_AUDIO_H */
diff --git a/aubio/src/io/sink_sndfile.h b/aubio/src/io/sink_sndfile.h
new file mode 100644
index 00000000..d12ff55c
--- /dev/null
+++ b/aubio/src/io/sink_sndfile.h
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2012-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SINK_SNDFILE_H
+#define AUBIO_SINK_SNDFILE_H
+
+/** \file
+
+ Write to file using [libsndfile](http://www.mega-nerd.com/libsndfile/)
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_sndfile.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_sndfile object */
+typedef struct _aubio_sink_sndfile_t aubio_sink_sndfile_t;
+
+/**
+
+ create new ::aubio_sink_sndfile_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_sndfile_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_sndfile_preset_samplerate(aubio_sink_sndfile_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_sndfile_preset_channels(aubio_sink_sndfile_t *s, uint_t channels);
+
+/**
+
+ preset sink format
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param fmt format of the file to create
+
+ \return 0 on success, 1 on error
+
+ Preset the format of the sink. Supported format strings:
+ - "wav": 16 bit (default)
+ - "aiff": aiff, 16 bit
+ - "flac": flac, 16 bit
+ - "ogg": ogg vorbis stream
+
+ Alternatively, any sndfile format can be set by passing the corresponding
+ integer as a string:
+
+ \code{.c}
+ char_t fmt[10];
+ snprintf(fmt, sizeof(fmt), "%d", SF_FORMAT_FLAC | SF_FORMAT_PCM_24);
+ aubio_sink_sndfile_preset_format(s, fmt);
+ \endcode
+
+ The file should have been created using a samplerate of 0.
+
+ This function should be called before aubio_sink_sndfile_preset_samplerate()
+ and aubio_sink_sndfile_preset_channels().
+
+*/
+uint_t aubio_sink_sndfile_preset_format(aubio_sink_sndfile_t *s,
+ const char_t* fmt);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_sndfile
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_sndfile
+ \return number of channels
+
+*/
+uint_t aubio_sink_sndfile_get_channels(const aubio_sink_sndfile_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_sndfile_do(aubio_sink_sndfile_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_sndfile_do_multi(aubio_sink_sndfile_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_sndfile object, created with ::new_aubio_sink_sndfile
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_sndfile_close(aubio_sink_sndfile_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+
+*/
+void del_aubio_sink_sndfile(aubio_sink_sndfile_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_SNDFILE_H */
diff --git a/aubio/src/io/sink_wavwrite.h b/aubio/src/io/sink_wavwrite.h
new file mode 100644
index 00000000..bb479e43
--- /dev/null
+++ b/aubio/src/io/sink_wavwrite.h
@@ -0,0 +1,162 @@
+/*
+ Copyright (C) 2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SINK_WAVWRITE_H
+#define AUBIO_SINK_WAVWRITE_H
+
+/** \file
+
+ Write to file using native file writer.
+
+ Avoid including this file directly! Prefer using ::aubio_sink_t instead to
+ make your code portable.
+
+ To read from file, use ::aubio_source_t.
+
+ \example io/test-sink_wavwrite.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sink_wavwrite object */
+typedef struct _aubio_sink_wavwrite_t aubio_sink_wavwrite_t;
+
+/**
+
+ create new ::aubio_sink_wavwrite_t
+
+ \param uri the file path or uri to write to
+ \param samplerate sample rate to write the file at
+
+ \return newly created ::aubio_sink_wavwrite_t
+
+ Creates a new sink object.
+
+ If samplerate is set to 0, the creation of the file will be delayed until
+ both ::aubio_sink_preset_samplerate and ::aubio_sink_preset_channels have
+ been called.
+
+*/
+aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(const char_t * uri, uint_t samplerate);
+
+/**
+
+ preset sink samplerate
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param samplerate samplerate to preset the sink to, in Hz
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_wavwrite_preset_samplerate(aubio_sink_wavwrite_t *s, uint_t samplerate);
+
+/**
+
+ preset sink channels
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param channels number of channels to preset the sink to
+
+ \return 0 on success, 1 on error
+
+ Preset the samplerate of the sink. The file should have been created using a
+ samplerate of 0.
+
+ The file will be opened only when both samplerate and channels have been set.
+
+*/
+uint_t aubio_sink_wavwrite_preset_channels(aubio_sink_wavwrite_t *s, uint_t channels);
+
+/**
+
+ get samplerate of sink object
+
+ \param s sink object, created with ::new_aubio_sink_wavwrite
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_sink_wavwrite_get_samplerate(const aubio_sink_wavwrite_t *s);
+
+/**
+
+ get channels of sink object
+
+ \param s sink object, created with ::new_aubio_sink_wavwrite
+ \return number of channels
+
+*/
+uint_t aubio_sink_wavwrite_get_channels(const aubio_sink_wavwrite_t *s);
+
+/**
+
+ write monophonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param write_data ::fvec_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t * s, fvec_t * write_data, uint_t write);
+
+/**
+
+ write polyphonic vector of length hop_size to sink
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+ \param write_data ::fmat_t samples to write to sink
+ \param write number of frames to write
+
+*/
+void aubio_sink_wavwrite_do_multi(aubio_sink_wavwrite_t * s, fmat_t * write_data, uint_t write);
+
+/**
+
+ close sink
+
+ \param s sink_wavwrite object, create with ::new_aubio_sink_wavwrite
+
+ \return 0 on success, non-zero on failure
+
+*/
+uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s);
+
+/**
+
+ close sink and cleanup memory
+
+ \param s sink, created with ::new_aubio_sink_wavwrite
+
+*/
+void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SINK_WAVWRITE_H */
diff --git a/aubio/src/io/source.h b/aubio/src/io/source.h
new file mode 100644
index 00000000..ff9b8be9
--- /dev/null
+++ b/aubio/src/io/source.h
@@ -0,0 +1,183 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SOURCE_H
+#define AUBIO_SOURCE_H
+
+/** \file
+
+ Media source to read blocks of consecutive audio samples from file.
+
+ To write to file, use ::aubio_sink_t.
+
+ Depending on how aubio was compiled, the following sources will be available.
+
+ When creating a new source using ::new_aubio_source, the new function of each
+ of the compiled-in sources will be used, in the following order, until one of
+ them gets successfully created. If all sources returned NULL,
+ ::new_aubio_source will return NULL.
+
+ \b \p source_avcodec : libav
+
+ aubio can be optionally compiled with [libav](http://libav.org), which can
+ read from a very large number of audio and video formats, including over
+ different network protocols such as HTTP.
+
+ \b \p source_apple_audio : ExtAudioFileRef
+
+ On Mac and iOS platforms, aubio should be compiled with CoreAudio [Extended
+ Audio File Services]
+ (https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html).
+ This provides access to most common audio file formats, including compressed
+ ones.
+
+ \b \p source_sndfile : libsndfile
+
+ Also optional, aubio can be built against
+ [libsndfile](http://www.mega-nerd.com/libsndfile/), which can read [most
+ uncompressed formats](http://www.mega-nerd.com/libsndfile/#Features).
+
+ \b \p source_wavread : native WAV reader
+
+ A simple source to read from 16-bits PCM RIFF encoded WAV files.
+
+ \example io/test-source.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** media source object */
+typedef struct _aubio_source_t aubio_source_t;
+
+/**
+
+ create new ::aubio_source_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_get_samplerate.
+
+*/
+aubio_source_t * new_aubio_source(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source
+ \param read_to ::fmat_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_do_multi(aubio_source_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_get_samplerate(aubio_source_t * s);
+
+/**
+
+ get channels of source object
+
+ \param s source object, created with ::new_aubio_source
+ \return channels
+
+*/
+uint_t aubio_source_get_channels (aubio_source_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_seek (aubio_source_t * s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source
+ \return number of frames in file
+
+*/
+uint_t aubio_source_get_duration (aubio_source_t * s);
+
+/**
+
+ close source object
+
+ \param s source object, created with ::new_aubio_source
+
+ \return 0 if sucessful, non-zero on failure
+
+ */
+uint_t aubio_source_close (aubio_source_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source
+
+*/
+void del_aubio_source(aubio_source_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_H */
diff --git a/aubio/src/io/source_apple_audio.h b/aubio/src/io/source_apple_audio.h
new file mode 100644
index 00000000..0ad55694
--- /dev/null
+++ b/aubio/src/io/source_apple_audio.h
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SOURCE_APPLE_AUDIO_H
+#define AUBIO_SOURCE_APPLE_AUDIO_H
+
+/** \file
+
+ Read from file using CoreAudio Extended Audio File Services
+ [ExtAudioFileRef](https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/ExtendedAudioFileServicesReference/Reference/reference.html)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_apple_audio.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** apple audio media source object */
+typedef struct _aubio_source_apple_audio_t aubio_source_apple_audio_t;
+
+/**
+
+ create new ::aubio_source_apple_audio_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_apple_audio_get_samplerate.
+
+*/
+aubio_source_apple_audio_t * new_aubio_source_apple_audio(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_apple_audio_get_samplerate(const aubio_source_apple_audio_t * s);
+
+/**
+
+ get channels of source object
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return number of channels
+
+*/
+uint_t aubio_source_apple_audio_get_channels(const aubio_source_apple_audio_t * s);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+ \return number of frames in file
+
+*/
+uint_t aubio_source_apple_audio_get_duration(const aubio_source_apple_audio_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_apple_audio_close(aubio_source_apple_audio_t * s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_apple_audio
+
+*/
+void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_APPLE_AUDIO_H */
diff --git a/aubio/src/io/source_avcodec.h b/aubio/src/io/source_avcodec.h
new file mode 100644
index 00000000..81f657d6
--- /dev/null
+++ b/aubio/src/io/source_avcodec.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SOURCE_AVCODEC_H
+#define AUBIO_SOURCE_AVCODEC_H
+
+/** \file
+
+ Read from file using [libavcodec](http://libav.org/)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_avcodec.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** avcodec media source object */
+typedef struct _aubio_source_avcodec_t aubio_source_avcodec_t;
+
+/**
+
+ create new ::aubio_source_avcodec_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_avcodec_get_samplerate.
+
+*/
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param read_to ::fvec_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return number of channels
+
+*/
+uint_t aubio_source_avcodec_get_channels (const aubio_source_avcodec_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_avcodec
+ \return number of frames in file
+
+*/
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_avcodec
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_avcodec_close (aubio_source_avcodec_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_avcodec
+
+*/
+void del_aubio_source_avcodec(aubio_source_avcodec_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_AVCODEC_H */
diff --git a/aubio/src/io/source_sndfile.h b/aubio/src/io/source_sndfile.h
new file mode 100644
index 00000000..210a40d2
--- /dev/null
+++ b/aubio/src/io/source_sndfile.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2012-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SOURCE_SNDFILE_H
+#define AUBIO_SOURCE_SNDFILE_H
+
+/** \file
+
+ Read from file using [libsndfile](http://www.mega-nerd.com/libsndfile/)
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ \example io/test-source_sndfile.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sndfile media source object */
+typedef struct _aubio_source_sndfile_t aubio_source_sndfile_t;
+
+/**
+
+ create new ::aubio_source_sndfile_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_sndfile_get_samplerate.
+
+*/
+aubio_source_sndfile_t * new_aubio_source_sndfile(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param read_to ::fvec_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of channels
+
+*/
+uint_t aubio_source_sndfile_get_channels (aubio_source_sndfile_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of frames in file
+
+*/
+uint_t aubio_source_sndfile_get_duration (const aubio_source_sndfile_t *s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_sndfile
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_sndfile_close (aubio_source_sndfile_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_sndfile
+
+*/
+void del_aubio_source_sndfile(aubio_source_sndfile_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_SNDFILE_H */
diff --git a/aubio/src/io/source_wavread.h b/aubio/src/io/source_wavread.h
new file mode 100644
index 00000000..65f752f9
--- /dev/null
+++ b/aubio/src/io/source_wavread.h
@@ -0,0 +1,160 @@
+/*
+ Copyright (C) 2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SOURCE_WAVREAD_H
+#define AUBIO_SOURCE_WAVREAD_H
+
+/** \file
+
+ Read from file using custom wav reading routines.
+
+ Avoid including this file directly! Prefer using ::aubio_source_t instead to
+ make your code portable.
+
+ To write to file, use ::aubio_sink_t.
+
+ References:
+
+ - http://netghost.narod.ru/gff/graphics/summary/micriff.htm
+ - https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+
+ \example io/test-source_wavread.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** wavread media source object */
+typedef struct _aubio_source_wavread_t aubio_source_wavread_t;
+
+/**
+
+ create new ::aubio_source_wavread_t
+
+ \param uri the file path or uri to read from
+ \param samplerate sampling rate to view the fie at
+ \param hop_size the size of the blocks to read from
+
+ Creates a new source object. If `0` is passed as `samplerate`, the sample
+ rate of the original file is used.
+
+ The samplerate of newly created source can be obtained using
+ ::aubio_source_wavread_get_samplerate.
+
+*/
+aubio_source_wavread_t * new_aubio_source_wavread(const char_t * uri, uint_t samplerate, uint_t hop_size);
+
+/**
+
+ read monophonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param read_to ::fvec_t of data to read to
+ \param[out] read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_wavread_do(aubio_source_wavread_t * s, fvec_t * read_to, uint_t * read);
+
+/**
+
+ read polyphonic vector of length hop_size from source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param read_to ::fmat_t of data to read to
+ \param read upon returns, equals to number of frames actually read
+
+ Upon returns, `read` contains the number of frames actually read from the
+ source. `hop_size` if enough frames could be read, less otherwise.
+
+*/
+void aubio_source_wavread_do_multi(aubio_source_wavread_t * s, fmat_t * read_to, uint_t * read);
+
+/**
+
+ get samplerate of source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \return samplerate, in Hz
+
+*/
+uint_t aubio_source_wavread_get_samplerate(aubio_source_wavread_t * s);
+
+/**
+
+ get number of channels of source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \return number of channels
+
+*/
+uint_t aubio_source_wavread_get_channels (aubio_source_wavread_t * s);
+
+/**
+
+ seek source object
+
+ \param s source object, created with ::new_aubio_source_wavread
+ \param pos position to seek to, in frames
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_wavread_seek (aubio_source_wavread_t *s, uint_t pos);
+
+/**
+
+ get the duration of source object, in frames
+
+ \param s source object, created with ::new_aubio_source_sndfile
+ \return number of frames in file
+
+*/
+uint_t aubio_source_wavread_get_duration (const aubio_source_wavread_t *s);
+
+/**
+
+ close source
+
+ \param s source object, created with ::new_aubio_source_wavread
+
+ \return 0 if sucessful, non-zero on failure
+
+*/
+uint_t aubio_source_wavread_close (aubio_source_wavread_t *s);
+
+/**
+
+ close source and cleanup memory
+
+ \param s source object, created with ::new_aubio_source_wavread
+
+*/
+void del_aubio_source_wavread(aubio_source_wavread_t * s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SOURCE_WAVREAD_H */
diff --git a/aubio/src/lvec.c b/aubio/src/lvec.c
new file mode 100644
index 00000000..dd63bf42
--- /dev/null
+++ b/aubio/src/lvec.c
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "lvec.h"
+
+lvec_t * new_lvec(uint_t length) {
+ lvec_t * s;
+ if ((sint_t)length <= 0) {
+ return NULL;
+ }
+ s = AUBIO_NEW(lvec_t);
+ s->length = length;
+ s->data = AUBIO_ARRAY(lsmp_t, s->length);
+ return s;
+}
+
+void del_lvec(lvec_t *s) {
+ AUBIO_FREE(s->data);
+ AUBIO_FREE(s);
+}
+
+void lvec_set_sample(lvec_t *s, lsmp_t data, uint_t position) {
+ s->data[position] = data;
+}
+
+lsmp_t lvec_get_sample(lvec_t *s, uint_t position) {
+ return s->data[position];
+}
+
+lsmp_t * lvec_get_data(const lvec_t *s) {
+ return s->data;
+}
+
+/* helper functions */
+
+void lvec_print(const lvec_t *s) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ AUBIO_MSG(AUBIO_LSMP_FMT " ", s->data[j]);
+ }
+ AUBIO_MSG("\n");
+}
+
+void lvec_set_all (lvec_t *s, smpl_t val) {
+ uint_t j;
+ for (j=0; j< s->length; j++) {
+ s->data[j] = val;
+ }
+}
+
+void lvec_zeros(lvec_t *s) {
+#if HAVE_MEMCPY_HACKS
+ memset(s->data, 0, s->length * sizeof(lsmp_t));
+#else
+ lvec_set_all (s, 0.);
+#endif
+}
+
+void lvec_ones(lvec_t *s) {
+ lvec_set_all (s, 1.);
+}
+
diff --git a/aubio/src/lvec.h b/aubio/src/lvec.h
new file mode 100644
index 00000000..402ba0ff
--- /dev/null
+++ b/aubio/src/lvec.h
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_LVEC_H
+#define AUBIO_LVEC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Vector of real-valued data in double precision
+
+ This file specifies the ::lvec_t buffer type, which is used in some places in
+ aubio to store a vector of ::lsmp_t.
+
+ Note: the lvec_t data type is required in some algorithms such as IIR filters
+ (see temporal/filter.h).
+
+ \example test-lvec.c
+
+*/
+
+/** Buffer for real data in double precision */
+typedef struct {
+ uint_t length; /**< length of buffer */
+ lsmp_t *data; /**< data array of size [length] */
+} lvec_t;
+
+/** lvec_t buffer creation function
+
+ \param length the length of the buffer to create
+
+*/
+lvec_t * new_lvec(uint_t length);
+/** lvec_t buffer deletion function
+
+ \param s buffer to delete as returned by new_lvec()
+
+*/
+void del_lvec(lvec_t *s);
+
+/** read sample value in a buffer
+
+ \param s vector to read from
+ \param position sample position to read from
+
+*/
+lsmp_t lvec_get_sample(lvec_t *s, uint_t position);
+
+/** write sample value in a buffer
+
+ \param s vector to write to
+ \param data value to write in s->data[position]
+ \param position sample position to write to
+
+*/
+void lvec_set_sample(lvec_t *s, lsmp_t data, uint_t position);
+
+/** read data from a buffer
+
+ \param s vector to read from
+
+*/
+lsmp_t * lvec_get_data(const lvec_t *s);
+
+/** print out lvec data
+
+ \param s vector to print out
+
+*/
+void lvec_print(const lvec_t *s);
+
+/** set all elements to a given value
+
+ \param s vector to modify
+ \param val value to set elements to
+
+*/
+void lvec_set_all(lvec_t *s, smpl_t val);
+
+/** set all elements to zero
+
+ \param s vector to modify
+
+*/
+void lvec_zeros(lvec_t *s);
+
+/** set all elements to ones
+
+ \param s vector to modify
+
+*/
+void lvec_ones(lvec_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_LVEC_H */
diff --git a/aubio/src/mathutils.c b/aubio/src/mathutils.c
new file mode 100644
index 00000000..35755fe4
--- /dev/null
+++ b/aubio/src/mathutils.c
@@ -0,0 +1,681 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/* see in mathutils.h for doc */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "musicutils.h"
+
+/** Window types */
+typedef enum
+{
+ aubio_win_ones,
+ aubio_win_rectangle,
+ aubio_win_hamming,
+ aubio_win_hanning,
+ aubio_win_hanningz,
+ aubio_win_blackman,
+ aubio_win_blackman_harris,
+ aubio_win_gaussian,
+ aubio_win_welch,
+ aubio_win_parzen,
+ aubio_win_default = aubio_win_hanningz,
+} aubio_window_type;
+
+fvec_t *
+new_aubio_window (char_t * window_type, uint_t length)
+{
+ fvec_t * win = new_fvec (length);
+ uint_t err;
+ if (win == NULL) {
+ return NULL;
+ }
+ err = fvec_set_window (win, window_type);
+ if (err != 0) {
+ del_fvec(win);
+ return NULL;
+ }
+ return win;
+}
+
+uint_t fvec_set_window (fvec_t *win, char_t *window_type) {
+ smpl_t * w = win->data;
+ uint_t i, size = win->length;
+ aubio_window_type wintype;
+ if (window_type == NULL) {
+ AUBIO_ERR ("window type can not be null.\n");
+ return 1;
+ } else if (strcmp (window_type, "ones") == 0)
+ wintype = aubio_win_ones;
+ else if (strcmp (window_type, "rectangle") == 0)
+ wintype = aubio_win_rectangle;
+ else if (strcmp (window_type, "hamming") == 0)
+ wintype = aubio_win_hamming;
+ else if (strcmp (window_type, "hanning") == 0)
+ wintype = aubio_win_hanning;
+ else if (strcmp (window_type, "hanningz") == 0)
+ wintype = aubio_win_hanningz;
+ else if (strcmp (window_type, "blackman") == 0)
+ wintype = aubio_win_blackman;
+ else if (strcmp (window_type, "blackman_harris") == 0)
+ wintype = aubio_win_blackman_harris;
+ else if (strcmp (window_type, "gaussian") == 0)
+ wintype = aubio_win_gaussian;
+ else if (strcmp (window_type, "welch") == 0)
+ wintype = aubio_win_welch;
+ else if (strcmp (window_type, "parzen") == 0)
+ wintype = aubio_win_parzen;
+ else if (strcmp (window_type, "default") == 0)
+ wintype = aubio_win_default;
+ else {
+ AUBIO_ERR ("unknown window type `%s`.\n", window_type);
+ return 1;
+ }
+ switch(wintype) {
+ case aubio_win_ones:
+ fvec_ones(win);
+ break;
+ case aubio_win_rectangle:
+ fvec_set_all(win, .5);
+ break;
+ case aubio_win_hamming:
+ for (i=0;idata, (int)s->length, &tmp);
+ return tmp;
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_meanv(s->data, 1, &tmp, s->length);
+ return tmp;
+#else
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->data[j];
+ }
+ return tmp / (smpl_t)(s->length);
+#endif
+}
+
+smpl_t
+fvec_sum (fvec_t * s)
+{
+ smpl_t tmp = 0.0;
+#if defined(HAVE_INTEL_IPP)
+ aubio_ippsSum(s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+ aubio_vDSP_sve(s->data, 1, &tmp, s->length);
+#else
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->data[j];
+ }
+#endif
+ return tmp;
+}
+
+smpl_t
+fvec_max (fvec_t * s)
+{
+#if defined(HAVE_INTEL_IPP)
+ smpl_t tmp = 0.;
+ aubio_ippsMax( s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+ smpl_t tmp = 0.;
+ aubio_vDSP_maxv( s->data, 1, &tmp, s->length );
+#else
+ uint_t j;
+ smpl_t tmp = s->data[0];
+ for (j = 1; j < s->length; j++) {
+ tmp = (tmp > s->data[j]) ? tmp : s->data[j];
+ }
+#endif
+ return tmp;
+}
+
+smpl_t
+fvec_min (fvec_t * s)
+{
+#if defined(HAVE_INTEL_IPP)
+ smpl_t tmp = 0.;
+ aubio_ippsMin(s->data, (int)s->length, &tmp);
+#elif defined(HAVE_ACCELERATE)
+ smpl_t tmp = 0.;
+ aubio_vDSP_minv(s->data, 1, &tmp, s->length);
+#else
+ uint_t j;
+ smpl_t tmp = s->data[0];
+ for (j = 1; j < s->length; j++) {
+ tmp = (tmp < s->data[j]) ? tmp : s->data[j];
+ }
+#endif
+ return tmp;
+}
+
+uint_t
+fvec_min_elem (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j, pos = 0.;
+ smpl_t tmp = s->data[0];
+ for (j = 0; j < s->length; j++) {
+ pos = (tmp < s->data[j]) ? pos : j;
+ tmp = (tmp < s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ vDSP_Length pos = 0;
+ aubio_vDSP_minvi(s->data, 1, &tmp, &pos, s->length);
+#endif
+ return (uint_t)pos;
+}
+
+uint_t
+fvec_max_elem (fvec_t * s)
+{
+#ifndef HAVE_ACCELERATE
+ uint_t j, pos = 0;
+ smpl_t tmp = 0.0;
+ for (j = 0; j < s->length; j++) {
+ pos = (tmp > s->data[j]) ? pos : j;
+ tmp = (tmp > s->data[j]) ? tmp : s->data[j];
+ }
+#else
+ smpl_t tmp = 0.;
+ vDSP_Length pos = 0;
+ aubio_vDSP_maxvi(s->data, 1, &tmp, &pos, s->length);
+#endif
+ return (uint_t)pos;
+}
+
+void
+fvec_shift (fvec_t * s)
+{
+ uint_t half = s->length / 2, start = half, j;
+ // if length is odd, middle element is moved to the end
+ if (2 * half < s->length) start ++;
+#ifndef HAVE_BLAS
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j], s->data[j + start]);
+ }
+#else
+ aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+ if (start != half) {
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j + start - 1], s->data[j + start]);
+ }
+ }
+}
+
+void
+fvec_ishift (fvec_t * s)
+{
+ uint_t half = s->length / 2, start = half, j;
+ // if length is odd, middle element is moved to the beginning
+ if (2 * half < s->length) start ++;
+#ifndef HAVE_BLAS
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[j], s->data[j + start]);
+ }
+#else
+ aubio_cblas_swap(half, s->data, 1, s->data + start, 1);
+#endif
+ if (start != half) {
+ for (j = 0; j < half; j++) {
+ ELEM_SWAP (s->data[half], s->data[j]);
+ }
+ }
+}
+
+void fvec_push(fvec_t *in, smpl_t new_elem) {
+ uint_t i;
+ for (i = 0; i < in->length - 1; i++) {
+ in->data[i] = in->data[i + 1];
+ }
+ in->data[in->length - 1] = new_elem;
+}
+
+void fvec_clamp(fvec_t *in, smpl_t absmax) {
+ uint_t i;
+ for (i = 0; i < in->length; i++) {
+ if (in->data[i] > 0 && in->data[i] > ABS(absmax)) {
+ in->data[i] = absmax;
+ } else if (in->data[i] < 0 && in->data[i] < -ABS(absmax)) {
+ in->data[i] = -absmax;
+ }
+ }
+}
+
+smpl_t
+aubio_level_lin (const fvec_t * f)
+{
+ smpl_t energy = 0.;
+#ifndef HAVE_BLAS
+ uint_t j;
+ for (j = 0; j < f->length; j++) {
+ energy += SQR (f->data[j]);
+ }
+#else
+ energy = aubio_cblas_dot(f->length, f->data, 1, f->data, 1);
+#endif
+ return energy / f->length;
+}
+
+smpl_t
+fvec_local_hfc (fvec_t * v)
+{
+ smpl_t hfc = 0.;
+ uint_t j;
+ for (j = 0; j < v->length; j++) {
+ hfc += (j + 1) * v->data[j];
+ }
+ return hfc;
+}
+
+void
+fvec_min_removal (fvec_t * v)
+{
+ smpl_t v_min = fvec_min (v);
+ fvec_add (v, - v_min );
+}
+
+smpl_t
+fvec_alpha_norm (fvec_t * o, smpl_t alpha)
+{
+ uint_t j;
+ smpl_t tmp = 0.;
+ for (j = 0; j < o->length; j++) {
+ tmp += POW (ABS (o->data[j]), alpha);
+ }
+ return POW (tmp / o->length, 1. / alpha);
+}
+
+void
+fvec_alpha_normalise (fvec_t * o, smpl_t alpha)
+{
+ uint_t j;
+ smpl_t norm = fvec_alpha_norm (o, alpha);
+ for (j = 0; j < o->length; j++) {
+ o->data[j] /= norm;
+ }
+}
+
+void
+fvec_add (fvec_t * o, smpl_t val)
+{
+ uint_t j;
+ for (j = 0; j < o->length; j++) {
+ o->data[j] += val;
+ }
+}
+
+void
+fvec_mul (fvec_t *o, smpl_t val)
+{
+ uint_t j;
+ for (j = 0; j < o->length; j++) {
+ o->data[j] *= val;
+ }
+}
+
+void fvec_adapt_thres(fvec_t * vec, fvec_t * tmp,
+ uint_t post, uint_t pre) {
+ uint_t length = vec->length, j;
+ for (j=0;jdata[j] -= fvec_moving_thres(vec, tmp, post, pre, j);
+ }
+}
+
+smpl_t
+fvec_moving_thres (fvec_t * vec, fvec_t * tmpvec,
+ uint_t post, uint_t pre, uint_t pos)
+{
+ uint_t k;
+ smpl_t *medar = (smpl_t *) tmpvec->data;
+ uint_t win_length = post + pre + 1;
+ uint_t length = vec->length;
+ /* post part of the buffer does not exist */
+ if (pos < post + 1) {
+ for (k = 0; k < post + 1 - pos; k++)
+ medar[k] = 0.; /* 0-padding at the beginning */
+ for (k = post + 1 - pos; k < win_length; k++)
+ medar[k] = vec->data[k + pos - post];
+ /* the buffer is fully defined */
+ } else if (pos + pre < length) {
+ for (k = 0; k < win_length; k++)
+ medar[k] = vec->data[k + pos - post];
+ /* pre part of the buffer does not exist */
+ } else {
+ for (k = 0; k < length - pos + post; k++)
+ medar[k] = vec->data[k + pos - post];
+ for (k = length - pos + post; k < win_length; k++)
+ medar[k] = 0.; /* 0-padding at the end */
+ }
+ return fvec_median (tmpvec);
+}
+
+smpl_t fvec_median (fvec_t * input) {
+ uint_t n = input->length;
+ smpl_t * arr = (smpl_t *) input->data;
+ uint_t low, high ;
+ uint_t median;
+ uint_t middle, ll, hh;
+
+ low = 0 ; high = n-1 ; median = (low + high) / 2;
+ for (;;) {
+ if (high <= low) /* One element only */
+ return arr[median] ;
+
+ if (high == low + 1) { /* Two elements only */
+ if (arr[low] > arr[high])
+ ELEM_SWAP(arr[low], arr[high]) ;
+ return arr[median] ;
+ }
+
+ /* Find median of low, middle and high items; swap into position low */
+ middle = (low + high) / 2;
+ if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]);
+ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]);
+ if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ;
+
+ /* Swap low item (now in position middle) into position (low+1) */
+ ELEM_SWAP(arr[middle], arr[low+1]) ;
+
+ /* Nibble from each end towards middle, swapping items when stuck */
+ ll = low + 1;
+ hh = high;
+ for (;;) {
+ do ll++; while (arr[low] > arr[ll]) ;
+ do hh--; while (arr[hh] > arr[low]) ;
+
+ if (hh < ll)
+ break;
+
+ ELEM_SWAP(arr[ll], arr[hh]) ;
+ }
+
+ /* Swap middle item (in position low) back into correct position */
+ ELEM_SWAP(arr[low], arr[hh]) ;
+
+ /* Re-set active partition */
+ if (hh <= median)
+ low = ll;
+ if (hh >= median)
+ high = hh - 1;
+ }
+}
+
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t pos) {
+ smpl_t s0, s1, s2; uint_t x0, x2;
+ smpl_t half = .5, two = 2.;
+ if (pos == 0 || pos == x->length - 1) return pos;
+ x0 = (pos < 1) ? pos : pos - 1;
+ x2 = (pos + 1 < x->length) ? pos + 1 : pos;
+ if (x0 == pos) return (x->data[pos] <= x->data[x2]) ? pos : x2;
+ if (x2 == pos) return (x->data[pos] <= x->data[x0]) ? pos : x0;
+ s0 = x->data[x0];
+ s1 = x->data[pos];
+ s2 = x->data[x2];
+ return pos + half * (s0 - s2 ) / (s0 - two * s1 + s2);
+}
+
+smpl_t fvec_quadratic_peak_mag (fvec_t *x, smpl_t pos) {
+ smpl_t x0, x1, x2;
+ uint_t index = (uint_t)(pos - .5) + 1;
+ if (pos >= x->length || pos < 0.) return 0.;
+ if ((smpl_t)index == pos) return x->data[index];
+ x0 = x->data[index - 1];
+ x1 = x->data[index];
+ x2 = x->data[index + 1];
+ return x1 - .25 * (x0 - x2) * (pos - index);
+}
+
+uint_t fvec_peakpick(const fvec_t * onset, uint_t pos) {
+ uint_t tmp=0;
+ tmp = (onset->data[pos] > onset->data[pos-1]
+ && onset->data[pos] > onset->data[pos+1]
+ && onset->data[pos] > 0.);
+ return tmp;
+}
+
+smpl_t
+aubio_quadfrac (smpl_t s0, smpl_t s1, smpl_t s2, smpl_t pf)
+{
+ smpl_t tmp =
+ s0 + (pf / 2.) * (pf * (s0 - 2. * s1 + s2) - 3. * s0 + 4. * s1 - s2);
+ return tmp;
+}
+
+smpl_t
+aubio_freqtomidi (smpl_t freq)
+{
+ smpl_t midi;
+ if (freq < 2. || freq > 100000.) return 0.; // avoid nans and infs
+ /* log(freq/A-2)/log(2) */
+ midi = freq / 6.875;
+ midi = LOG (midi) / 0.6931471805599453;
+ midi *= 12;
+ midi -= 3;
+ return midi;
+}
+
+smpl_t
+aubio_miditofreq (smpl_t midi)
+{
+ smpl_t freq;
+ if (midi > 140.) return 0.; // avoid infs
+ freq = (midi + 3.) / 12.;
+ freq = EXP (freq * 0.6931471805599453);
+ freq *= 6.875;
+ return freq;
+}
+
+smpl_t
+aubio_bintofreq (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t freq = samplerate / fftsize;
+ return freq * MAX(bin, 0);
+}
+
+smpl_t
+aubio_bintomidi (smpl_t bin, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t midi = aubio_bintofreq (bin, samplerate, fftsize);
+ return aubio_freqtomidi (midi);
+}
+
+smpl_t
+aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t bin = fftsize / samplerate;
+ return MAX(freq, 0) * bin;
+}
+
+smpl_t
+aubio_miditobin (smpl_t midi, smpl_t samplerate, smpl_t fftsize)
+{
+ smpl_t freq = aubio_miditofreq (midi);
+ return aubio_freqtobin (freq, samplerate, fftsize);
+}
+
+uint_t
+aubio_is_power_of_two (uint_t a)
+{
+ if ((a & (a - 1)) == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+uint_t
+aubio_next_power_of_two (uint_t a)
+{
+ uint_t i = 1;
+ while (i < a) i <<= 1;
+ return i;
+}
+
+uint_t
+aubio_power_of_two_order (uint_t a)
+{
+ int order = 0;
+ int temp = aubio_next_power_of_two(a);
+ while (temp >>= 1) {
+ ++order;
+ }
+ return order;
+}
+
+smpl_t
+aubio_db_spl (const fvec_t * o)
+{
+ return 10. * LOG10 (aubio_level_lin (o));
+}
+
+uint_t
+aubio_silence_detection (const fvec_t * o, smpl_t threshold)
+{
+ return (aubio_db_spl (o) < threshold);
+}
+
+smpl_t
+aubio_level_detection (const fvec_t * o, smpl_t threshold)
+{
+ smpl_t db_spl = aubio_db_spl (o);
+ if (db_spl < threshold) {
+ return 1.;
+ } else {
+ return db_spl;
+ }
+}
+
+smpl_t
+aubio_zero_crossing_rate (fvec_t * input)
+{
+ uint_t j;
+ uint_t zcr = 0;
+ for (j = 1; j < input->length; j++) {
+ // previous was strictly negative
+ if (input->data[j - 1] < 0.) {
+ // current is positive or null
+ if (input->data[j] >= 0.) {
+ zcr += 1;
+ }
+ // previous was positive or null
+ } else {
+ // current is strictly negative
+ if (input->data[j] < 0.) {
+ zcr += 1;
+ }
+ }
+ }
+ return zcr / (smpl_t) input->length;
+}
+
+void
+aubio_autocorr (const fvec_t * input, fvec_t * output)
+{
+ uint_t i, j, length = input->length;
+ smpl_t *data, *acf;
+ smpl_t tmp = 0;
+ data = input->data;
+ acf = output->data;
+ for (i = 0; i < length; i++) {
+ tmp = 0.;
+ for (j = i; j < length; j++) {
+ tmp += data[j - i] * data[j];
+ }
+ acf[i] = tmp / (smpl_t) (length - i);
+ }
+}
+
+void
+aubio_cleanup (void)
+{
+#ifdef HAVE_FFTW3F
+ fftwf_cleanup ();
+#else
+#ifdef HAVE_FFTW3
+ fftw_cleanup ();
+#endif
+#endif
+}
diff --git a/aubio/src/mathutils.h b/aubio/src/mathutils.h
new file mode 100644
index 00000000..4336d7ec
--- /dev/null
+++ b/aubio/src/mathutils.h
@@ -0,0 +1,338 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Various math functions
+
+ \example test-mathutils.c
+ \example test-mathutils-window.c
+
+ */
+
+#ifndef AUBIO_MATHUTILS_H
+#define AUBIO_MATHUTILS_H
+
+#include "fvec.h"
+#include "musicutils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** compute the mean of a vector
+
+ \param s vector to compute mean from
+ \return the mean of `v`
+
+*/
+smpl_t fvec_mean (fvec_t * s);
+
+/** find the max of a vector
+
+ \param s vector to get the max from
+
+ \return the value of the minimum of v
+
+*/
+smpl_t fvec_max (fvec_t * s);
+
+/** find the min of a vector
+
+ \param s vector to get the min from
+
+ \return the value of the maximum of v
+
+*/
+smpl_t fvec_min (fvec_t * s);
+
+/** find the index of the min of a vector
+
+ \param s vector to get the index from
+
+ \return the index of the minimum element of v
+
+*/
+uint_t fvec_min_elem (fvec_t * s);
+
+/** find the index of the max of a vector
+
+ \param s vector to get the index from
+
+ \return the index of the maximum element of v
+
+*/
+uint_t fvec_max_elem (fvec_t * s);
+
+/** swap the left and right halves of a vector
+
+ This function swaps the left part of the signal with the right part of the
+signal. Therefore
+
+ \f$ a[0], a[1], ..., a[\frac{N}{2}], a[\frac{N}{2}+1], ..., a[N-1], a[N] \f$
+
+ becomes
+
+ \f$ a[\frac{N}{2}+1], ..., a[N-1], a[N], a[0], a[1], ..., a[\frac{N}{2}] \f$
+
+ This operation, known as 'fftshift' in the Matlab Signal Processing Toolbox,
+can be used before computing the FFT to simplify the phase relationship of the
+resulting spectrum. See Amalia de Götzen's paper referred to above.
+
+*/
+void fvec_shift (fvec_t * v);
+
+/** swap the left and right halves of a vector
+
+ This function swaps the left part of the signal with the right part of the
+signal. Therefore
+
+ \f$ a[0], a[1], ..., a[\frac{N}{2}], a[\frac{N}{2}+1], ..., a[N-1], a[N] \f$
+
+ becomes
+
+ \f$ a[\frac{N}{2}+1], ..., a[N-1], a[N], a[0], a[1], ..., a[\frac{N}{2}] \f$
+
+ This operation, known as 'ifftshift' in the Matlab Signal Processing Toolbox,
+can be used after computing the inverse FFT to simplify the phase relationship
+of the resulting spectrum. See Amalia de Götzen's paper referred to above.
+
+*/
+void fvec_ishift (fvec_t * v);
+
+/** push a new element to the end of a vector, erasing the first element and
+ * sliding all others
+
+ \param in vector to push to
+ \param new_elem new_element to add at the end of the vector
+
+ In numpy words, this is equivalent to: in = np.concatenate([in, [new_elem]])[1:]
+
+*/
+void fvec_push(fvec_t *in, smpl_t new_elem);
+
+/** compute the sum of all elements of a vector
+
+ \param v vector to compute the sum of
+
+ \return the sum of v
+
+*/
+smpl_t fvec_sum (fvec_t * v);
+
+/** compute the High Frequency Content of a vector
+
+ The High Frequency Content is defined as \f$ \sum_0^{N-1} (k+1) v[k] \f$.
+
+ \param v vector to get the energy from
+
+ \return the HFC of v
+
+*/
+smpl_t fvec_local_hfc (fvec_t * v);
+
+/** computes the p-norm of a vector
+
+ Computes the p-norm of a vector for \f$ p = \alpha \f$
+
+ \f$ L^p = ||x||_p = (|x_1|^p + |x_2|^p + ... + |x_n|^p ) ^ \frac{1}{p} \f$
+
+ If p = 1, the result is the Manhattan distance.
+
+ If p = 2, the result is the Euclidean distance.
+
+ As p tends towards large values, \f$ L^p \f$ tends towards the maximum of the
+input vector.
+
+ References:
+
+ - \f$L^p\f$ space on
+ Wikipedia
+
+ \param v vector to compute norm from
+ \param p order of the computed norm
+
+ \return the p-norm of v
+
+*/
+smpl_t fvec_alpha_norm (fvec_t * v, smpl_t p);
+
+/** alpha normalisation
+
+ This function divides all elements of a vector by the p-norm as computed by
+fvec_alpha_norm().
+
+ \param v vector to compute norm from
+ \param p order of the computed norm
+
+*/
+void fvec_alpha_normalise (fvec_t * v, smpl_t p);
+
+/** add a constant to each elements of a vector
+
+ \param v vector to add constant to
+ \param c constant to add to v
+
+*/
+void fvec_add (fvec_t * v, smpl_t c);
+
+/** multiply each elements of a vector by a scalar
+
+ \param v vector to add constant to
+ \param s constant to scale v with
+
+*/
+void fvec_mul (fvec_t * v, smpl_t s);
+
+/** remove the minimum value of the vector to each elements
+
+ \param v vector to remove minimum from
+
+*/
+void fvec_min_removal (fvec_t * v);
+
+/** compute moving median threshold of a vector
+
+ This function computes the moving median threshold value of at the given
+position of a vector, taking the median among post elements before and up to
+pre elements after pos.
+
+ \param v input vector
+ \param tmp temporary vector of length post+1+pre
+ \param post length of causal part to take before pos
+ \param pre length of anti-causal part to take after pos
+ \param pos index to compute threshold for
+
+ \return moving median threshold value
+
+*/
+smpl_t fvec_moving_thres (fvec_t * v, fvec_t * tmp, uint_t post, uint_t pre,
+ uint_t pos);
+
+/** apply adaptive threshold to a vector
+
+ For each points at position p of an input vector, this function remove the
+moving median threshold computed at p.
+
+ \param v input vector
+ \param tmp temporary vector of length post+1+pre
+ \param post length of causal part to take before pos
+ \param pre length of anti-causal part to take after pos
+
+*/
+void fvec_adapt_thres (fvec_t * v, fvec_t * tmp, uint_t post, uint_t pre);
+
+/** returns the median of a vector
+
+ The QuickSelect routine is based on the algorithm described in "Numerical
+recipes in C", Second Edition, Cambridge University Press, 1992, Section 8.5,
+ISBN 0-521-43108-5
+
+ This implementation of the QuickSelect routine is based on Nicolas
+Devillard's implementation, available at http://ndevilla.free.fr/median/median/
+and in the Public Domain.
+
+ \param v vector to get median from
+
+ \return the median of v
+
+*/
+smpl_t fvec_median (fvec_t * v);
+
+/** finds exact peak index by quadratic interpolation
+
+ See [Quadratic Interpolation of Spectral
+ Peaks](https://ccrma.stanford.edu/~jos/sasp/Quadratic_Peak_Interpolation.html),
+ by Julius O. Smith III
+
+ \f$ p_{frac} = \frac{1}{2} \frac {x[p-1] - x[p+1]} {x[p-1] - 2 x[p] + x[p+1]} \in [ -.5, .5] \f$
+
+ \param x vector to get the interpolated peak position from
+ \param p index of the peak in vector `x`
+ \return \f$ p + p_{frac} \f$ exact peak position of interpolated maximum or minimum
+
+*/
+smpl_t fvec_quadratic_peak_pos (const fvec_t * x, uint_t p);
+
+/** finds magnitude of peak by quadratic interpolation
+
+ See [Quadratic Interpolation of Spectral
+ Peaks](https://ccrma.stanford.edu/~jos/sasp/Quadratic_Peak_Interpolation.html),
+ by Julius O. Smith III
+
+ \param x vector to get the magnitude of the interpolated peak position from
+ \param p index of the peak in vector `x`
+ \return magnitude of interpolated peak
+
+*/
+smpl_t fvec_quadratic_peak_mag (fvec_t * x, smpl_t p);
+
+/** Quadratic interpolation using Lagrange polynomial.
+
+ Inspired from ``Comparison of interpolation algorithms in real-time sound
+processing'', Vladimir Arnost,
+
+ \param s0,s1,s2 are 3 consecutive samples of a curve
+ \param pf is the floating point index [0;2]
+
+ \return \f$ s0 + (pf/2.)*((pf-3.)*s0-2.*(pf-2.)*s1+(pf-1.)*s2); \f$
+
+*/
+smpl_t aubio_quadfrac (smpl_t s0, smpl_t s1, smpl_t s2, smpl_t pf);
+
+/** return 1 if v[p] is a peak and positive, 0 otherwise
+
+ This function returns 1 if a peak is found at index p in the vector v. The
+peak is defined as follows:
+
+ - v[p] is positive
+ - v[p-1] < v[p]
+ - v[p] > v[p+1]
+
+ \param v input vector
+ \param p position of supposed for peak
+
+ \return 1 if a peak is found, 0 otherwise
+
+*/
+uint_t fvec_peakpick (const fvec_t * v, uint_t p);
+
+/** return 1 if a is a power of 2, 0 otherwise */
+uint_t aubio_is_power_of_two(uint_t a);
+
+/** return the next power of power of 2 greater than a */
+uint_t aubio_next_power_of_two(uint_t a);
+
+/** return the log2 factor of the given power of 2 value a */
+uint_t aubio_power_of_two_order(uint_t a);
+
+/** compute normalised autocorrelation function
+
+ \param input vector to compute autocorrelation from
+ \param output vector to store autocorrelation function to
+
+*/
+void aubio_autocorr (const fvec_t * input, fvec_t * output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MATHUTILS_H */
diff --git a/aubio/src/musicutils.c b/aubio/src/musicutils.c
new file mode 100644
index 00000000..14ef849e
--- /dev/null
+++ b/aubio/src/musicutils.c
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2018 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "musicutils.h"
+
+smpl_t
+aubio_hztomel (smpl_t freq)
+{
+ const smpl_t lin_space = 3./200.;
+ const smpl_t split_hz = 1000.;
+ const smpl_t split_mel = split_hz * lin_space;
+ const smpl_t log_space = 27./LOG(6400/1000.);
+ if (freq < 0) {
+ AUBIO_WRN("hztomel: input frequency should be >= 0\n");
+ return 0;
+ }
+ if (freq < split_hz)
+ {
+ return freq * lin_space;
+ } else {
+ return split_mel + log_space * LOG (freq / split_hz);
+ }
+
+}
+
+smpl_t
+aubio_meltohz (smpl_t mel)
+{
+ const smpl_t lin_space = 200./3.;
+ const smpl_t split_hz = 1000.;
+ const smpl_t split_mel = split_hz / lin_space;
+ const smpl_t logSpacing = POW(6400/1000., 1/27.);
+ if (mel < 0) {
+ AUBIO_WRN("meltohz: input mel should be >= 0\n");
+ return 0;
+ }
+ if (mel < split_mel) {
+ return lin_space * mel;
+ } else {
+ return split_hz * POW(logSpacing, mel - split_mel);
+ }
+}
+
+smpl_t
+aubio_hztomel_htk (smpl_t freq)
+{
+ const smpl_t split_hz = 700.;
+ const smpl_t log_space = 1127.;
+ if (freq < 0) {
+ AUBIO_WRN("hztomel_htk: input frequency should be >= 0\n");
+ return 0;
+ }
+ return log_space * LOG (1 + freq / split_hz);
+}
+
+smpl_t
+aubio_meltohz_htk (smpl_t mel)
+{
+ const smpl_t split_hz = 700.;
+ const smpl_t log_space = 1./1127.;
+ if (mel < 0) {
+ AUBIO_WRN("meltohz_htk: input frequency should be >= 0\n");
+ return 0;
+ }
+ return split_hz * ( EXP ( mel * log_space) - 1.);
+}
+
diff --git a/aubio/src/musicutils.h b/aubio/src/musicutils.h
new file mode 100644
index 00000000..af222e5b
--- /dev/null
+++ b/aubio/src/musicutils.h
@@ -0,0 +1,270 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** @file
+ * various functions useful in audio signal processing
+ */
+
+#ifndef AUBIO_MUSICUTILS_H
+#define AUBIO_MUSICUTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create window
+
+ \param window_type type of the window to create
+ \param size length of the window to create (see fvec_set_window())
+
+*/
+fvec_t *new_aubio_window (char_t * window_type, uint_t size);
+
+/** set elements of a vector to window coefficients
+
+ \param window exsting ::fvec_t to use
+ \param window_type type of the window to create
+
+ List of available window types: "rectangle", "hamming", "hanning",
+ "hanningz", "blackman", "blackman_harris", "gaussian", "welch", "parzen",
+ "default".
+
+ "default" is equivalent to "hanningz".
+
+ References:
+
+ - Window
+function on Wikipedia
+ - Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional (?)
+implementations of a phase vocoder: the tricks of the trade. In Proceedings of
+the International Conference on Digital Audio Effects (DAFx-00), pages 37–44,
+Uni- versity of Verona, Italy, 2000.
+ (
+ pdf)
+
+ */
+uint_t fvec_set_window (fvec_t * window, char_t * window_type);
+
+/** compute the principal argument
+
+ This function maps the input phase to its corresponding value wrapped in the
+range \f$ [-\pi, \pi] \f$.
+
+ \param phase unwrapped phase to map to the unit circle
+
+ \return equivalent phase wrapped to the unit circle
+
+*/
+smpl_t aubio_unwrap2pi (smpl_t phase);
+
+/** convert frequency bin to midi value */
+smpl_t aubio_bintomidi (smpl_t bin, smpl_t samplerate, smpl_t fftsize);
+
+/** convert midi value to frequency bin */
+smpl_t aubio_miditobin (smpl_t midi, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency bin to frequency (Hz) */
+smpl_t aubio_bintofreq (smpl_t bin, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency (Hz) to frequency bin */
+smpl_t aubio_freqtobin (smpl_t freq, smpl_t samplerate, smpl_t fftsize);
+
+/** convert frequency (Hz) to mel
+
+ \param freq input frequency, in Hz
+
+ \return output mel
+
+ Converts a scalar from the frequency domain to the mel scale using Slaney
+ Auditory Toolbox's implementation:
+
+ If \f$ f < 1000 \f$, \f$ m = 3 f / 200 \f$.
+
+ If \f$ f >= 1000 \f$, \f$ m = 1000 + 27 \frac{{ln}(f) - ln(1000))}
+ {{ln}(6400) - ln(1000)}
+ \f$
+
+ See also
+ --------
+
+ aubio_meltohz(), aubio_hztomel_htk().
+
+*/
+smpl_t aubio_hztomel (smpl_t freq);
+
+/** convert mel to frequency (Hz)
+
+ \param mel input mel
+
+ \return output frequency, in Hz
+
+ Converts a scalar from the mel scale to the frequency domain using Slaney
+ Auditory Toolbox's implementation:
+
+ If \f$ f < 1000 \f$, \f$ f = 200 m/3 \f$.
+
+ If \f$ f \geq 1000 \f$, \f$ f = 1000 + \left(\frac{6400}{1000}\right)
+ ^{\frac{m - 1000}{27}} \f$
+
+ See also
+ --------
+
+ aubio_hztomel(), aubio_meltohz_htk().
+
+ References
+ ----------
+
+ Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+*/
+smpl_t aubio_meltohz (smpl_t mel);
+
+/** convert frequency (Hz) to mel
+
+ \param freq input frequency, in Hz
+
+ \return output mel
+
+ Converts a scalar from the frequency domain to the mel scale, using the
+ equation defined by O'Shaughnessy, as implemented in the HTK speech
+ recognition toolkit:
+
+ \f$ m = 1127 + ln(1 + \frac{f}{700}) \f$
+
+ See also
+ --------
+
+ aubio_meltohz_htk(), aubio_hztomel().
+
+ References
+ ----------
+
+ Douglas O'Shaughnessy (1987). *Speech communication: human and machine*.
+ Addison-Wesley. p. 150. ISBN 978-0-201-16520-3.
+
+ HTK Speech Recognition Toolkit: http://htk.eng.cam.ac.uk/
+
+ */
+smpl_t aubio_hztomel_htk (smpl_t freq);
+
+/** convert mel to frequency (Hz)
+
+ \param mel input mel
+
+ \return output frequency, in Hz
+
+ Converts a scalar from the mel scale to the frequency domain, using the
+ equation defined by O'Shaughnessy, as implemented in the HTK speech
+ recognition toolkit:
+
+ \f$ f = 700 * {e}^\left(\frac{f}{1127} - 1\right) \f$
+
+ See also
+ --------
+
+ aubio_hztomel_htk(), aubio_meltohz().
+
+*/
+smpl_t aubio_meltohz_htk (smpl_t mel);
+
+/** convert frequency (Hz) to midi value (0-128) */
+smpl_t aubio_freqtomidi (smpl_t freq);
+
+/** convert midi value (0-128) to frequency (Hz) */
+smpl_t aubio_miditofreq (smpl_t midi);
+
+/** clean up cached memory at the end of program
+
+ This function should be used at the end of programs to purge all cached
+ memory. So far it is only useful to clean FFTW's cache.
+
+*/
+void aubio_cleanup (void);
+
+/** zero-crossing rate (ZCR)
+
+ The zero-crossing rate is the number of times a signal changes sign,
+ divided by the length of this signal.
+
+ \param v vector to compute ZCR from
+
+ \return zero-crossing rate of v
+
+*/
+smpl_t aubio_zero_crossing_rate (fvec_t * v);
+
+/** compute sound level on a linear scale
+
+ This gives the average of the square amplitudes.
+
+ \param v vector to compute level from
+
+ \return level of v
+
+*/
+smpl_t aubio_level_lin (const fvec_t * v);
+
+/** compute sound pressure level (SPL) in dB
+
+ This quantity is often wrongly called 'loudness'.
+
+ This gives ten times the log10 of the average of the square amplitudes.
+
+ \param v vector to compute dB SPL from
+
+ \return level of v in dB SPL
+
+*/
+smpl_t aubio_db_spl (const fvec_t * v);
+
+/** check if buffer level in dB SPL is under a given threshold
+
+ \param v vector to get level from
+ \param threshold threshold in dB SPL
+
+ \return 1 if level is under the given threshold, 0 otherwise
+
+*/
+uint_t aubio_silence_detection (const fvec_t * v, smpl_t threshold);
+
+/** get buffer level if level >= threshold, 1. otherwise
+
+ \param v vector to get level from
+ \param threshold threshold in dB SPL
+
+ \return level in dB SPL if level >= threshold, 1. otherwise
+
+*/
+smpl_t aubio_level_detection (const fvec_t * v, smpl_t threshold);
+
+/** clamp the values of a vector within the range [-abs(max), abs(max)]
+
+ \param in vector to clamp
+ \param absmax maximum value over which input vector elements should be clamped
+
+*/
+void fvec_clamp(fvec_t *in, smpl_t absmax);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MUSICUTILS_H */
diff --git a/aubio/src/notes/notes.h b/aubio/src/notes/notes.h
new file mode 100644
index 00000000..f256be31
--- /dev/null
+++ b/aubio/src/notes/notes.h
@@ -0,0 +1,143 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Note detection object
+
+*/
+
+#ifndef _AUBIO_NOTES_H
+#define _AUBIO_NOTES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** notes detection object */
+typedef struct _aubio_notes_t aubio_notes_t;
+
+/** create notes detection object
+
+ \param method notes detection type as specified in specdesc.h
+ \param buf_size buffer size for phase vocoder
+ \param hop_size hop size for phase vocoder
+ \param samplerate sampling rate of the input signal
+
+ \return newly created ::aubio_notes_t
+
+*/
+aubio_notes_t * new_aubio_notes (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** delete notes detection object
+
+ \param o notes detection object to delete
+
+*/
+void del_aubio_notes(aubio_notes_t * o);
+
+/** execute note detection on an input signal frame
+
+ \param o note detection object as returned by new_aubio_notes()
+ \param input input signal of size [hop_size]
+ \param output output notes, fvec of length 3
+
+ The notes output is a vector of length 3 containing:
+ - 0. the midi note value, or 0 if no note was found
+ - 1. the note velocity
+ - 2. the midi note to turn off
+
+*/
+void aubio_notes_do (aubio_notes_t *o, const fvec_t * input, fvec_t * output);
+
+/** set notes detection silence threshold
+
+ \param o notes detection object as returned by new_aubio_notes()
+ \param silence new silence detection threshold
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_silence(aubio_notes_t * o, smpl_t silence);
+
+/** get notes detection silence threshold
+
+ \param o notes detection object as returned by new_aubio_notes()
+
+ \return current silence threshold
+
+*/
+smpl_t aubio_notes_get_silence(const aubio_notes_t * o);
+
+/** get notes detection minimum inter-onset interval, in millisecond
+
+ \param o notes detection object as returned by new_aubio_notes()
+
+ \return current minimum inter onset interval
+
+ */
+smpl_t aubio_notes_get_minioi_ms(const aubio_notes_t *o);
+
+/** set notes detection minimum inter-onset interval, in millisecond
+
+ \param o notes detection object as returned by new_aubio_notes()
+ \param minioi_ms new inter-onset interval
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_minioi_ms (aubio_notes_t *o, smpl_t minioi_ms);
+
+/** get notes object release drop level, in dB
+
+ \param o notes detection object as returned by new_aubio_notes()
+
+ \return current release drop level, in dB
+
+ */
+smpl_t aubio_notes_get_release_drop (const aubio_notes_t *o);
+
+/** set note release drop level, in dB
+
+ This function sets the release_drop_level parameter, in dB. When a new note
+ is found, the current level in dB is measured. If the measured level drops
+ under that initial level - release_drop_level, then a note-off will be
+ emitted.
+
+ Defaults to `10`, in dB.
+
+ \note This parameter was added in version `0.4.8`. Results obtained with
+ earlier versions can be reproduced by setting this value to `100`, so that
+ note-off will not be played until the next note.
+
+ \param o notes detection object as returned by new_aubio_notes()
+ \param release_drop new release drop level, in dB
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_release_drop (aubio_notes_t *o, smpl_t release_drop);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_NOTES_H */
diff --git a/aubio/src/onset/onset.c b/aubio/src/onset/onset.c
new file mode 100644
index 00000000..6123d51a
--- /dev/null
+++ b/aubio/src/onset/onset.c
@@ -0,0 +1,355 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+#include "spectral/phasevoc.h"
+#include "spectral/awhitening.h"
+#include "onset/peakpicker.h"
+#include "mathutils.h"
+#include "onset/onset.h"
+
+void aubio_onset_default_parameters (aubio_onset_t *o, const char_t * method);
+
+/** structure to store object state */
+struct _aubio_onset_t {
+ aubio_pvoc_t * pv; /**< phase vocoder */
+ aubio_specdesc_t * od; /**< spectral descriptor */
+ aubio_peakpicker_t * pp; /**< peak picker */
+ cvec_t * fftgrain; /**< phase vocoder output */
+ fvec_t * desc; /**< spectral description */
+ smpl_t silence; /**< silence threhsold */
+ uint_t minioi; /**< minimum inter onset interval */
+ uint_t delay; /**< constant delay, in samples, removed from detected onset times */
+ uint_t samplerate; /**< sampling rate of the input signal */
+ uint_t hop_size; /**< number of samples between two runs */
+
+ uint_t total_frames; /**< total number of frames processed since the beginning */
+ uint_t last_onset; /**< last detected onset location, in frames */
+
+ uint_t apply_compression;
+ smpl_t lambda_compression;
+ uint_t apply_awhitening; /**< apply adaptive spectral whitening */
+ aubio_spectral_whitening_t *spectral_whitening;
+};
+
+/* execute onset detection function on iput buffer */
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset)
+{
+ smpl_t isonset = 0;
+ aubio_pvoc_do (o->pv,input, o->fftgrain);
+ /*
+ if (apply_filtering) {
+ }
+ */
+ if (o->apply_awhitening) {
+ aubio_spectral_whitening_do(o->spectral_whitening, o->fftgrain);
+ }
+ if (o->apply_compression) {
+ cvec_logmag(o->fftgrain, o->lambda_compression);
+ }
+ aubio_specdesc_do (o->od, o->fftgrain, o->desc);
+ aubio_peakpicker_do(o->pp, o->desc, onset);
+ isonset = onset->data[0];
+ if (isonset > 0.) {
+ if (aubio_silence_detection(input, o->silence)==1) {
+ //AUBIO_DBG ("silent onset, not marking as onset\n");
+ isonset = 0;
+ } else {
+ // we have an onset
+ uint_t new_onset = o->total_frames + (uint_t)ROUND(isonset * o->hop_size);
+ // check if last onset time was more than minioi ago
+ if (o->last_onset + o->minioi < new_onset) {
+ // start of file: make sure (new_onset - delay) >= 0
+ if (o->last_onset > 0 && o->delay > new_onset) {
+ isonset = 0;
+ } else {
+ //AUBIO_DBG ("accepted detection, marking as onset\n");
+ o->last_onset = MAX(o->delay, new_onset);
+ }
+ } else {
+ //AUBIO_DBG ("doubled onset, not marking as onset\n");
+ isonset = 0;
+ }
+ }
+ } else {
+ // we are at the beginning of the file
+ if (o->total_frames <= o->delay) {
+ // and we don't find silence
+ if (aubio_silence_detection(input, o->silence) == 0) {
+ uint_t new_onset = o->total_frames;
+ if (o->total_frames == 0 || o->last_onset + o->minioi < new_onset) {
+ isonset = o->delay / o->hop_size;
+ o->last_onset = o->total_frames + o->delay;
+ }
+ }
+ }
+ }
+ onset->data[0] = isonset;
+ o->total_frames += o->hop_size;
+ return;
+}
+
+uint_t aubio_onset_get_last (const aubio_onset_t *o)
+{
+ return o->last_onset - o->delay;
+}
+
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o)
+{
+ return aubio_onset_get_last (o) / (smpl_t) (o->samplerate);
+}
+
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o)
+{
+ return aubio_onset_get_last_s (o) * 1000.;
+}
+
+uint_t aubio_onset_set_awhitening (aubio_onset_t *o, uint_t enable)
+{
+ o->apply_awhitening = enable == 1 ? 1 : 0;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_awhitening (aubio_onset_t *o)
+{
+ return o->apply_awhitening;
+}
+
+uint_t aubio_onset_set_compression (aubio_onset_t *o, smpl_t lambda)
+{
+ if (lambda < 0.) {
+ return AUBIO_FAIL;
+ }
+ o->lambda_compression = lambda;
+ o->apply_compression = (o->lambda_compression > 0.) ? 1 : 0;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_compression (aubio_onset_t *o)
+{
+ return o->apply_compression ? o->lambda_compression : 0;
+}
+
+uint_t aubio_onset_set_silence(aubio_onset_t * o, smpl_t silence) {
+ o->silence = silence;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o) {
+ return o->silence;
+}
+
+uint_t aubio_onset_set_threshold(aubio_onset_t * o, smpl_t threshold) {
+ aubio_peakpicker_set_threshold(o->pp, threshold);
+ return AUBIO_OK;
+}
+
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o) {
+ return aubio_peakpicker_get_threshold(o->pp);
+}
+
+uint_t aubio_onset_set_minioi(aubio_onset_t * o, uint_t minioi) {
+ o->minioi = minioi;
+ return AUBIO_OK;
+}
+
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o) {
+ return o->minioi;
+}
+
+uint_t aubio_onset_set_minioi_s(aubio_onset_t * o, smpl_t minioi) {
+ return aubio_onset_set_minioi (o, (uint_t)ROUND(minioi * o->samplerate));
+}
+
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o) {
+ return aubio_onset_get_minioi (o) / (smpl_t) o->samplerate;
+}
+
+uint_t aubio_onset_set_minioi_ms(aubio_onset_t * o, smpl_t minioi) {
+ return aubio_onset_set_minioi_s (o, minioi / 1000.);
+}
+
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o) {
+ return aubio_onset_get_minioi_s (o) * 1000.;
+}
+
+uint_t aubio_onset_set_delay(aubio_onset_t * o, uint_t delay) {
+ o->delay = delay;
+ return AUBIO_OK;
+}
+
+uint_t aubio_onset_get_delay(const aubio_onset_t * o) {
+ return o->delay;
+}
+
+uint_t aubio_onset_set_delay_s(aubio_onset_t * o, smpl_t delay) {
+ return aubio_onset_set_delay (o, delay * o->samplerate);
+}
+
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o) {
+ return aubio_onset_get_delay (o) / (smpl_t) o->samplerate;
+}
+
+uint_t aubio_onset_set_delay_ms(aubio_onset_t * o, smpl_t delay) {
+ return aubio_onset_set_delay_s (o, delay / 1000.);
+}
+
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o) {
+ return aubio_onset_get_delay_s (o) * 1000.;
+}
+
+smpl_t aubio_onset_get_descriptor(const aubio_onset_t * o) {
+ return o->desc->data[0];
+}
+
+smpl_t aubio_onset_get_thresholded_descriptor(const aubio_onset_t * o) {
+ fvec_t * thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
+ return thresholded->data[0];
+}
+
+/* Allocate memory for an onset detection */
+aubio_onset_t * new_aubio_onset (const char_t * onset_mode,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+ aubio_onset_t * o = AUBIO_NEW(aubio_onset_t);
+
+ /* check parameters are valid */
+ if ((sint_t)hop_size < 1) {
+ AUBIO_ERR("onset: got hop_size %d, but can not be < 1\n", hop_size);
+ goto beach;
+ } else if ((sint_t)buf_size < 2) {
+ AUBIO_ERR("onset: got buffer_size %d, but can not be < 2\n", buf_size);
+ goto beach;
+ } else if (buf_size < hop_size) {
+ AUBIO_ERR("onset: hop size (%d) is larger than win size (%d)\n", hop_size, buf_size);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("onset: samplerate (%d) can not be < 1\n", samplerate);
+ goto beach;
+ }
+
+ /* store creation parameters */
+ o->samplerate = samplerate;
+ o->hop_size = hop_size;
+
+ /* allocate memory */
+ o->pv = new_aubio_pvoc(buf_size, o->hop_size);
+ o->pp = new_aubio_peakpicker();
+ o->od = new_aubio_specdesc(onset_mode,buf_size);
+ o->fftgrain = new_cvec(buf_size);
+ o->desc = new_fvec(1);
+ o->spectral_whitening = new_aubio_spectral_whitening(buf_size, hop_size, samplerate);
+
+ if (!o->pv || !o->pp || !o->od || !o->fftgrain
+ || !o->desc || !o->spectral_whitening)
+ goto beach;
+
+ /* initialize internal variables */
+ aubio_onset_set_default_parameters (o, onset_mode);
+
+ aubio_onset_reset(o);
+ return o;
+
+beach:
+ del_aubio_onset(o);
+ return NULL;
+}
+
+void aubio_onset_reset (aubio_onset_t *o) {
+ o->last_onset = 0;
+ o->total_frames = 0;
+}
+
+uint_t aubio_onset_set_default_parameters (aubio_onset_t * o, const char_t * onset_mode)
+{
+ uint_t ret = AUBIO_OK;
+ /* set some default parameter */
+ aubio_onset_set_threshold (o, 0.3);
+ aubio_onset_set_delay (o, 4.3 * o->hop_size);
+ aubio_onset_set_minioi_ms (o, 50.);
+ aubio_onset_set_silence (o, -70.);
+ // disable spectral whitening
+ aubio_onset_set_awhitening (o, 0);
+ // disable logarithmic magnitude
+ aubio_onset_set_compression (o, 0.);
+
+ /* method specific optimisations */
+ if (strcmp (onset_mode, "energy") == 0) {
+ } else if (strcmp (onset_mode, "hfc") == 0 || strcmp (onset_mode, "default") == 0) {
+ aubio_onset_set_threshold (o, 0.058);
+ aubio_onset_set_compression (o, 1.);
+ } else if (strcmp (onset_mode, "complexdomain") == 0
+ || strcmp (onset_mode, "complex") == 0) {
+ aubio_onset_set_delay (o, 4.6 * o->hop_size);
+ aubio_onset_set_threshold (o, 0.15);
+ aubio_onset_set_awhitening(o, 1);
+ aubio_onset_set_compression (o, 1.);
+ } else if (strcmp (onset_mode, "phase") == 0) {
+ o->apply_compression = 0;
+ aubio_onset_set_awhitening (o, 0);
+ } else if (strcmp (onset_mode, "wphase") == 0) {
+ // use defaults for now
+ } else if (strcmp (onset_mode, "mkl") == 0) {
+ aubio_onset_set_threshold (o, 0.05);
+ aubio_onset_set_awhitening(o, 1);
+ aubio_onset_set_compression (o, 0.02);
+ } else if (strcmp (onset_mode, "kl") == 0) {
+ aubio_onset_set_threshold (o, 0.35);
+ aubio_onset_set_awhitening(o, 1);
+ aubio_onset_set_compression (o, 0.02);
+ } else if (strcmp (onset_mode, "specflux") == 0) {
+ aubio_onset_set_threshold (o, 0.18);
+ aubio_onset_set_awhitening(o, 1);
+ aubio_spectral_whitening_set_relax_time(o->spectral_whitening, 100);
+ aubio_spectral_whitening_set_floor(o->spectral_whitening, 1.);
+ aubio_onset_set_compression (o, 10.);
+ } else if (strcmp (onset_mode, "specdiff") == 0) {
+ } else if (strcmp (onset_mode, "old_default") == 0) {
+ // used to reproduce results obtained with the previous version
+ aubio_onset_set_threshold (o, 0.3);
+ aubio_onset_set_minioi_ms (o, 20.);
+ aubio_onset_set_compression (o, 0.);
+ } else {
+ AUBIO_WRN("onset: unknown spectral descriptor type %s, "
+ "using default parameters.\n", onset_mode);
+ ret = AUBIO_FAIL;
+ }
+ return ret;
+}
+
+void del_aubio_onset (aubio_onset_t *o)
+{
+ if (o->spectral_whitening)
+ del_aubio_spectral_whitening(o->spectral_whitening);
+ if (o->od)
+ del_aubio_specdesc(o->od);
+ if (o->pp)
+ del_aubio_peakpicker(o->pp);
+ if (o->pv)
+ del_aubio_pvoc(o->pv);
+ if (o->desc)
+ del_fvec(o->desc);
+ if (o->fftgrain)
+ del_cvec(o->fftgrain);
+ AUBIO_FREE(o);
+}
diff --git a/aubio/src/onset/onset.h b/aubio/src/onset/onset.h
new file mode 100644
index 00000000..b115e6aa
--- /dev/null
+++ b/aubio/src/onset/onset.h
@@ -0,0 +1,347 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Onset detection object
+
+ The following routines compute the onset detection function and detect peaks
+ in these functions. When onsets are found above a given silence threshold,
+ and after a minimum inter-onset interval, the output vector returned by
+ aubio_onset_do() is filled with `1`. Otherwise, the output vector remains
+ `0`.
+
+ The peak-picking threshold, the silence threshold, and the minimum
+ inter-onset interval can be adjusted during the execution of the
+ aubio_onset_do routine using the corresponding functions.
+
+ \example onset/test-onset.c
+ \example examples/aubioonset.c
+ \example examples/aubionotes.c
+
+*/
+
+
+#ifndef AUBIO_ONSET_H
+#define AUBIO_ONSET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** onset detection object */
+typedef struct _aubio_onset_t aubio_onset_t;
+
+/** create onset detection object
+
+ \param method onset detection type as specified in specdesc.h
+ \param buf_size buffer size for phase vocoder
+ \param hop_size hop size for phase vocoder
+ \param samplerate sampling rate of the input signal
+
+ \return newly created ::aubio_onset_t
+
+*/
+aubio_onset_t * new_aubio_onset (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** execute onset detection
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param input new audio vector of length hop_size
+ \param onset output vector of length 1, containing 0 if no onset was found,
+ and a value equal or greater than 1 otherwise
+
+ When no onset was detected, the first element of the output vector `onset`
+ is set to 0.
+
+ When an onset is found, the first element of the output vector `onset` is set
+ to `offset = 1 + a` where `a` is a number in the range`[0, 1]`.
+
+ The final onset detection time, in samples, can be obtained with
+ aubio_onset_get_last(). It can also be derived from `offset` as
+ follows:
+
+ \code
+ t = total_frames + offset * hop_size - delay
+ \endcode
+
+ where `total_frames` is the total number of frames processed so far, and
+ `delay` is the current delay of the onset object, as returned by
+ aubio_onset_get_delay().
+
+*/
+void aubio_onset_do (aubio_onset_t *o, const fvec_t * input, fvec_t * onset);
+
+/** get the time of the latest onset detected, in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in samples)
+
+*/
+uint_t aubio_onset_get_last (const aubio_onset_t *o);
+
+/** get the time of the latest onset detected, in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in seconds)
+
+*/
+smpl_t aubio_onset_get_last_s (const aubio_onset_t *o);
+
+/** get the time of the latest onset detected, in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return onset detection timestamps (in milliseconds)
+
+*/
+smpl_t aubio_onset_get_last_ms (const aubio_onset_t *o);
+
+/** set onset detection adaptive whitening
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param enable 1 to enable, 0 to disable
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_onset_set_awhitening(aubio_onset_t * o, uint_t enable);
+
+/** get onset detection adaptive whitening
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return 1 if enabled, 0 otherwise
+
+*/
+smpl_t aubio_onset_get_awhitening(aubio_onset_t * o);
+
+/** set or disable log compression
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param lambda logarithmic compression factor, 0 to disable
+
+ \return 0 if successful, 1 otherwise
+
+ */
+uint_t aubio_onset_set_compression(aubio_onset_t *o, smpl_t lambda);
+
+/** get onset detection log compression
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \returns 0 if disabled, compression factor otherwise
+
+ */
+smpl_t aubio_onset_get_compression(aubio_onset_t *o);
+
+/** set onset detection silence threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param silence new silence detection threshold
+
+*/
+uint_t aubio_onset_set_silence(aubio_onset_t * o, smpl_t silence);
+
+/** get onset detection silence threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ \return current silence threshold
+
+*/
+smpl_t aubio_onset_get_silence(const aubio_onset_t * o);
+
+/** get onset detection function
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return the current value of the descriptor
+
+*/
+smpl_t aubio_onset_get_descriptor (const aubio_onset_t *o);
+
+/** get thresholded onset detection function
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return the value of the thresholded descriptor
+
+*/
+smpl_t aubio_onset_get_thresholded_descriptor (const aubio_onset_t *o);
+
+/** set onset detection peak picking threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param threshold new peak-picking threshold
+
+*/
+uint_t aubio_onset_set_threshold(aubio_onset_t * o, smpl_t threshold);
+
+/** set minimum inter onset interval in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ samples)
+
+*/
+uint_t aubio_onset_set_minioi(aubio_onset_t * o, uint_t minioi);
+
+/** set minimum inter onset interval in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ seconds)
+
+*/
+uint_t aubio_onset_set_minioi_s(aubio_onset_t * o, smpl_t minioi);
+
+/** set minimum inter onset interval in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param minioi minimum interval between two consecutive onsets (in
+ milliseconds)
+
+*/
+uint_t aubio_onset_set_minioi_ms(aubio_onset_t * o, smpl_t minioi);
+
+/** set delay in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in samples)
+
+*/
+uint_t aubio_onset_set_delay(aubio_onset_t * o, uint_t delay);
+
+/** set delay in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in seconds)
+
+*/
+uint_t aubio_onset_set_delay_s(aubio_onset_t * o, smpl_t delay);
+
+/** set delay in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param delay constant system delay to take back from detection time
+ (in milliseconds)
+
+*/
+uint_t aubio_onset_set_delay_ms(aubio_onset_t * o, smpl_t delay);
+
+/** get minimum inter onset interval in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ samples)
+
+*/
+uint_t aubio_onset_get_minioi(const aubio_onset_t * o);
+
+/** get minimum inter onset interval in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ seconds)
+
+*/
+smpl_t aubio_onset_get_minioi_s(const aubio_onset_t * o);
+
+/** get minimum inter onset interval in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return minimum interval between two consecutive onsets (in
+ milliseconds)
+
+*/
+smpl_t aubio_onset_get_minioi_ms(const aubio_onset_t * o);
+
+/** get delay in samples
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in samples)
+
+*/
+uint_t aubio_onset_get_delay(const aubio_onset_t * o);
+
+/** get delay in seconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in seconds)
+
+*/
+smpl_t aubio_onset_get_delay_s(const aubio_onset_t * o);
+
+/** get delay in milliseconds
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return constant system delay to take back from detection time
+ (in milliseconds)
+
+*/
+smpl_t aubio_onset_get_delay_ms(const aubio_onset_t * o);
+
+/** get onset peak picking threshold
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \return current onset detection threshold
+
+*/
+smpl_t aubio_onset_get_threshold(const aubio_onset_t * o);
+
+/** set default parameters
+
+ \param o onset detection object as returned by new_aubio_onset()
+ \param onset_mode detection mode to adjust
+
+ This function is called at the end of new_aubio_onset().
+
+ */
+uint_t aubio_onset_set_default_parameters (aubio_onset_t * o, const char_t * onset_mode);
+
+/** reset onset detection
+
+ \param o onset detection object as returned by new_aubio_onset()
+
+ Reset current time and last onset to 0.
+
+ This function is called at the end of new_aubio_onset().
+
+ */
+void aubio_onset_reset(aubio_onset_t * o);
+
+/** delete onset detection object
+
+ \param o onset detection object to delete
+
+*/
+void del_aubio_onset(aubio_onset_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_ONSET_H */
diff --git a/aubio/src/onset/peakpicker.c b/aubio/src/onset/peakpicker.c
new file mode 100644
index 00000000..fa1ee38e
--- /dev/null
+++ b/aubio/src/onset/peakpicker.c
@@ -0,0 +1,199 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+#include "onset/peakpicker.h"
+
+/** function pointer to thresholding function */
+typedef smpl_t (*aubio_thresholdfn_t)(fvec_t *input);
+/** function pointer to peak-picking function */
+typedef uint_t (*aubio_pickerfn_t)(fvec_t *input, uint_t pos);
+
+/** set peak picker thresholding function */
+uint_t aubio_peakpicker_set_thresholdfn(aubio_peakpicker_t * p, aubio_thresholdfn_t thresholdfn);
+/** get peak picker thresholding function */
+aubio_thresholdfn_t aubio_peakpicker_get_thresholdfn(aubio_peakpicker_t * p);
+
+/* peak picking parameters, default values in brackets
+ *
+ * [<----post----|--pre-->]
+ * .................|.............
+ * time-> ^now
+ */
+struct _aubio_peakpicker_t
+{
+ /** thresh: offset threshold [0.033 or 0.01] */
+ smpl_t threshold;
+ /** win_post: median filter window length (causal part) [8] */
+ uint_t win_post;
+ /** pre: median filter window (anti-causal part) [post-1] */
+ uint_t win_pre;
+ /** threshfn: name or handle of fn for computing adaptive threshold [median] */
+ aubio_thresholdfn_t thresholdfn;
+ /** picker: name or handle of fn for picking event times [peakpick] */
+ aubio_pickerfn_t pickerfn;
+
+ /** biquad lowpass filter */
+ aubio_filter_t *biquad;
+ /** original onsets */
+ fvec_t *onset_keep;
+ /** modified onsets */
+ fvec_t *onset_proc;
+ /** peak picked window [3] */
+ fvec_t *onset_peek;
+ /** thresholded function */
+ fvec_t *thresholded;
+ /** scratch pad for biquad and median */
+ fvec_t *scratch;
+
+ /** \bug should be used to calculate filter coefficients */
+ /* cutoff: low-pass filter cutoff [0.34, 1] */
+ /* smpl_t cutoff; */
+
+ /* not used anymore */
+ /* time precision [512/44100 winlength/samplerate, fs/buffer_size */
+ /* smpl_t tau; */
+ /* alpha: normalisation exponent [9] */
+ /* smpl_t alpha; */
+};
+
+
+/** modified version for real time, moving mean adaptive threshold this method
+ * is slightly more permissive than the offline one, and yelds to an increase
+ * of false positives. best */
+void
+aubio_peakpicker_do (aubio_peakpicker_t * p, fvec_t * onset, fvec_t * out)
+{
+ fvec_t *onset_keep = p->onset_keep;
+ fvec_t *onset_proc = p->onset_proc;
+ fvec_t *onset_peek = p->onset_peek;
+ fvec_t *thresholded = p->thresholded;
+ fvec_t *scratch = p->scratch;
+ smpl_t mean = 0., median = 0.;
+ uint_t j = 0;
+
+ /* push new novelty to the end */
+ fvec_push(onset_keep, onset->data[0]);
+ /* store a copy */
+ fvec_copy(onset_keep, onset_proc);
+
+ /* filter this copy */
+ aubio_filter_do_filtfilt (p->biquad, onset_proc, scratch);
+
+ /* calculate mean and median for onset_proc */
+ mean = fvec_mean (onset_proc);
+
+ /* copy to scratch and compute its median */
+ fvec_copy(onset_proc, scratch);
+ median = p->thresholdfn (scratch);
+
+ /* shift peek array */
+ for (j = 0; j < 3 - 1; j++)
+ onset_peek->data[j] = onset_peek->data[j + 1];
+ /* calculate new tresholded value */
+ thresholded->data[0] =
+ onset_proc->data[p->win_post] - median - mean * p->threshold;
+ onset_peek->data[2] = thresholded->data[0];
+ out->data[0] = (p->pickerfn) (onset_peek, 1);
+ if (out->data[0]) {
+ out->data[0] = fvec_quadratic_peak_pos (onset_peek, 1);
+ }
+}
+
+/** this method returns the current value in the pick peaking buffer
+ * after smoothing
+ */
+fvec_t *
+aubio_peakpicker_get_thresholded_input (aubio_peakpicker_t * p)
+{
+ return p->thresholded;
+}
+
+uint_t
+aubio_peakpicker_set_threshold (aubio_peakpicker_t * p, smpl_t threshold)
+{
+ p->threshold = threshold;
+ return AUBIO_OK;
+}
+
+smpl_t
+aubio_peakpicker_get_threshold (aubio_peakpicker_t * p)
+{
+ return p->threshold;
+}
+
+uint_t
+aubio_peakpicker_set_thresholdfn (aubio_peakpicker_t * p,
+ aubio_thresholdfn_t thresholdfn)
+{
+ p->thresholdfn = thresholdfn;
+ return AUBIO_OK;
+}
+
+aubio_thresholdfn_t
+aubio_peakpicker_get_thresholdfn (aubio_peakpicker_t * p)
+{
+ return (aubio_thresholdfn_t) (p->thresholdfn);
+}
+
+aubio_peakpicker_t *
+new_aubio_peakpicker (void)
+{
+ aubio_peakpicker_t *t = AUBIO_NEW (aubio_peakpicker_t);
+ t->threshold = 0.1; /* 0.0668; 0.33; 0.082; 0.033; */
+ t->win_post = 5;
+ t->win_pre = 1;
+
+ t->thresholdfn = (aubio_thresholdfn_t) (fvec_median); /* (fvec_mean); */
+ t->pickerfn = (aubio_pickerfn_t) (fvec_peakpick);
+
+ t->scratch = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_keep = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_proc = new_fvec (t->win_post + t->win_pre + 1);
+ t->onset_peek = new_fvec (3);
+ t->thresholded = new_fvec (1);
+
+ /* cutoff: low-pass filter with cutoff reduced frequency at 0.34
+ generated with octave butter function: [b,a] = butter(2, 0.34);
+ */
+ t->biquad = new_aubio_filter_biquad (0.15998789, 0.31997577, 0.15998789,
+ // FIXME: broken since c9e20ca, revert for now
+ //-0.59488894, 0.23484048);
+ 0.23484048, 0);
+
+ return t;
+}
+
+void
+del_aubio_peakpicker (aubio_peakpicker_t * p)
+{
+ del_aubio_filter (p->biquad);
+ del_fvec (p->onset_keep);
+ del_fvec (p->onset_proc);
+ del_fvec (p->onset_peek);
+ del_fvec (p->thresholded);
+ del_fvec (p->scratch);
+ AUBIO_FREE (p);
+}
diff --git a/aubio/src/onset/peakpicker.h b/aubio/src/onset/peakpicker.h
new file mode 100644
index 00000000..dafaf915
--- /dev/null
+++ b/aubio/src/onset/peakpicker.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Peak picking utilities function
+
+ \example onset/test-peakpicker.c
+
+*/
+
+#ifndef AUBIO_PEAKPICK_H
+#define AUBIO_PEAKPICK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** peak-picker structure */
+typedef struct _aubio_peakpicker_t aubio_peakpicker_t;
+
+/** peak-picker creation function */
+aubio_peakpicker_t * new_aubio_peakpicker(void);
+/** real time peak picking function */
+void aubio_peakpicker_do(aubio_peakpicker_t * p, fvec_t * in, fvec_t * out);
+/** destroy peak picker structure */
+void del_aubio_peakpicker(aubio_peakpicker_t * p);
+
+/** get current peak value */
+fvec_t *aubio_peakpicker_get_thresholded_input (aubio_peakpicker_t * p);
+/** set peak picking threshold */
+uint_t aubio_peakpicker_set_threshold(aubio_peakpicker_t * p, smpl_t threshold);
+/** get peak picking threshold */
+smpl_t aubio_peakpicker_get_threshold(aubio_peakpicker_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PEAKPICK_H */
diff --git a/aubio/src/pitch/pitch.h b/aubio/src/pitch/pitch.h
new file mode 100644
index 00000000..92a05f77
--- /dev/null
+++ b/aubio/src/pitch/pitch.h
@@ -0,0 +1,197 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_PITCH_H
+#define AUBIO_PITCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Pitch detection object
+
+ This file creates the objects required for the computation of the selected
+ pitch detection algorithm and output the results, in midi note or Hz.
+
+ \section pitch Pitch detection methods
+
+ A list of the pitch detection methods currently available follows.
+
+ \b \p default : use the default method
+
+ Currently, the default method is set to \p yinfft .
+
+ \b \p schmitt : Schmitt trigger
+
+ This pitch extraction method implements a Schmitt trigger to estimate the
+ period of a signal.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \b \p fcomb : a fast harmonic comb filter
+
+ This pitch extraction method implements a fast harmonic comb filter to
+ determine the fundamental frequency of a harmonic sound.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \b \p mcomb : multiple-comb filter
+
+ This fundamental frequency estimation algorithm implements spectral
+ flattening, multi-comb filtering and peak histogramming.
+
+ This method was designed by Juan P. Bello and described in:
+
+ Juan-Pablo Bello. ``Towards the Automated Analysis of Simple Polyphonic
+ Music''. PhD thesis, Centre for Digital Music, Queen Mary University of
+ London, London, UK, 2003.
+
+ \b \p yin : YIN algorithm
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+
+ \b \p yinfast : Yinfast algorithm
+
+ This algorithm is equivalent to the YIN algorithm, but computed in the
+ spectral domain for efficiency. See also `python/demos/demo_yin_compare.py`.
+
+ \b \p yinfft : Yinfft algorithm
+
+ This algorithm was derived from the YIN algorithm. In this implementation, a
+ Fourier transform is used to compute a tapered square difference function,
+ which allows spectral weighting. Because the difference function is tapered,
+ the selection of the period is simplified.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, PhD thesis,
+ Centre for Digital music, Queen Mary University of London, London, UK, 2006.
+
+ \example pitch/test-pitch.c
+ \example examples/aubiopitch.c
+
+*/
+
+/** pitch detection object */
+typedef struct _aubio_pitch_t aubio_pitch_t;
+
+/** execute pitch detection on an input signal frame
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param in input signal of size [hop_size]
+ \param out output pitch candidates of size [1]
+
+*/
+void aubio_pitch_do (aubio_pitch_t * o, const fvec_t * in, fvec_t * out);
+
+/** change yin or yinfft tolerance threshold
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param tol tolerance default is 0.15 for yin and 0.85 for yinfft
+
+*/
+uint_t aubio_pitch_set_tolerance (aubio_pitch_t * o, smpl_t tol);
+
+/** get yin or yinfft tolerance threshold
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \return tolerance (default is 0.15 for yin and 0.85 for yinfft)
+
+*/
+smpl_t aubio_pitch_get_tolerance (aubio_pitch_t * o);
+
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+
+*/
+void del_aubio_pitch (aubio_pitch_t * o);
+
+/** creation of the pitch detection object
+
+ \param method set pitch detection algorithm
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_pitch_t
+
+*/
+aubio_pitch_t *new_aubio_pitch (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** set the output unit of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param mode set pitch units for output
+
+ mode can be one of "Hz", "midi", "cent", or "bin". Defaults to "Hz".
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_pitch_set_unit (aubio_pitch_t * o, const char_t * mode);
+
+/** set the silence threshold of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+ \param silence level threshold under which pitch should be ignored, in dB
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_pitch_set_silence (aubio_pitch_t * o, smpl_t silence);
+
+/** set the silence threshold of the pitch detection object
+
+ \param o pitch detection object as returned by ::new_aubio_pitch()
+
+ \return level threshold under which pitch should be ignored, in dB
+
+*/
+smpl_t aubio_pitch_get_silence (aubio_pitch_t * o);
+
+/** get the current confidence
+
+ \param o pitch detection object as returned by new_aubio_pitch()
+
+ \return the current confidence of the pitch algorithm
+
+*/
+smpl_t aubio_pitch_get_confidence (aubio_pitch_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCH_H */
diff --git a/aubio/src/pitch/pitchfcomb.h b/aubio/src/pitch/pitchfcomb.h
new file mode 100644
index 00000000..50167088
--- /dev/null
+++ b/aubio/src/pitch/pitchfcomb.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using a fast harmonic comb filter
+
+ This pitch extraction method implements a fast harmonic comb filter to
+ determine the fundamental frequency of a harmonic sound.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \example pitch/test-pitchfcomb.c
+
+*/
+
+#ifndef AUBIO_PITCHFCOMB_H
+#define AUBIO_PITCHFCOMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchfcomb_t aubio_pitchfcomb_t;
+
+/** execute pitch detection on an input buffer
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+ \param input input signal window (length as specified at creation time)
+ \param output pitch candidates in bins
+
+*/
+void aubio_pitchfcomb_do (aubio_pitchfcomb_t * p, const fvec_t * input,
+ fvec_t * output);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+
+*/
+aubio_pitchfcomb_t *new_aubio_pitchfcomb (uint_t buf_size, uint_t hop_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+
+*/
+void del_aubio_pitchfcomb (aubio_pitchfcomb_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHFCOMB_H */
diff --git a/aubio/src/pitch/pitchmcomb.h b/aubio/src/pitch/pitchmcomb.h
new file mode 100644
index 00000000..88f117f2
--- /dev/null
+++ b/aubio/src/pitch/pitchmcomb.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using multiple-comb filter
+
+ This fundamental frequency estimation algorithm implements spectral
+ flattening, multi-comb filtering and peak histogramming.
+
+ This method was designed by Juan P. Bello and described in:
+
+ Juan-Pablo Bello. ``Towards the Automated Analysis of Simple Polyphonic
+ Music''. PhD thesis, Centre for Digital Music, Queen Mary University of
+ London, London, UK, 2003.
+
+ \example pitch/test-pitchmcomb.c
+
+*/
+
+#ifndef AUBIO_PITCHMCOMB_H
+#define AUBIO_PITCHMCOMB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchmcomb_t aubio_pitchmcomb_t;
+
+/** execute pitch detection on an input spectral frame
+
+ \param p pitch detection object as returned by new_aubio_pitchmcomb
+ \param in_fftgrain input signal spectrum as computed by aubio_pvoc_do
+ \param out_cands pitch candidate frequenciess, in bins
+
+*/
+void aubio_pitchmcomb_do (aubio_pitchmcomb_t * p, const cvec_t * in_fftgrain,
+ fvec_t * out_cands);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+ \param hop_size step size between two consecutive analysis instant
+
+*/
+aubio_pitchmcomb_t *new_aubio_pitchmcomb (uint_t buf_size, uint_t hop_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchfcomb
+
+*/
+void del_aubio_pitchmcomb (aubio_pitchmcomb_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHMCOMB_H */
diff --git a/aubio/src/pitch/pitchschmitt.h b/aubio/src/pitch/pitchschmitt.h
new file mode 100644
index 00000000..db952c34
--- /dev/null
+++ b/aubio/src/pitch/pitchschmitt.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using a Schmitt trigger
+
+ This pitch extraction method implements a Schmitt trigger to estimate the
+ period of a signal.
+
+ This file was derived from the tuneit project, written by Mario Lang to
+ detect the fundamental frequency of a sound.
+
+ See http://delysid.org/tuneit.html
+
+ \example pitch/test-pitchschmitt.c
+
+*/
+
+#ifndef AUBIO_PITCHSCHMITT_H
+#define AUBIO_PITCHSCHMITT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchschmitt_t aubio_pitchschmitt_t;
+
+/** execute pitch detection on an input buffer
+
+ \param p pitch detection object as returned by new_aubio_pitchschmitt
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period estimates, in samples
+
+*/
+void aubio_pitchschmitt_do (aubio_pitchschmitt_t * p, const fvec_t * samples_in,
+ fvec_t * cands_out);
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchschmitt_t *new_aubio_pitchschmitt (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+ \param p pitch detection object as returned by new_aubio_pitchschmitt
+
+*/
+void del_aubio_pitchschmitt (aubio_pitchschmitt_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSCHMITT_H */
diff --git a/aubio/src/pitch/pitchspecacf.h b/aubio/src/pitch/pitchspecacf.h
new file mode 100644
index 00000000..e3c9c4c1
--- /dev/null
+++ b/aubio/src/pitch/pitchspecacf.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using spectral auto correlation
+
+ This algorithm implements pitch detection by computing the autocorrelation
+ function as the cosine transform of the square spectral magnitudes.
+
+ Anssi Klapuri. Qualitative and quantitative aspects in the design of
+ periodicity esti- mation algorithms. In Proceedings of the European Signal
+ Processing Conference (EUSIPCO), 2000.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, Autocorrelation,
+ pp. 75-77, PhD thesis, Centre for Digital music, Queen Mary University of
+ London, London, UK, 2006.
+
+ \example pitch/test-pitchspecacf.c
+
+*/
+
+#ifndef AUBIO_PITCHSPECACF_H
+#define AUBIO_PITCHSPECACF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchspecacf_t aubio_pitchspecacf_t;
+
+/** execute pitch detection on an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchspecacf
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchspecacf_do (aubio_pitchspecacf_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchspecacf_t *new_aubio_pitchspecacf (uint_t buf_size);
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchspecacf()
+
+*/
+void del_aubio_pitchspecacf (aubio_pitchspecacf_t * o);
+
+/** get tolerance parameter for `specacf` pitch detection object
+
+ \param o pitch detection object
+
+ \return tolerance parameter for minima selection [default 1.]
+
+*/
+smpl_t aubio_pitchspecacf_get_tolerance (const aubio_pitchspecacf_t * o);
+
+/** set tolerance parameter for `specacf` pitch detection object
+
+ \param o pitch detection object
+ \param tol tolerance parameter for minima selection [default 1.]
+
+ \return `1` on error, `0` on success
+
+*/
+uint_t aubio_pitchspecacf_set_tolerance (aubio_pitchspecacf_t * o, smpl_t tol);
+
+/** get currenct confidence for `specacf` pitch detection object
+
+ \param o pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchspecacf_get_confidence (const aubio_pitchspecacf_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSPECACF_H */
diff --git a/aubio/src/pitch/pitchyin.h b/aubio/src/pitch/pitchyin.h
new file mode 100644
index 00000000..fa32b8da
--- /dev/null
+++ b/aubio/src/pitch/pitchyin.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using the YIN algorithm
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+ http://recherche.ircam.fr/equipes/pcm/cheveign/ps/2002_JASA_YIN_proof.pdf
+
+ \example pitch/test-pitchyin.c
+
+*/
+
+#ifndef AUBIO_PITCHYIN_H
+#define AUBIO_PITCHYIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyin_t aubio_pitchyin_t;
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyin_t *new_aubio_pitchyin (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+
+*/
+void del_aubio_pitchyin (aubio_pitchyin_t * o);
+
+/** execute pitch detection an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyin_do (aubio_pitchyin_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+
+
+/** set tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyin_set_tolerance (aubio_pitchyin_t * o, smpl_t tol);
+
+/** get tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyin_get_tolerance (aubio_pitchyin_t * o);
+
+/** get current confidence of YIN algorithm
+
+ \param o YIN pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchyin_get_confidence (aubio_pitchyin_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYIN_H */
diff --git a/aubio/src/pitch/pitchyinfast.h b/aubio/src/pitch/pitchyinfast.h
new file mode 100644
index 00000000..abb81393
--- /dev/null
+++ b/aubio/src/pitch/pitchyinfast.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2003-2017 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using YIN algorithm (fast implementation)
+
+ This algorithm was developed by A. de Cheveigne and H. Kawahara and
+ published in:
+
+ De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency
+ estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930.
+
+ This implementation compute the autocorrelation function using time domain
+ convolution computed in the spectral domain.
+
+ see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html
+ http://recherche.ircam.fr/equipes/pcm/cheveign/ps/2002_JASA_YIN_proof.pdf
+
+*/
+
+#ifndef AUBIO_PITCHYINFAST_H
+#define AUBIO_PITCHYINFAST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyinfast_t aubio_pitchyinfast_t;
+
+/** creation of the pitch detection object
+
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyinfast_t *new_aubio_pitchyinfast (uint_t buf_size);
+
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+
+*/
+void del_aubio_pitchyinfast (aubio_pitchyinfast_t * o);
+
+/** execute pitch detection an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchyin()
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyinfast_do (aubio_pitchyinfast_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+
+
+/** set tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyinfast_set_tolerance (aubio_pitchyinfast_t * o, smpl_t tol);
+
+/** get tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyinfast_get_tolerance (aubio_pitchyinfast_t * o);
+
+/** get current confidence of YIN algorithm
+
+ \param o YIN pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchyinfast_get_confidence (aubio_pitchyinfast_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYINFAST_H */
+
diff --git a/aubio/src/pitch/pitchyinfft.h b/aubio/src/pitch/pitchyinfft.h
new file mode 100644
index 00000000..ccd4e518
--- /dev/null
+++ b/aubio/src/pitch/pitchyinfft.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Pitch detection using a spectral implementation of the YIN algorithm
+
+ This algorithm was derived from the YIN algorithm. In this implementation, a
+ Fourier transform is used to compute a tapered square difference function,
+ which allows spectral weighting. Because the difference function is tapered,
+ the selection of the period is simplified.
+
+ Paul Brossier, [Automatic annotation of musical audio for interactive
+ systems](http://aubio.org/phd/), Chapter 3, Pitch Analysis, PhD thesis,
+ Centre for Digital music, Queen Mary University of London, London, UK, 2006.
+
+ \example pitch/test-pitchyinfft.c
+
+*/
+
+#ifndef AUBIO_PITCHYINFFT_H
+#define AUBIO_PITCHYINFFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** pitch detection object */
+typedef struct _aubio_pitchyinfft_t aubio_pitchyinfft_t;
+
+/** execute pitch detection on an input buffer
+
+ \param o pitch detection object as returned by new_aubio_pitchyinfft
+ \param samples_in input signal vector (length as specified at creation time)
+ \param cands_out pitch period candidates, in samples
+
+*/
+void aubio_pitchyinfft_do (aubio_pitchyinfft_t * o, const fvec_t * samples_in, fvec_t * cands_out);
+/** creation of the pitch detection object
+
+ \param samplerate samplerate of the input signal
+ \param buf_size size of the input buffer to analyse
+
+*/
+aubio_pitchyinfft_t *new_aubio_pitchyinfft (uint_t samplerate, uint_t buf_size);
+/** deletion of the pitch detection object
+
+ \param o pitch detection object as returned by new_aubio_pitchyinfft()
+
+*/
+void del_aubio_pitchyinfft (aubio_pitchyinfft_t * o);
+
+/** get tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+
+ \return tolerance parameter for minima selection [default 0.15]
+
+*/
+smpl_t aubio_pitchyinfft_get_tolerance (aubio_pitchyinfft_t * o);
+
+/** set tolerance parameter for YIN algorithm
+
+ \param o YIN pitch detection object
+ \param tol tolerance parameter for minima selection [default 0.15]
+
+*/
+uint_t aubio_pitchyinfft_set_tolerance (aubio_pitchyinfft_t * o, smpl_t tol);
+
+/** get current confidence of YIN algorithm
+
+ \param o YIN pitch detection object
+ \return confidence parameter
+
+*/
+smpl_t aubio_pitchyinfft_get_confidence (aubio_pitchyinfft_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHYINFFT_H */
diff --git a/aubio/src/spectral/awhitening.c b/aubio/src/spectral/awhitening.c
new file mode 100644
index 00000000..1543544c
--- /dev/null
+++ b/aubio/src/spectral/awhitening.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2003-2015 Paul Brossier
+ *
+ * This file is part of aubio.
+ *
+ * aubio is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * aubio is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * aubio. If not, see .
+ *
+ */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/awhitening.h"
+
+#define aubio_spectral_whitening_default_relax_time 250 // in seconds, between 22 and 446
+#define aubio_spectral_whitening_default_decay 0.001 // -60dB attenuation
+#define aubio_spectral_whitening_default_floor 1.e-4 // from 1.e-6 to .2
+
+/** structure to store object state */
+struct _aubio_spectral_whitening_t {
+ uint_t buf_size;
+ uint_t hop_size;
+ uint_t samplerate;
+ smpl_t relax_time;
+ smpl_t r_decay;
+ smpl_t floor;
+ fvec_t *peak_values;
+};
+
+void
+aubio_spectral_whitening_do (aubio_spectral_whitening_t * o, cvec_t * fftgrain)
+{
+ uint_t i = 0;
+ uint_t length = MIN(fftgrain->length, o->peak_values->length);
+ for (i = 0; i < length; i++) {
+ smpl_t tmp = MAX(o->r_decay * o->peak_values->data[i], o->floor);
+ o->peak_values->data[i] = MAX(fftgrain->norm[i], tmp);
+ fftgrain->norm[i] /= o->peak_values->data[i];
+ }
+}
+
+aubio_spectral_whitening_t *
+new_aubio_spectral_whitening (uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+ aubio_spectral_whitening_t *o = AUBIO_NEW (aubio_spectral_whitening_t);
+ if ((sint_t)buf_size < 1) {
+ AUBIO_ERR("spectral_whitening: got buffer_size %d, but can not be < 1\n", buf_size);
+ goto beach;
+ } else if ((sint_t)hop_size < 1) {
+ AUBIO_ERR("spectral_whitening: got hop_size %d, but can not be < 1\n", hop_size);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("spectral_whitening: got samplerate %d, but can not be < 1\n", samplerate);
+ goto beach;
+ }
+ o->peak_values = new_fvec (buf_size / 2 + 1);
+ o->buf_size = buf_size;
+ o->hop_size = hop_size;
+ o->samplerate = samplerate;
+ o->floor = aubio_spectral_whitening_default_floor;
+ aubio_spectral_whitening_set_relax_time (o, aubio_spectral_whitening_default_relax_time);
+ aubio_spectral_whitening_reset (o);
+ return o;
+
+beach:
+ AUBIO_FREE(o);
+ return NULL;
+}
+
+uint_t
+aubio_spectral_whitening_set_relax_time (aubio_spectral_whitening_t * o, smpl_t relax_time)
+{
+ o->relax_time = relax_time;
+ o->r_decay = POW (aubio_spectral_whitening_default_decay,
+ (o->hop_size / (float) o->samplerate) / o->relax_time);
+ return AUBIO_OK;
+}
+
+smpl_t
+aubio_spectral_whitening_get_relax_time (aubio_spectral_whitening_t * o)
+{
+ return o->relax_time;
+}
+
+uint_t
+aubio_spectral_whitening_set_floor (aubio_spectral_whitening_t *o, smpl_t floor)
+{
+ o->floor = floor;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_spectral_whitening_get_floor (aubio_spectral_whitening_t *o)
+{
+ return o->floor;
+}
+
+void
+aubio_spectral_whitening_reset (aubio_spectral_whitening_t * o)
+{
+ /* cover the case n == 0. */
+ fvec_set_all (o->peak_values, o->floor);
+}
+
+void
+del_aubio_spectral_whitening (aubio_spectral_whitening_t * o)
+{
+ del_fvec (o->peak_values);
+ AUBIO_FREE (o);
+}
diff --git a/aubio/src/spectral/awhitening.h b/aubio/src/spectral/awhitening.h
new file mode 100644
index 00000000..64150e7f
--- /dev/null
+++ b/aubio/src/spectral/awhitening.h
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Spectral adaptive whitening
+
+ References:
+
+ D. Stowell and M. D. Plumbley. Adaptive whitening for improved real-time
+ audio onset detection. In Proceedings of the International Computer Music
+ Conference (ICMC), 2007, Copenhagen, Denmark.
+
+ http://www.eecs.qmul.ac.uk/~markp/2007/StowellPlumbley07-icmc.pdf
+
+ S. Böck,, F. Krebs, and M. Schedl. Evaluating the Online Capabilities of
+ Onset Detection Methods. In Proceedings of the 13th International Society for
+ Music Information Retrieval Conference (ISMIR), 2012, Porto, Portugal.
+
+ http://ismir2012.ismir.net/event/papers/049_ISMIR_2012.pdf
+ http://www.cp.jku.at/research/papers/Boeck_etal_ISMIR_2012.pdf
+
+*/
+
+
+#ifndef _AUBIO_SPECTRAL_WHITENING_H
+#define _AUBIO_SPECTRAL_WHITENING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** spectral whitening structure */
+typedef struct _aubio_spectral_whitening_t aubio_spectral_whitening_t;
+
+/** execute spectral adaptive whitening, in-place
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+ \param fftgrain input signal spectrum as computed by aubio_pvoc_do() or aubio_fft_do()
+
+*/
+void aubio_spectral_whitening_do (aubio_spectral_whitening_t * o,
+ cvec_t * fftgrain);
+
+/** creation of a spectral whitening object
+
+ \param buf_size window size of input grains
+ \param hop_size number of samples between two consecutive input grains
+ \param samplerate sampling rate of the input signal
+
+*/
+aubio_spectral_whitening_t *new_aubio_spectral_whitening (uint_t buf_size,
+ uint_t hop_size,
+ uint_t samplerate);
+
+/** reset spectral whitening object
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+
+ */
+void aubio_spectral_whitening_reset (aubio_spectral_whitening_t * o);
+
+/** set relaxation time for spectral whitening
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+ \param relax_time relaxation time in seconds between 20 and 500, defaults 250
+
+ */
+uint_t aubio_spectral_whitening_set_relax_time (aubio_spectral_whitening_t * o,
+ smpl_t relax_time);
+
+/** get relaxation time of spectral whitening
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+ \return relaxation time in seconds
+
+*/
+smpl_t aubio_spectral_whitening_get_relax_time (aubio_spectral_whitening_t * o);
+
+/** set floor for spectral whitening
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+ \param floor value (typically between 1.e-6 and .2, defaults to 1.e-4)
+
+ */
+uint_t aubio_spectral_whitening_set_floor (aubio_spectral_whitening_t * o,
+ smpl_t floor);
+
+/** get floor of spectral whitening
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+ \return floor value
+
+*/
+smpl_t aubio_spectral_whitening_get_floor (aubio_spectral_whitening_t * o);
+
+/** deletion of a spectral whitening
+
+ \param o spectral whitening object as returned by new_aubio_spectral_whitening()
+
+*/
+void del_aubio_spectral_whitening (aubio_spectral_whitening_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_SPECTRAL_WHITENING_H */
diff --git a/aubio/src/spectral/dct.h b/aubio/src/spectral/dct.h
new file mode 100644
index 00000000..6ceb006f
--- /dev/null
+++ b/aubio/src/spectral/dct.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2017 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Discrete Cosine Transform
+
+ Functions aubio_dct_do() and aubio_dct_rdo() are equivalent to MATLAB/Octave
+ dct() and idct() functions, as well as scipy.fftpack.dct(x, norm='ortho') and
+ scipy.fftpack.idct(x, norm='ortho')
+
+ \example spectral/test-dct.c
+
+*/
+
+#ifndef AUBIO_DCT_H
+#define AUBIO_DCT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** DCT object
+
+ This object computes forward and backward DCT type 2 with orthonormal
+ scaling.
+
+*/
+typedef struct _aubio_dct_t aubio_dct_t;
+
+/** create new DCT computation object
+
+ \param size length of the DCT
+
+*/
+aubio_dct_t * new_aubio_dct(uint_t size);
+
+/** compute forward DCT
+
+ \param s dct object as returned by new_aubio_dct
+ \param input input signal
+ \param dct_output transformed input array
+
+*/
+void aubio_dct_do (aubio_dct_t *s, const fvec_t * input, fvec_t * dct_output);
+
+/** compute backward DCT
+
+ \param s dct object as returned by new_aubio_dct
+ \param input input signal
+ \param idct_output transformed input array
+
+*/
+void aubio_dct_rdo (aubio_dct_t *s, const fvec_t * input, fvec_t * idct_output);
+
+
+/** delete DCT object
+
+ \param s dct object as returned by new_aubio_dct
+
+*/
+void del_aubio_dct (aubio_dct_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_DCT_H */
diff --git a/aubio/src/spectral/fft.c b/aubio/src/spectral/fft.c
new file mode 100644
index 00000000..598fe22d
--- /dev/null
+++ b/aubio/src/spectral/fft.c
@@ -0,0 +1,572 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+
+#ifdef HAVE_FFTW3 // using FFTW3
+/* note that is not included here but only in aubio_priv.h, so that
+ * c++ projects can still use their own complex definition. */
+#include
+#include
+
+#ifdef HAVE_COMPLEX_H
+#ifdef HAVE_FFTW3F
+/** fft data type with complex.h and fftw3f */
+#define FFTW_TYPE fftwf_complex
+#else
+/** fft data type with complex.h and fftw3 */
+#define FFTW_TYPE fftw_complex
+#endif
+#else
+#ifdef HAVE_FFTW3F
+/** fft data type without complex.h and with fftw3f */
+#define FFTW_TYPE float
+#else
+/** fft data type without complex.h and with fftw */
+#define FFTW_TYPE double
+#endif
+#endif
+
+/** fft data type */
+typedef FFTW_TYPE fft_data_t;
+
+#ifdef HAVE_FFTW3F
+#define fftw_malloc fftwf_malloc
+#define fftw_free fftwf_free
+#define fftw_execute fftwf_execute
+#define fftw_plan_dft_r2c_1d fftwf_plan_dft_r2c_1d
+#define fftw_plan_dft_c2r_1d fftwf_plan_dft_c2r_1d
+#define fftw_plan_r2r_1d fftwf_plan_r2r_1d
+#define fftw_plan fftwf_plan
+#define fftw_destroy_plan fftwf_destroy_plan
+#endif
+
+#ifdef HAVE_FFTW3F
+#if HAVE_AUBIO_DOUBLE
+#error "Using aubio in double precision with fftw3 in single precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#define real_t float
+#elif defined (HAVE_FFTW3) /* HAVE_FFTW3F */
+#if !HAVE_AUBIO_DOUBLE
+#error "Using aubio in single precision with fftw3 in double precision"
+#endif /* HAVE_AUBIO_DOUBLE */
+#define real_t double
+#endif /* HAVE_FFTW3F */
+
+// a global mutex for FFTW thread safety
+pthread_mutex_t aubio_fftw_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+// https://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html
+#include
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_vDSP_ctoz vDSP_ctoz
+#define aubio_vDSP_fft_zrip vDSP_fft_zrip
+#define aubio_vDSP_ztoc vDSP_ztoc
+#define aubio_vDSP_zvmags vDSP_zvmags
+#define aubio_vDSP_zvphas vDSP_zvphas
+#define aubio_vDSP_vsadd vDSP_vsadd
+#define aubio_vDSP_vsmul vDSP_vsmul
+#define aubio_DSPComplex DSPComplex
+#define aubio_DSPSplitComplex DSPSplitComplex
+#define aubio_vDSP_DFT_Setup vDSP_DFT_Setup
+#define aubio_vDSP_DFT_zrop_CreateSetup vDSP_DFT_zrop_CreateSetup
+#define aubio_vDSP_DFT_Execute vDSP_DFT_Execute
+#define aubio_vDSP_DFT_DestroySetup vDSP_DFT_DestroySetup
+#define aubio_vvsqrt vvsqrtf
+#else
+#define aubio_vDSP_ctoz vDSP_ctozD
+#define aubio_vDSP_fft_zrip vDSP_fft_zripD
+#define aubio_vDSP_ztoc vDSP_ztocD
+#define aubio_vDSP_zvmags vDSP_zvmagsD
+#define aubio_vDSP_zvphas vDSP_zvphasD
+#define aubio_vDSP_vsadd vDSP_vsaddD
+#define aubio_vDSP_vsmul vDSP_vsmulD
+#define aubio_DSPComplex DSPDoubleComplex
+#define aubio_DSPSplitComplex DSPDoubleSplitComplex
+#define aubio_vDSP_DFT_Setup vDSP_DFT_SetupD
+#define aubio_vDSP_DFT_zrop_CreateSetup vDSP_DFT_zrop_CreateSetupD
+#define aubio_vDSP_DFT_Execute vDSP_DFT_ExecuteD
+#define aubio_vDSP_DFT_DestroySetup vDSP_DFT_DestroySetupD
+#define aubio_vvsqrt vvsqrt
+#endif /* HAVE_AUBIO_DOUBLE */
+
+#elif defined HAVE_INTEL_IPP // using INTEL IPP
+
+#if !HAVE_AUBIO_DOUBLE
+#define aubio_IppFloat Ipp32f
+#define aubio_IppComplex Ipp32fc
+#define aubio_FFTSpec FFTSpec_R_32f
+#define aubio_ippsMalloc_complex ippsMalloc_32fc
+#define aubio_ippsFFTInit_R ippsFFTInit_R_32f
+#define aubio_ippsFFTGetSize_R ippsFFTGetSize_R_32f
+#define aubio_ippsFFTInv_CCSToR ippsFFTInv_CCSToR_32f
+#define aubio_ippsFFTFwd_RToCCS ippsFFTFwd_RToCCS_32f
+#define aubio_ippsAtan2 ippsAtan2_32f_A21
+#else /* HAVE_AUBIO_DOUBLE */
+#define aubio_IppFloat Ipp64f
+#define aubio_IppComplex Ipp64fc
+#define aubio_FFTSpec FFTSpec_R_64f
+#define aubio_ippsMalloc_complex ippsMalloc_64fc
+#define aubio_ippsFFTInit_R ippsFFTInit_R_64f
+#define aubio_ippsFFTGetSize_R ippsFFTGetSize_R_64f
+#define aubio_ippsFFTInv_CCSToR ippsFFTInv_CCSToR_64f
+#define aubio_ippsFFTFwd_RToCCS ippsFFTFwd_RToCCS_64f
+#define aubio_ippsAtan2 ippsAtan2_64f_A50
+#endif
+
+
+#else // using OOURA
+// let's use ooura instead
+extern void aubio_ooura_rdft(int, int, smpl_t *, int *, smpl_t *);
+
+#endif
+
+struct _aubio_fft_t {
+ uint_t winsize;
+ uint_t fft_size;
+
+#ifdef HAVE_FFTW3 // using FFTW3
+ real_t *in, *out;
+ fftw_plan pfw, pbw;
+ fft_data_t * specdata; /* complex spectral data */
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+ aubio_vDSP_DFT_Setup fftSetupFwd;
+ aubio_vDSP_DFT_Setup fftSetupBwd;
+ aubio_DSPSplitComplex spec;
+ smpl_t *in, *out;
+
+#elif defined HAVE_INTEL_IPP // using Intel IPP
+ smpl_t *in, *out;
+ Ipp8u* memSpec;
+ Ipp8u* memInit;
+ Ipp8u* memBuffer;
+ struct aubio_FFTSpec* fftSpec;
+ aubio_IppComplex* complexOut;
+#else // using OOURA
+ smpl_t *in, *out;
+ smpl_t *w;
+ int *ip;
+#endif /* using OOURA */
+
+ fvec_t * compspec;
+};
+
+aubio_fft_t * new_aubio_fft (uint_t winsize) {
+ aubio_fft_t * s = AUBIO_NEW(aubio_fft_t);
+ if ((sint_t)winsize < 2) {
+ AUBIO_ERR("fft: got winsize %d, but can not be < 2\n", winsize);
+ goto beach;
+ }
+
+#ifdef HAVE_FFTW3
+ uint_t i;
+ s->winsize = winsize;
+ /* allocate memory */
+ s->in = AUBIO_ARRAY(real_t,winsize);
+ s->out = AUBIO_ARRAY(real_t,winsize);
+ s->compspec = new_fvec(winsize);
+ /* create plans */
+ pthread_mutex_lock(&aubio_fftw_mutex);
+#ifdef HAVE_COMPLEX_H
+ s->fft_size = winsize/2 + 1;
+ s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
+ s->pfw = fftw_plan_dft_r2c_1d(winsize, s->in, s->specdata, FFTW_ESTIMATE);
+ s->pbw = fftw_plan_dft_c2r_1d(winsize, s->specdata, s->out, FFTW_ESTIMATE);
+#else
+ s->fft_size = winsize;
+ s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
+ s->pfw = fftw_plan_r2r_1d(winsize, s->in, s->specdata, FFTW_R2HC, FFTW_ESTIMATE);
+ s->pbw = fftw_plan_r2r_1d(winsize, s->specdata, s->out, FFTW_HC2R, FFTW_ESTIMATE);
+#endif
+ pthread_mutex_unlock(&aubio_fftw_mutex);
+ for (i = 0; i < s->winsize; i++) {
+ s->in[i] = 0.;
+ s->out[i] = 0.;
+ }
+ for (i = 0; i < s->fft_size; i++) {
+ s->specdata[i] = 0.;
+ }
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+ {
+ uint_t radix = winsize;
+ uint_t order = 0;
+ while ((radix / 2) * 2 == radix) {
+ radix /= 2;
+ order++;
+ }
+ if (order < 4 || (radix != 1 && radix != 3 && radix != 5 && radix != 15)) {
+ AUBIO_ERR("fft: vDSP/Accelerate supports FFT with sizes = "
+ "f * 2 ** n, where n > 4 and f in [1, 3, 5, 15], but requested %d. "
+ "Use the closest power of two, or try recompiling aubio with "
+ "--enable-fftw3.\n", winsize);
+ goto beach;
+ }
+ }
+ s->winsize = winsize;
+ s->fft_size = winsize;
+ s->compspec = new_fvec(winsize);
+ s->in = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->out = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->spec.realp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
+ s->spec.imagp = AUBIO_ARRAY(smpl_t, s->fft_size/2);
+ s->fftSetupFwd = aubio_vDSP_DFT_zrop_CreateSetup(NULL,
+ s->fft_size, vDSP_DFT_FORWARD);
+ s->fftSetupBwd = aubio_vDSP_DFT_zrop_CreateSetup(s->fftSetupFwd,
+ s->fft_size, vDSP_DFT_INVERSE);
+
+#elif defined HAVE_INTEL_IPP // using Intel IPP
+ const IppHintAlgorithm qualityHint = ippAlgHintAccurate; // OR ippAlgHintFast;
+ const int flags = IPP_FFT_NODIV_BY_ANY; // we're scaling manually afterwards
+ int order = aubio_power_of_two_order(winsize);
+ int sizeSpec, sizeInit, sizeBuffer;
+ IppStatus status;
+
+ if (winsize <= 4 || aubio_is_power_of_two(winsize) != 1)
+ {
+ AUBIO_ERR("intel IPP fft: can only create with sizes > 4 and power of two, requested %d,"
+ " try recompiling aubio with --enable-fftw3\n", winsize);
+ goto beach;
+ }
+
+ status = aubio_ippsFFTGetSize_R(order, flags, qualityHint,
+ &sizeSpec, &sizeInit, &sizeBuffer);
+ if (status != ippStsNoErr) {
+ AUBIO_ERR("fft: failed to initialize fft. IPP error: %d\n", status);
+ goto beach;
+ }
+ s->fft_size = s->winsize = winsize;
+ s->compspec = new_fvec(winsize);
+ s->in = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->out = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->memSpec = ippsMalloc_8u(sizeSpec);
+ s->memBuffer = ippsMalloc_8u(sizeBuffer);
+ if (sizeInit > 0 ) {
+ s->memInit = ippsMalloc_8u(sizeInit);
+ }
+ s->complexOut = aubio_ippsMalloc_complex(s->fft_size / 2 + 1);
+ status = aubio_ippsFFTInit_R(
+ &s->fftSpec, order, flags, qualityHint, s->memSpec, s->memInit);
+ if (status != ippStsNoErr) {
+ AUBIO_ERR("fft: failed to initialize. IPP error: %d\n", status);
+ goto beach;
+ }
+
+#else // using OOURA
+ if (aubio_is_power_of_two(winsize) != 1) {
+ AUBIO_ERR("fft: can only create with sizes power of two, requested %d,"
+ " try recompiling aubio with --enable-fftw3\n", winsize);
+ goto beach;
+ }
+ s->winsize = winsize;
+ s->fft_size = winsize / 2 + 1;
+ s->compspec = new_fvec(winsize);
+ s->in = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->out = AUBIO_ARRAY(smpl_t, s->winsize);
+ s->ip = AUBIO_ARRAY(int , s->fft_size);
+ s->w = AUBIO_ARRAY(smpl_t, s->fft_size);
+ s->ip[0] = 0;
+#endif /* using OOURA */
+
+ return s;
+
+beach:
+ AUBIO_FREE(s);
+ return NULL;
+}
+
+void del_aubio_fft(aubio_fft_t * s) {
+ /* destroy data */
+#ifdef HAVE_FFTW3 // using FFTW3
+ pthread_mutex_lock(&aubio_fftw_mutex);
+ fftw_destroy_plan(s->pfw);
+ fftw_destroy_plan(s->pbw);
+ fftw_free(s->specdata);
+ pthread_mutex_unlock(&aubio_fftw_mutex);
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+ AUBIO_FREE(s->spec.realp);
+ AUBIO_FREE(s->spec.imagp);
+ aubio_vDSP_DFT_DestroySetup(s->fftSetupBwd);
+ aubio_vDSP_DFT_DestroySetup(s->fftSetupFwd);
+
+#elif defined HAVE_INTEL_IPP // using Intel IPP
+ ippFree(s->memSpec);
+ ippFree(s->memInit);
+ ippFree(s->memBuffer);
+ ippFree(s->complexOut);
+
+#else // using OOURA
+ AUBIO_FREE(s->w);
+ AUBIO_FREE(s->ip);
+#endif
+
+ del_fvec(s->compspec);
+ AUBIO_FREE(s->in);
+ AUBIO_FREE(s->out);
+ AUBIO_FREE(s);
+}
+
+void aubio_fft_do(aubio_fft_t * s, const fvec_t * input, cvec_t * spectrum) {
+ aubio_fft_do_complex(s, input, s->compspec);
+ aubio_fft_get_spectrum(s->compspec, spectrum);
+}
+
+void aubio_fft_rdo(aubio_fft_t * s, const cvec_t * spectrum, fvec_t * output) {
+ aubio_fft_get_realimag(spectrum, s->compspec);
+ aubio_fft_rdo_complex(s, s->compspec, output);
+}
+
+void aubio_fft_do_complex(aubio_fft_t * s, const fvec_t * input, fvec_t * compspec) {
+ uint_t i;
+#ifndef HAVE_MEMCPY_HACKS
+ for (i=0; i < s->winsize; i++) {
+ s->in[i] = input->data[i];
+ }
+#else
+ memcpy(s->in, input->data, s->winsize * sizeof(smpl_t));
+#endif /* HAVE_MEMCPY_HACKS */
+
+#ifdef HAVE_FFTW3 // using FFTW3
+ fftw_execute(s->pfw);
+#ifdef HAVE_COMPLEX_H
+ compspec->data[0] = REAL(s->specdata[0]);
+ for (i = 1; i < s->fft_size -1 ; i++) {
+ compspec->data[i] = REAL(s->specdata[i]);
+ compspec->data[compspec->length - i] = IMAG(s->specdata[i]);
+ }
+ compspec->data[s->fft_size-1] = REAL(s->specdata[s->fft_size-1]);
+#else /* HAVE_COMPLEX_H */
+ for (i = 0; i < s->fft_size; i++) {
+ compspec->data[i] = s->specdata[i];
+ }
+#endif /* HAVE_COMPLEX_H */
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+ // convert real data to even/odd format used in vDSP
+ aubio_vDSP_ctoz((aubio_DSPComplex*)s->in, 2, &s->spec, 1, s->fft_size/2);
+ // compute the FFT
+ aubio_vDSP_DFT_Execute(s->fftSetupFwd, s->spec.realp, s->spec.imagp,
+ s->spec.realp, s->spec.imagp);
+ // convert from vDSP complex split to [ r0, r1, ..., rN, iN-1, .., i2, i1]
+ compspec->data[0] = s->spec.realp[0];
+ compspec->data[s->fft_size / 2] = s->spec.imagp[0];
+ for (i = 1; i < s->fft_size / 2; i++) {
+ compspec->data[i] = s->spec.realp[i];
+ compspec->data[s->fft_size - i] = s->spec.imagp[i];
+ }
+ // apply scaling
+ smpl_t scale = 1./2.;
+ aubio_vDSP_vsmul(compspec->data, 1, &scale, compspec->data, 1, s->fft_size);
+
+#elif defined HAVE_INTEL_IPP // using Intel IPP
+
+ // apply fft
+ aubio_ippsFFTFwd_RToCCS(s->in, (aubio_IppFloat*)s->complexOut, s->fftSpec, s->memBuffer);
+ // convert complex buffer to [ r0, r1, ..., rN, iN-1, .., i2, i1]
+ compspec->data[0] = s->complexOut[0].re;
+ compspec->data[s->fft_size / 2] = s->complexOut[s->fft_size / 2].re;
+ for (i = 1; i < s->fft_size / 2; i++) {
+ compspec->data[i] = s->complexOut[i].re;
+ compspec->data[s->fft_size - i] = s->complexOut[i].im;
+ }
+
+#else // using OOURA
+ aubio_ooura_rdft(s->winsize, 1, s->in, s->ip, s->w);
+ compspec->data[0] = s->in[0];
+ compspec->data[s->winsize / 2] = s->in[1];
+ for (i = 1; i < s->fft_size - 1; i++) {
+ compspec->data[i] = s->in[2 * i];
+ compspec->data[s->winsize - i] = - s->in[2 * i + 1];
+ }
+#endif /* using OOURA */
+}
+
+void aubio_fft_rdo_complex(aubio_fft_t * s, const fvec_t * compspec, fvec_t * output) {
+ uint_t i;
+#ifdef HAVE_FFTW3
+ const smpl_t renorm = 1./(smpl_t)s->winsize;
+#ifdef HAVE_COMPLEX_H
+ s->specdata[0] = compspec->data[0];
+ for (i=1; i < s->fft_size - 1; i++) {
+ s->specdata[i] = compspec->data[i] +
+ I * compspec->data[compspec->length - i];
+ }
+ s->specdata[s->fft_size - 1] = compspec->data[s->fft_size - 1];
+#else
+ for (i=0; i < s->fft_size; i++) {
+ s->specdata[i] = compspec->data[i];
+ }
+#endif
+ fftw_execute(s->pbw);
+ for (i = 0; i < output->length; i++) {
+ output->data[i] = s->out[i]*renorm;
+ }
+
+#elif defined HAVE_ACCELERATE // using ACCELERATE
+ // convert from real imag [ r0, r1, ..., rN, iN-1, .., i2, i1]
+ // to vDSP packed format [ r0, rN, r1, i1, ..., rN-1, iN-1 ]
+ s->out[0] = compspec->data[0];
+ s->out[1] = compspec->data[s->winsize / 2];
+ for (i = 1; i < s->fft_size / 2; i++) {
+ s->out[2 * i] = compspec->data[i];
+ s->out[2 * i + 1] = compspec->data[s->winsize - i];
+ }
+ // convert to split complex format used in vDSP
+ aubio_vDSP_ctoz((aubio_DSPComplex*)s->out, 2, &s->spec, 1, s->fft_size/2);
+ // compute the FFT
+ aubio_vDSP_DFT_Execute(s->fftSetupBwd, s->spec.realp, s->spec.imagp,
+ s->spec.realp, s->spec.imagp);
+ // convert result to real output
+ aubio_vDSP_ztoc(&s->spec, 1, (aubio_DSPComplex*)output->data, 2, s->fft_size/2);
+ // apply scaling
+ smpl_t scale = 1.0 / s->winsize;
+ aubio_vDSP_vsmul(output->data, 1, &scale, output->data, 1, s->fft_size);
+
+#elif defined HAVE_INTEL_IPP // using Intel IPP
+
+ // convert from real imag [ r0, 0, ..., rN, iN-1, .., i2, i1, iN-1] to complex format
+ s->complexOut[0].re = compspec->data[0];
+ s->complexOut[0].im = 0;
+ s->complexOut[s->fft_size / 2].re = compspec->data[s->fft_size / 2];
+ s->complexOut[s->fft_size / 2].im = 0.0;
+ for (i = 1; i < s->fft_size / 2; i++) {
+ s->complexOut[i].re = compspec->data[i];
+ s->complexOut[i].im = compspec->data[s->fft_size - i];
+ }
+ // apply fft
+ aubio_ippsFFTInv_CCSToR((const aubio_IppFloat *)s->complexOut, output->data, s->fftSpec, s->memBuffer);
+ // apply scaling
+ aubio_ippsMulC(output->data, 1.0 / s->winsize, output->data, s->fft_size);
+
+#else // using OOURA
+ smpl_t scale = 2.0 / s->winsize;
+ s->out[0] = compspec->data[0];
+ s->out[1] = compspec->data[s->winsize / 2];
+ for (i = 1; i < s->fft_size - 1; i++) {
+ s->out[2 * i] = compspec->data[i];
+ s->out[2 * i + 1] = - compspec->data[s->winsize - i];
+ }
+ aubio_ooura_rdft(s->winsize, -1, s->out, s->ip, s->w);
+ for (i=0; i < s->winsize; i++) {
+ output->data[i] = s->out[i] * scale;
+ }
+#endif
+}
+
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum) {
+ aubio_fft_get_phas(compspec, spectrum);
+ aubio_fft_get_norm(compspec, spectrum);
+}
+
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec) {
+ aubio_fft_get_imag(spectrum, compspec);
+ aubio_fft_get_real(spectrum, compspec);
+}
+
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum) {
+ uint_t i;
+ if (compspec->data[0] < 0) {
+ spectrum->phas[0] = PI;
+ } else {
+ spectrum->phas[0] = 0.;
+ }
+#if defined(HAVE_INTEL_IPP)
+ // convert from real imag [ r0, r1, ..., rN, iN-1, ..., i2, i1, i0]
+ // to [ r0, r1, ..., rN, i0, i1, i2, ..., iN-1]
+ for (i = 1; i < spectrum->length / 2; i++) {
+ ELEM_SWAP(compspec->data[compspec->length - i],
+ compspec->data[spectrum->length + i - 1]);
+ }
+ aubio_ippsAtan2(compspec->data + spectrum->length,
+ compspec->data + 1, spectrum->phas + 1, spectrum->length - 1);
+ // revert the imaginary part back again
+ for (i = 1; i < spectrum->length / 2; i++) {
+ ELEM_SWAP(compspec->data[spectrum->length + i - 1],
+ compspec->data[compspec->length - i]);
+ }
+#else
+ for (i=1; i < spectrum->length - 1; i++) {
+ spectrum->phas[i] = ATAN2(compspec->data[compspec->length-i],
+ compspec->data[i]);
+ }
+#endif
+#ifdef HAVE_FFTW3
+ // for even length only, make sure last element is 0 or PI
+ if (2 * (compspec->length / 2) == compspec->length) {
+#endif
+ if (compspec->data[compspec->length/2] < 0) {
+ spectrum->phas[spectrum->length - 1] = PI;
+ } else {
+ spectrum->phas[spectrum->length - 1] = 0.;
+ }
+#ifdef HAVE_FFTW3
+ } else {
+ i = spectrum->length - 1;
+ spectrum->phas[i] = ATAN2(compspec->data[compspec->length-i],
+ compspec->data[i]);
+ }
+#endif
+}
+
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum) {
+ uint_t i = 0;
+ spectrum->norm[0] = ABS(compspec->data[0]);
+ for (i=1; i < spectrum->length - 1; i++) {
+ spectrum->norm[i] = SQRT(SQR(compspec->data[i])
+ + SQR(compspec->data[compspec->length - i]) );
+ }
+#ifdef HAVE_FFTW3
+ // for even length, make sure last element is > 0
+ if (2 * (compspec->length / 2) == compspec->length) {
+#endif
+ spectrum->norm[spectrum->length-1] =
+ ABS(compspec->data[compspec->length/2]);
+#ifdef HAVE_FFTW3
+ } else {
+ i = spectrum->length - 1;
+ spectrum->norm[i] = SQRT(SQR(compspec->data[i])
+ + SQR(compspec->data[compspec->length - i]) );
+ }
+#endif
+}
+
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec) {
+ uint_t i;
+ for (i = 1; i < ( compspec->length + 1 ) / 2 /*- 1 + 1*/; i++) {
+ compspec->data[compspec->length - i] =
+ spectrum->norm[i]*SIN(spectrum->phas[i]);
+ }
+}
+
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec) {
+ uint_t i;
+ for (i = 0; i < compspec->length / 2 + 1; i++) {
+ compspec->data[i] =
+ spectrum->norm[i]*COS(spectrum->phas[i]);
+ }
+}
diff --git a/aubio/src/spectral/fft.h b/aubio/src/spectral/fft.h
new file mode 100644
index 00000000..21072c8b
--- /dev/null
+++ b/aubio/src/spectral/fft.h
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Fast Fourier Transform
+
+ Depending on how aubio was compiled, FFT are computed using one of:
+ - [Ooura](http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html)
+ - [FFTW3](http://www.fftw.org)
+ - [vDSP](https://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html)
+
+ \example spectral/test-fft.c
+
+*/
+
+#ifndef AUBIO_FFT_H
+#define AUBIO_FFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** FFT object
+
+ This object computes forward and backward FFTs.
+
+*/
+typedef struct _aubio_fft_t aubio_fft_t;
+
+/** create new FFT computation object
+
+ \param size length of the FFT
+
+*/
+aubio_fft_t * new_aubio_fft (uint_t size);
+/** delete FFT object
+
+ \param s fft object as returned by new_aubio_fft
+
+*/
+void del_aubio_fft(aubio_fft_t * s);
+
+/** compute forward FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param input input signal
+ \param spectrum output spectrum
+
+*/
+void aubio_fft_do (aubio_fft_t *s, const fvec_t * input, cvec_t * spectrum);
+/** compute backward (inverse) FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param spectrum input spectrum
+ \param output output signal
+
+*/
+void aubio_fft_rdo (aubio_fft_t *s, const cvec_t * spectrum, fvec_t * output);
+
+/** compute forward FFT
+
+ \param s fft object as returned by new_aubio_fft
+ \param input real input signal
+ \param compspec complex output fft real/imag
+
+*/
+void aubio_fft_do_complex (aubio_fft_t *s, const fvec_t * input, fvec_t * compspec);
+/** compute backward (inverse) FFT from real/imag
+
+ \param s fft object as returned by new_aubio_fft
+ \param compspec real/imag input fft array
+ \param output real output array
+
+*/
+void aubio_fft_rdo_complex (aubio_fft_t *s, const fvec_t * compspec, fvec_t * output);
+
+/** convert real/imag spectrum to norm/phas spectrum
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_spectrum(const fvec_t * compspec, cvec_t * spectrum);
+/** convert real/imag spectrum to norm/phas spectrum
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_realimag(const cvec_t * spectrum, fvec_t * compspec);
+
+/** compute phas spectrum from real/imag parts
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_phas(const fvec_t * compspec, cvec_t * spectrum);
+/** compute imaginary part from the norm/phas cvec
+
+ \param spectrum norm/phas input array
+ \param compspec real/imag output fft array
+
+*/
+void aubio_fft_get_imag(const cvec_t * spectrum, fvec_t * compspec);
+
+/** compute norm component from real/imag parts
+
+ \param compspec real/imag input fft array
+ \param spectrum cvec norm/phas output array
+
+*/
+void aubio_fft_get_norm(const fvec_t * compspec, cvec_t * spectrum);
+/** compute real part from norm/phas components
+
+ \param spectrum norm/phas input array
+ \param compspec real/imag output fft array
+
+*/
+void aubio_fft_get_real(const cvec_t * spectrum, fvec_t * compspec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FFT_H */
diff --git a/aubio/src/spectral/filterbank.c b/aubio/src/spectral/filterbank.c
new file mode 100644
index 00000000..e82d93dd
--- /dev/null
+++ b/aubio/src/spectral/filterbank.c
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier
+ and Amaury Hazan
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "cvec.h"
+#include "vecutils.h"
+#include "spectral/filterbank.h"
+#include "mathutils.h"
+
+/** \brief A structure to store a set of n_filters filters of lenghts win_s */
+struct _aubio_filterbank_t
+{
+ uint_t win_s;
+ uint_t n_filters;
+ fmat_t *filters;
+ smpl_t norm;
+ smpl_t power;
+};
+
+aubio_filterbank_t *
+new_aubio_filterbank (uint_t n_filters, uint_t win_s)
+{
+ /* allocate space for filterbank object */
+ aubio_filterbank_t *fb = AUBIO_NEW (aubio_filterbank_t);
+
+ if ((sint_t)n_filters <= 0) {
+ AUBIO_ERR("filterbank: n_filters should be > 0, got %d\n", n_filters);
+ goto fail;
+ }
+ if ((sint_t)win_s <= 0) {
+ AUBIO_ERR("filterbank: win_s should be > 0, got %d\n", win_s);
+ goto fail;
+ }
+ fb->win_s = win_s;
+ fb->n_filters = n_filters;
+
+ /* allocate filter tables, a matrix of length win_s and of height n_filters */
+ fb->filters = new_fmat (n_filters, win_s / 2 + 1);
+
+ fb->norm = 1;
+
+ fb->power = 1;
+
+ return fb;
+fail:
+ AUBIO_FREE (fb);
+ return NULL;
+}
+
+void
+del_aubio_filterbank (aubio_filterbank_t * fb)
+{
+ del_fmat (fb->filters);
+ AUBIO_FREE (fb);
+}
+
+void
+aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out)
+{
+ /* apply filter to all input channel, provided out has enough channels */
+ //uint_t max_filters = MIN (f->n_filters, out->length);
+ //uint_t max_length = MIN (in->length, f->filters->length);
+
+ // view cvec->norm as fvec->data
+ fvec_t tmp;
+ tmp.length = in->length;
+ tmp.data = in->norm;
+
+ if (f->power != 1.) fvec_pow(&tmp, f->power);
+
+ fmat_vecmul(f->filters, &tmp, out);
+
+ return;
+}
+
+fmat_t *
+aubio_filterbank_get_coeffs (const aubio_filterbank_t * f)
+{
+ return f->filters;
+}
+
+uint_t
+aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filter_coeffs)
+{
+ fmat_copy(filter_coeffs, f->filters);
+ return 0;
+}
+
+uint_t
+aubio_filterbank_set_norm (aubio_filterbank_t *f, smpl_t norm)
+{
+ if (norm != 0 && norm != 1) return AUBIO_FAIL;
+ f->norm = norm;
+ return AUBIO_OK;
+}
+
+smpl_t
+aubio_filterbank_get_norm (aubio_filterbank_t *f)
+{
+ return f->norm;
+}
+
+uint_t
+aubio_filterbank_set_power (aubio_filterbank_t *f, smpl_t power)
+{
+ f->power = power;
+ return AUBIO_OK;
+}
+
+smpl_t
+aubio_filterbank_get_power (aubio_filterbank_t *f)
+{
+ return f->power;
+}
diff --git a/aubio/src/spectral/filterbank.h b/aubio/src/spectral/filterbank.h
new file mode 100644
index 00000000..876b14d3
--- /dev/null
+++ b/aubio/src/spectral/filterbank.h
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier
+ and Amaury Hazan
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Filterbank object
+
+ General-purpose spectral filterbank object.
+
+ \example spectral/test-filterbank.c
+
+*/
+
+#ifndef AUBIO_FILTERBANK_H
+#define AUBIO_FILTERBANK_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** filterbank object
+
+ This object stores a matrix of spectral filter coefficients.
+
+ */
+typedef struct _aubio_filterbank_t aubio_filterbank_t;
+
+/** create filterbank object
+
+ \param n_filters number of filters to create
+ \param win_s size of analysis buffer (and length the FFT transform)
+
+*/
+aubio_filterbank_t *new_aubio_filterbank (uint_t n_filters, uint_t win_s);
+
+/** destroy filterbank object
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+
+*/
+void del_aubio_filterbank (aubio_filterbank_t * f);
+
+/** compute filterbank
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param in input spectrum containing an input spectrum of length `win_s`
+ \param out output vector containing the energy found in each band, `nfilt` output values
+
+*/
+void aubio_filterbank_do (aubio_filterbank_t * f, const cvec_t * in, fvec_t * out);
+
+/** return a pointer to the matrix object containing all filter coefficients
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+
+ */
+fmat_t *aubio_filterbank_get_coeffs (const aubio_filterbank_t * f);
+
+/** copy filter coefficients to the filterbank
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param filters filter bank coefficients to copy from
+
+ */
+uint_t aubio_filterbank_set_coeffs (aubio_filterbank_t * f, const fmat_t * filters);
+
+/** set norm parameter
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param norm `1` to norm the filters, `0` otherwise.
+
+ If set to `0`, the filters will not be normalized. If set to `1`,
+ each filter will be normalized to one. Defaults to `1`.
+
+ This function should be called *before* setting the filters with one of
+ aubio_filterbank_set_triangle_bands(), aubio_filterbank_set_mel_coeffs(),
+ aubio_filterbank_set_mel_coeffs_htk(), or
+ aubio_filterbank_set_mel_coeffs_slaney().
+
+ */
+uint_t aubio_filterbank_set_norm (aubio_filterbank_t *f, smpl_t norm);
+
+/** get norm parameter
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \returns `1` if norm is set, `0` otherwise. Defaults to `1`.
+
+ */
+smpl_t aubio_filterbank_get_norm (aubio_filterbank_t *f);
+
+/** set power parameter
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \param power Raise norm of the input spectrum norm to this power before
+ computing filterbank. Defaults to `1`.
+
+ */
+uint_t aubio_filterbank_set_power (aubio_filterbank_t *f, smpl_t power);
+
+/** get power parameter
+
+ \param f filterbank object, as returned by new_aubio_filterbank()
+ \return current power parameter. Defaults to `1`.
+
+ */
+smpl_t aubio_filterbank_get_power (aubio_filterbank_t *f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTERBANK_H */
diff --git a/aubio/src/spectral/filterbank_mel.c b/aubio/src/spectral/filterbank_mel.c
new file mode 100644
index 00000000..37713a3a
--- /dev/null
+++ b/aubio/src/spectral/filterbank_mel.c
@@ -0,0 +1,298 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier
+ and Amaury Hazan
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/filterbank.h"
+#include "spectral/filterbank_mel.h"
+#include "mathutils.h"
+
+uint_t
+aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
+ const fvec_t * freqs, smpl_t samplerate)
+{
+
+ fmat_t *filters = aubio_filterbank_get_coeffs (fb);
+ uint_t n_filters = filters->height, win_s = filters->length;
+ fvec_t *lower_freqs, *upper_freqs, *center_freqs;
+ fvec_t *triangle_heights, *fft_freqs;
+
+ uint_t fn; /* filter counter */
+ uint_t bin; /* bin counter */
+
+ smpl_t riseInc, downInc;
+
+ /* freqs define the bands of triangular overlapping windows.
+ throw a warning if filterbank object fb is too short. */
+ if (freqs->length - 2 > n_filters) {
+ AUBIO_WRN ("not enough filters, %d allocated but %d requested\n",
+ n_filters, freqs->length - 2);
+ }
+
+ if (freqs->length - 2 < n_filters) {
+ AUBIO_WRN ("too many filters, %d allocated but %d requested\n",
+ n_filters, freqs->length - 2);
+ }
+
+ for (fn = 0; fn < freqs->length; fn++) {
+ if (freqs->data[fn] < 0) {
+ AUBIO_ERR("filterbank_mel: freqs must contain only positive values.\n");
+ return AUBIO_FAIL;
+ } else if (freqs->data[fn] > samplerate / 2) {
+ AUBIO_WRN("filterbank_mel: freqs should contain only "
+ "values < samplerate / 2.\n");
+ } else if (fn > 0 && freqs->data[fn] < freqs->data[fn-1]) {
+ AUBIO_ERR("filterbank_mel: freqs should be a list of frequencies "
+ "sorted from low to high, but freq[%d] < freq[%d-1]\n", fn, fn);
+ return AUBIO_FAIL;
+ } else if (fn > 0 && freqs->data[fn] == freqs->data[fn-1]) {
+ AUBIO_WRN("filterbank_mel: set_triangle_bands received a list "
+ "with twice the frequency %f\n", freqs->data[fn]);
+ }
+ }
+
+ /* convenience reference to lower/center/upper frequency for each triangle */
+ lower_freqs = new_fvec (n_filters);
+ upper_freqs = new_fvec (n_filters);
+ center_freqs = new_fvec (n_filters);
+
+ /* height of each triangle */
+ triangle_heights = new_fvec (n_filters);
+
+ /* lookup table of each bin frequency in hz */
+ fft_freqs = new_fvec (win_s);
+
+ /* fill up the lower/center/upper */
+ for (fn = 0; fn < n_filters; fn++) {
+ lower_freqs->data[fn] = freqs->data[fn];
+ center_freqs->data[fn] = freqs->data[fn + 1];
+ upper_freqs->data[fn] = freqs->data[fn + 2];
+ }
+
+ /* compute triangle heights so that each triangle has unit area */
+ if (aubio_filterbank_get_norm(fb)) {
+ for (fn = 0; fn < n_filters; fn++) {
+ triangle_heights->data[fn] =
+ 2. / (upper_freqs->data[fn] - lower_freqs->data[fn]);
+ }
+ } else {
+ fvec_ones (triangle_heights);
+ }
+
+ /* fill fft_freqs lookup table, which assigns the frequency in hz to each bin */
+ for (bin = 0; bin < win_s; bin++) {
+ fft_freqs->data[bin] =
+ aubio_bintofreq (bin, samplerate, (win_s - 1) * 2);
+ }
+
+ /* zeroing of all filters */
+ fmat_zeros (filters);
+
+ /* building each filter table */
+ for (fn = 0; fn < n_filters; fn++) {
+
+ /* skip first elements */
+ for (bin = 0; bin < win_s - 1; bin++) {
+ if (fft_freqs->data[bin] <= lower_freqs->data[fn] &&
+ fft_freqs->data[bin + 1] > lower_freqs->data[fn]) {
+ bin++;
+ break;
+ }
+ }
+
+ /* compute positive slope step size */
+ riseInc = triangle_heights->data[fn]
+ / (center_freqs->data[fn] - lower_freqs->data[fn]);
+
+ /* compute coefficients in positive slope */
+ for (; bin < win_s - 1; bin++) {
+ filters->data[fn][bin] =
+ (fft_freqs->data[bin] - lower_freqs->data[fn]) * riseInc;
+
+ if (fft_freqs->data[bin + 1] >= center_freqs->data[fn]) {
+ bin++;
+ break;
+ }
+ }
+
+ /* compute negative slope step size */
+ downInc = triangle_heights->data[fn]
+ / (upper_freqs->data[fn] - center_freqs->data[fn]);
+
+ /* compute coefficents in negative slope */
+ for (; bin < win_s - 1; bin++) {
+ filters->data[fn][bin] +=
+ (upper_freqs->data[fn] - fft_freqs->data[bin]) * downInc;
+
+ if (filters->data[fn][bin] < 0.) {
+ filters->data[fn][bin] = 0.;
+ }
+
+ if (fft_freqs->data[bin + 1] >= upper_freqs->data[fn])
+ break;
+ }
+ /* nothing else to do */
+
+ }
+
+ /* destroy temporarly allocated vectors */
+ del_fvec (lower_freqs);
+ del_fvec (upper_freqs);
+ del_fvec (center_freqs);
+
+ del_fvec (triangle_heights);
+ del_fvec (fft_freqs);
+
+ return AUBIO_OK;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
+ smpl_t samplerate)
+{
+ /* Malcolm Slaney parameters */
+ const smpl_t lowestFrequency = 133.3333;
+ const smpl_t linearSpacing = 66.66666666;
+ const smpl_t logSpacing = 1.0711703;
+
+ const uint_t linearFilters = 13;
+ const uint_t logFilters = 27;
+ const uint_t n_filters = linearFilters + logFilters;
+
+ uint_t fn, retval;
+ smpl_t lastlinearCF;
+
+ /* buffers to compute filter frequencies */
+ fvec_t *freqs;
+
+ if (samplerate <= 0) {
+ AUBIO_ERR("filterbank: set_mel_coeffs_slaney samplerate should be > 0\n");
+ return AUBIO_FAIL;
+ }
+
+ freqs = new_fvec (n_filters + 2);
+
+ /* first step: fill all the linear filter frequencies */
+ for (fn = 0; fn < linearFilters; fn++) {
+ freqs->data[fn] = lowestFrequency + fn * linearSpacing;
+ }
+ lastlinearCF = freqs->data[fn - 1];
+
+ /* second step: fill all the log filter frequencies */
+ for (fn = 0; fn < logFilters + 2; fn++) {
+ freqs->data[fn + linearFilters] =
+ lastlinearCF * (POW (logSpacing, fn + 1));
+ }
+
+ /* now compute the actual coefficients */
+ retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+ /* destroy vector used to store frequency limits */
+ del_fvec (freqs);
+
+ return retval;
+}
+
+static uint_t aubio_filterbank_check_freqs (aubio_filterbank_t *fb UNUSED,
+ smpl_t samplerate, smpl_t *freq_min, smpl_t *freq_max)
+{
+ if (samplerate <= 0) {
+ AUBIO_ERR("filterbank: set_mel_coeffs samplerate should be > 0\n");
+ return AUBIO_FAIL;
+ }
+ if (*freq_max < 0) {
+ AUBIO_ERR("filterbank: set_mel_coeffs freq_max should be > 0\n");
+ return AUBIO_FAIL;
+ } else if (*freq_max == 0) {
+ *freq_max = samplerate / 2.;
+ }
+ if (*freq_min < 0) {
+ AUBIO_ERR("filterbank: set_mel_coeffs freq_min should be > 0\n");
+ return AUBIO_FAIL;
+ }
+ return AUBIO_OK;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs (aubio_filterbank_t * fb, smpl_t samplerate,
+ smpl_t freq_min, smpl_t freq_max)
+{
+ uint_t m, retval;
+ smpl_t start = freq_min, end = freq_max, step;
+ fvec_t *freqs;
+ fmat_t *coeffs = aubio_filterbank_get_coeffs(fb);
+ uint_t n_bands = coeffs->height;
+
+ if (aubio_filterbank_check_freqs(fb, samplerate, &start, &end)) {
+ return AUBIO_FAIL;
+ }
+
+ start = aubio_hztomel(start);
+ end = aubio_hztomel(end);
+
+ freqs = new_fvec(n_bands + 2);
+ step = (end - start) / (n_bands + 1);
+
+ for (m = 0; m < n_bands + 2; m++)
+ {
+ freqs->data[m] = MIN(aubio_meltohz(start + step * m), samplerate/2.);
+ }
+
+ retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+ /* destroy vector used to store frequency limits */
+ del_fvec (freqs);
+ return retval;
+}
+
+uint_t
+aubio_filterbank_set_mel_coeffs_htk (aubio_filterbank_t * fb, smpl_t samplerate,
+ smpl_t freq_min, smpl_t freq_max)
+{
+ uint_t m, retval;
+ smpl_t start = freq_min, end = freq_max, step;
+ fvec_t *freqs;
+ fmat_t *coeffs = aubio_filterbank_get_coeffs(fb);
+ uint_t n_bands = coeffs->height;
+
+ if (aubio_filterbank_check_freqs(fb, samplerate, &start, &end)) {
+ return AUBIO_FAIL;
+ }
+
+ start = aubio_hztomel_htk(start);
+ end = aubio_hztomel_htk(end);
+
+ freqs = new_fvec (n_bands + 2);
+ step = (end - start) / (n_bands + 1);
+
+ for (m = 0; m < n_bands + 2; m++)
+ {
+ freqs->data[m] = MIN(aubio_meltohz_htk(start + step * m), samplerate/2.);
+ }
+
+ retval = aubio_filterbank_set_triangle_bands (fb, freqs, samplerate);
+
+ /* destroy vector used to store frequency limits */
+ del_fvec (freqs);
+ return retval;
+}
diff --git a/aubio/src/spectral/filterbank_mel.h b/aubio/src/spectral/filterbank_mel.h
new file mode 100644
index 00000000..06bbf6c6
--- /dev/null
+++ b/aubio/src/spectral/filterbank_mel.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier
+ and Amaury Hazan
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Filterbank object coefficients initialization
+
+ Functions to create set the ::aubio_filterbank_t coefficients to
+ - ::aubio_filterbank_set_triangle_bands: overlapping triangular bands,
+ - ::aubio_filterbank_set_mel_coeffs_slaney: Mel frequency bands.
+
+ \example spectral/test-filterbank_mel.c
+
+*/
+
+#ifndef AUBIO_FILTERBANK_MEL_H
+#define AUBIO_FILTERBANK_MEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** filterbank initialization with triangular and overlapping bands
+
+ \param fb filterbank object
+ \param freqs arbitrary array of boundary frequencies
+ \param samplerate audio sampling rate
+
+ This function computes the coefficients of the filterbank based on the
+ boundaries found in freqs, in Hz, and using triangular overlapping bands.
+
+*/
+uint_t aubio_filterbank_set_triangle_bands (aubio_filterbank_t * fb,
+ const fvec_t * freqs, smpl_t samplerate);
+
+/** filterbank initialization for Mel filters using Slaney's coefficients
+
+ \param fb filterbank object
+ \param samplerate audio sampling rate, in Hz
+
+ The filter coefficients are built to match exactly Malcolm Slaney's Auditory
+ Toolbox implementation (see file mfcc.m). The number of filters should be 40.
+
+ References
+ ----------
+
+ Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
+ smpl_t samplerate);
+
+/** Mel filterbank initialization
+
+ \param fb filterbank object
+ \param samplerate audio sampling rate
+ \param fmin start frequency, in Hz
+ \param fmax end frequency, in Hz
+
+ The filterbank will be initialized with bands linearly spaced in the mel
+ scale, from `fmin` to `fmax`.
+
+ References
+ ----------
+
+ Malcolm Slaney, *Auditory Toolbox Version 2, Technical Report #1998-010*
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs(aubio_filterbank_t * fb,
+ smpl_t samplerate, smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization
+
+ \param fb filterbank object
+ \param samplerate audio sampling rate
+ \param fmin start frequency, in Hz
+ \param fmax end frequency, in Hz
+
+ The bank of filters will be initalized to to cover linearly spaced bands in
+ the Htk mel scale, from `fmin` to `fmax`.
+
+ References
+ ----------
+
+ Douglas O'Shaughnessy (1987). *Speech communication: human and machine*.
+ Addison-Wesley. p. 150. ISBN 978-0-201-16520-3.
+
+ HTK Speech Recognition Toolkit: http://htk.eng.cam.ac.uk/
+
+*/
+uint_t aubio_filterbank_set_mel_coeffs_htk(aubio_filterbank_t * fb,
+ smpl_t samplerate, smpl_t fmin, smpl_t fmax);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTERBANK_MEL_H */
diff --git a/aubio/src/spectral/mfcc.h b/aubio/src/spectral/mfcc.h
new file mode 100644
index 00000000..46fd979e
--- /dev/null
+++ b/aubio/src/spectral/mfcc.h
@@ -0,0 +1,173 @@
+/*
+ Copyright (C) 2007-2013 Paul Brossier
+ and Amaury Hazan
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Mel-Frequency Cepstrum Coefficients object
+
+ This object computes MFCC coefficients on an input cvec_t.
+
+ The implementation follows the specifications established by Malcolm Slaney
+ in its Auditory Toolbox, available online at the following address (see
+ file mfcc.m):
+
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
+
+ \example spectral/test-mfcc.c
+
+*/
+
+#ifndef AUBIO_MFCC_H
+#define AUBIO_MFCC_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** mfcc object */
+typedef struct _aubio_mfcc_t aubio_mfcc_t;
+
+/** create mfcc object
+
+ \param buf_size size of analysis buffer (and length the FFT transform)
+ \param samplerate audio sampling rate
+ \param n_coeffs number of desired coefficients
+ \param n_filters number of desired filters
+
+*/
+aubio_mfcc_t *new_aubio_mfcc (uint_t buf_size,
+ uint_t n_filters, uint_t n_coeffs, uint_t samplerate);
+
+/** delete mfcc object
+
+ \param mf mfcc object as returned by new_aubio_mfcc
+
+*/
+void del_aubio_mfcc (aubio_mfcc_t * mf);
+
+/** mfcc object processing
+
+ \param mf mfcc object as returned by new_aubio_mfcc
+ \param in input spectrum (buf_size long)
+ \param out output mel coefficients buffer (n_coeffs long)
+
+*/
+void aubio_mfcc_do (aubio_mfcc_t * mf, const cvec_t * in, fvec_t * out);
+
+/** set power parameter
+
+ \param mf mfcc object, as returned by new_aubio_mfcc()
+ \param power Raise norm of the input spectrum norm to this power before
+ computing filterbank. Defaults to `1`.
+
+ See aubio_filterbank_set_power().
+
+ */
+uint_t aubio_mfcc_set_power (aubio_mfcc_t *mf, smpl_t power);
+
+/** get power parameter
+
+ \param mf mfcc object, as returned by new_aubio_mfcc()
+ \return current power parameter. Defaults to `1`.
+
+ See aubio_filterbank_get_power().
+
+ */
+smpl_t aubio_mfcc_get_power (aubio_mfcc_t *mf);
+
+/** set scaling parameter
+
+ \param mf mfcc object, as returned by new_aubio_mfcc()
+ \param scale Scaling value to apply.
+
+ Scales the output of the filterbank after taking its logarithm and before
+ computing the DCT. Defaults to `1`.
+
+*/
+uint_t aubio_mfcc_set_scale (aubio_mfcc_t *mf, smpl_t scale);
+
+/** get scaling parameter
+
+ \param mf mfcc object, as returned by new_aubio_mfcc()
+ \return current scaling parameter. Defaults to `1`.
+
+ */
+smpl_t aubio_mfcc_get_scale (aubio_mfcc_t *mf);
+
+/** Mel filterbank initialization
+
+ \param mf mfcc object
+ \param fmin start frequency, in Hz
+ \param fmax end frequency, in Hz
+
+ The filterbank will be initialized with bands linearly spaced in the mel
+ scale, from `fmin` to `fmax`.
+
+ See also
+ --------
+
+ aubio_filterbank_set_mel_coeffs()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs (aubio_mfcc_t *mf,
+ smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization
+
+ \param mf mfcc object
+ \param fmin start frequency, in Hz
+ \param fmax end frequency, in Hz
+
+ The bank of filters will be initalized to to cover linearly spaced bands in
+ the Htk mel scale, from `fmin` to `fmax`.
+
+ See also
+ --------
+
+ aubio_filterbank_set_mel_coeffs_htk()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs_htk (aubio_mfcc_t *mf,
+ smpl_t fmin, smpl_t fmax);
+
+/** Mel filterbank initialization (Auditory Toolbox's parameters)
+
+ \param mf mfcc object
+
+ The filter coefficients are built to match exactly Malcolm Slaney's Auditory
+ Toolbox implementation. The number of filters should be 40.
+
+ This is the default filterbank when `mf` was created with `n_filters = 40`.
+
+ See also
+ --------
+
+ aubio_filterbank_set_mel_coeffs_slaney()
+
+*/
+uint_t aubio_mfcc_set_mel_coeffs_slaney (aubio_mfcc_t *mf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_MFCC_H */
diff --git a/aubio/src/spectral/ooura_fft8g.c b/aubio/src/spectral/ooura_fft8g.c
new file mode 100644
index 00000000..394bea08
--- /dev/null
+++ b/aubio/src/spectral/ooura_fft8g.c
@@ -0,0 +1,1672 @@
+// modifications made for aubio:
+// - replace all 'double' with 'smpl_t'
+// - include "aubio_priv.h" (for config.h and types.h)
+// - add missing prototypes
+// - use COS, SIN, and ATAN macros
+// - add cast to (smpl_t) to avoid float conversion warnings
+// - declare initialization as static
+// - prefix public function with aubio_ooura_
+
+#include "aubio_priv.h"
+
+void aubio_ooura_cdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void aubio_ooura_rdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void aubio_ooura_ddct(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void aubio_ooura_ddst(int n, int isgn, smpl_t *a, int *ip, smpl_t *w);
+void aubio_ooura_dfct(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w);
+void aubio_ooura_dfst(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w);
+static void makewt(int nw, int *ip, smpl_t *w);
+static void makect(int nc, int *ip, smpl_t *c);
+static void bitrv2(int n, int *ip, smpl_t *a);
+static void bitrv2conj(int n, int *ip, smpl_t *a);
+static void cftfsub(int n, smpl_t *a, smpl_t *w);
+static void cftbsub(int n, smpl_t *a, smpl_t *w);
+static void cft1st(int n, smpl_t *a, smpl_t *w);
+static void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+static void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+static void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+static void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+static void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+
+/*
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :8, 4, 2
+ data :inplace
+ table :use
+functions
+ cdft: Complex Discrete Fourier Transform
+ rdft: Real Discrete Fourier Transform
+ ddct: Discrete Cosine Transform
+ ddst: Discrete Sine Transform
+ dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+ dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+ void cdft(int, int, smpl_t *, int *, smpl_t *);
+ void rdft(int, int, smpl_t *, int *, smpl_t *);
+ void ddct(int, int, smpl_t *, int *, smpl_t *);
+ void ddst(int, int, smpl_t *, int *, smpl_t *);
+ void dfct(int, smpl_t *, smpl_t *, int *, smpl_t *);
+ void dfst(int, smpl_t *, smpl_t *, int *, smpl_t *);
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+
+ ip[0] = 0; // first time only
+ cdft(2*n, -1, a, ip, w);
+ [parameters]
+ 2*n :data length (int)
+ n >= 1, n = power of 2
+ a[0...2*n-1] :input/output data (smpl_t *)
+ input data
+ a[2*j] = Re(x[j]),
+ a[2*j+1] = Im(x[j]), 0<=j= 2+sqrt(n)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ cdft(2*n, -1, a, ip, w);
+ is
+ cdft(2*n, 1, a, ip, w);
+ for (j = 0; j <= 2 * n - 1; j++) {
+ a[j] *= 1.0 / n;
+ }
+ .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+ [definition]
+ RDFT
+ R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+ I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale)
+ a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
+ sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
+ sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+
+ ip[0] = 0; // first time only
+ rdft(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+
+ output data
+ a[2*k] = R[k], 0<=k
+ input data
+ a[2*j] = R[j], 0<=j= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ rdft(n, 1, a, ip, w);
+ is
+ rdft(n, -1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+ [definition]
+ IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+
+ ip[0] = 0; // first time only
+ ddct(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ output data
+ a[k] = C[k], 0<=k= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddct(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddct(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+ [definition]
+ IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+
+ ip[0] = 0; // first time only
+ ddst(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+
+ input data
+ a[j] = A[j], 0
+ output data
+ a[k] = S[k], 0= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddst(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddst(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+ [definition]
+ C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+ [usage]
+ ip[0] = 0; // first time only
+ dfct(n, a, t, ip, w);
+ [parameters]
+ n :data length - 1 (int)
+ n >= 2, n = power of 2
+ a[0...n] :input/output data (smpl_t *)
+ output data
+ a[k] = C[k], 0<=k<=n
+ t[0...n/2] :work area (smpl_t *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ is
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ for (j = 0; j <= n; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+ [definition]
+ S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2
+ a[0...n-1] :input/output data (smpl_t *)
+ output data
+ a[k] = S[k], 0= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (smpl_t *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ dfst(n, a, t, ip, w);
+ is
+ dfst(n, a, t, ip, w);
+ for (j = 1; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+Appendix :
+ The cos/sin table is recalculated when the larger table required.
+ w[] and ip[] are compatible with all routines.
+*/
+
+
+void aubio_ooura_cdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void bitrv2conj(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+
+ if (n > (ip[0] << 2)) {
+ makewt(n >> 2, ip, w);
+ }
+ if (n > 4) {
+ if (isgn >= 0) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ } else {
+ bitrv2conj(n, ip + 2, a);
+ cftbsub(n, a, w);
+ }
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+}
+
+
+void aubio_ooura_rdft(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int nw, nc;
+ smpl_t xi;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 2)) {
+ nc = n >> 2;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xi = a[0] - a[1];
+ a[0] += a[1];
+ a[1] = xi;
+ } else {
+ a[1] = (smpl_t)0.5 * (a[0] - a[1]);
+ a[0] -= a[1];
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+}
+
+
+void aubio_ooura_ddct(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, nw, nc;
+ smpl_t xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = a[j] - a[j - 1];
+ a[j] += a[j - 1];
+ }
+ a[1] = a[0] - xr;
+ a[0] += xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+ dctsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = a[j] - a[j + 1];
+ a[j] += a[j + 1];
+ }
+ a[n - 1] = xr;
+ }
+}
+
+
+void aubio_ooura_ddst(int n, int isgn, smpl_t *a, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void cftbsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void rftbsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, nw, nc;
+ smpl_t xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = -a[j] - a[j - 1];
+ a[j] -= a[j - 1];
+ }
+ a[1] = a[0] + xr;
+ a[0] -= xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+ dstsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = -a[j] - a[j + 1];
+ a[j] -= a[j + 1];
+ }
+ a[n - 1] = -xr;
+ }
+}
+
+
+void aubio_ooura_dfct(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dctsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, k, l, m, mh, nw, nc;
+ smpl_t xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ m = n >> 1;
+ yi = a[m];
+ xi = a[0] + a[n];
+ a[0] -= a[n];
+ t[0] = xi - yi;
+ t[m] = xi + yi;
+ if (n > 2) {
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] - a[n - j];
+ xi = a[j] + a[n - j];
+ yr = a[k] - a[n - k];
+ yi = a[k] + a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi - yi;
+ t[k] = xi + yi;
+ }
+ t[mh] = a[mh] + a[n - mh];
+ a[mh] -= a[n - mh];
+ dctsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[0] - a[1];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] + a[j + 1];
+ a[2 * j - 1] = a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dctsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[0] - t[1];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = t[j] - t[j + 1];
+ a[k + l] = t[j] + t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 0; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] - t[m + j];
+ t[k] = t[m + k] + t[m + j];
+ }
+ t[mh] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ a[n] = t[2] - t[1];
+ a[0] = t[2] + t[1];
+ } else {
+ a[1] = a[0];
+ a[2] = t[0];
+ a[0] = t[1];
+ }
+}
+
+
+void aubio_ooura_dfst(int n, smpl_t *a, smpl_t *t, int *ip, smpl_t *w)
+{
+ void makewt(int nw, int *ip, smpl_t *w);
+ void makect(int nc, int *ip, smpl_t *c);
+ void bitrv2(int n, int *ip, smpl_t *a);
+ void cftfsub(int n, smpl_t *a, smpl_t *w);
+ void rftfsub(int n, smpl_t *a, int nc, smpl_t *c);
+ void dstsub(int n, smpl_t *a, int nc, smpl_t *c);
+ int j, k, l, m, mh, nw, nc;
+ smpl_t xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ if (n > 2) {
+ m = n >> 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] + a[n - j];
+ xi = a[j] - a[n - j];
+ yr = a[k] + a[n - k];
+ yi = a[k] - a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi + yi;
+ t[k] = xi - yi;
+ }
+ t[0] = a[mh] - a[n - mh];
+ a[mh] += a[n - mh];
+ a[0] = a[m];
+ dstsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[1] - a[0];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] - a[j + 1];
+ a[2 * j - 1] = -a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dstsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[1] - t[0];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = -t[j] - t[j + 1];
+ a[k + l] = t[j] - t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] + t[m + j];
+ t[k] = t[m + k] - t[m + j];
+ }
+ t[0] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ }
+ a[0] = 0;
+}
+
+
+/* -------- initializing routines -------- */
+
+
+#include
+
+void makewt(int nw, int *ip, smpl_t *w)
+{
+ void bitrv2(int n, int *ip, smpl_t *a);
+ int j, nwh;
+ smpl_t delta, x, y;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = ATAN(1.0) / nwh;
+ w[0] = 1;
+ w[1] = 0;
+ w[nwh] = COS(delta * nwh);
+ w[nwh + 1] = w[nwh];
+ if (nwh > 2) {
+ for (j = 2; j < nwh; j += 2) {
+ x = COS(delta * j);
+ y = SIN(delta * j);
+ w[j] = x;
+ w[j + 1] = y;
+ w[nw - j] = y;
+ w[nw - j + 1] = x;
+ }
+ for (j = nwh - 2; j >= 2; j -= 2) {
+ x = w[2 * j];
+ y = w[2 * j + 1];
+ w[nwh + j] = x;
+ w[nwh + j + 1] = y;
+ }
+ bitrv2(nw, ip + 2, w);
+ }
+ }
+}
+
+
+void makect(int nc, int *ip, smpl_t *c)
+{
+ int j, nch;
+ smpl_t delta;
+
+ ip[1] = nc;
+ if (nc > 1) {
+ nch = nc >> 1;
+ delta = ATAN(1.0) / nch;
+ c[0] = COS(delta * nch);
+ c[nch] = (smpl_t)0.5 * c[0];
+ for (j = 1; j < nch; j++) {
+ c[j] = (smpl_t)0.5 * COS(delta * j);
+ c[nc - j] = (smpl_t)0.5 * SIN(delta * j);
+ }
+ }
+}
+
+
+/* -------- child routines -------- */
+
+
+void bitrv2(int n, int *ip, smpl_t *a)
+{
+ int j, j1, k, k1, l, m, m2;
+ smpl_t xr, xi, yr, yi;
+
+ ip[0] = 0;
+ l = n;
+ m = 1;
+ while ((m << 3) < l) {
+ l >>= 1;
+ for (j = 0; j < m; j++) {
+ ip[m + j] = ip[j] + l;
+ }
+ m <<= 1;
+ }
+ m2 = 2 * m;
+ if ((m << 3) == l) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 -= m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ j1 = 2 * k + m2 + ip[k];
+ k1 = j1 + m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ } else {
+ for (k = 1; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ }
+ }
+}
+
+
+void bitrv2conj(int n, int *ip, smpl_t *a)
+{
+ int j, j1, k, k1, l, m, m2;
+ smpl_t xr, xi, yr, yi;
+
+ ip[0] = 0;
+ l = n;
+ m = 1;
+ while ((m << 3) < l) {
+ l >>= 1;
+ for (j = 0; j < m; j++) {
+ ip[m + j] = ip[j] + l;
+ }
+ m <<= 1;
+ }
+ m2 = 2 * m;
+ if ((m << 3) == l) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 -= m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ j1 = k1 + m2;
+ k1 = j1 + m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ k1 += m2;
+ a[k1 + 1] = -a[k1 + 1];
+ }
+ } else {
+ a[1] = -a[1];
+ a[m2 + 1] = -a[m2 + 1];
+ for (k = 1; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += m2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ a[k1 + m2 + 1] = -a[k1 + m2 + 1];
+ }
+ }
+}
+
+
+void cftfsub(int n, smpl_t *a, smpl_t *w)
+{
+ void cft1st(int n, smpl_t *a, smpl_t *w);
+ void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+ int j, j1, j2, j3, l;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ l = 2;
+ if (n >= 16) {
+ cft1st(n, a, w);
+ l = 16;
+ while ((l << 3) <= n) {
+ cftmdl(n, l, a, w);
+ l <<= 3;
+ }
+ }
+ if ((l << 1) < n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i - x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ }
+ } else if ((l << 1) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = a[j + 1] - a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] += a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+
+void cftbsub(int n, smpl_t *a, smpl_t *w)
+{
+ void cft1st(int n, smpl_t *a, smpl_t *w);
+ void cftmdl(int n, int l, smpl_t *a, smpl_t *w);
+ int j, j1, j2, j3, j4, j5, j6, j7, l;
+ smpl_t wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ l = 2;
+ if (n > 16) {
+ cft1st(n, a, w);
+ l = 16;
+ while ((l << 3) < n) {
+ cftmdl(n, l, a, w);
+ l <<= 3;
+ }
+ }
+ if ((l << 2) < n) {
+ wn4r = w[2];
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i - x2i;
+ y2r = x0r - x2r;
+ y2i = x0i + x2i;
+ y1r = x1r - x3i;
+ y1i = x1i - x3r;
+ y3r = x1r + x3i;
+ y3i = x1i + x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[j1] = y1r + y5r;
+ a[j1 + 1] = y1i - y5i;
+ a[j5] = y1r - y5r;
+ a[j5 + 1] = y1i + y5i;
+ a[j3] = y3r - y7i;
+ a[j3 + 1] = y3i - y7r;
+ a[j7] = y3r + y7i;
+ a[j7 + 1] = y3i + y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i - y4i;
+ a[j4] = y0r - y4r;
+ a[j4 + 1] = y0i + y4i;
+ a[j2] = y2r - y6i;
+ a[j2 + 1] = y2i - y6r;
+ a[j6] = y2r + y6i;
+ a[j6 + 1] = y2i + y6r;
+ }
+ } else if ((l << 2) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i + x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i - x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i + x3r;
+ }
+ } else {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = -a[j + 1] + a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] = -a[j + 1] - a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+
+void cft1st(int n, smpl_t *a, smpl_t *w)
+{
+ int j, k1;
+ smpl_t wn4r, wtmp, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ wk4r, wk4i, wk5r, wk5i, wk6r, wk6i, wk7r, wk7i;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[2];
+ x0r = a[0] + a[2];
+ x0i = a[1] + a[3];
+ x1r = a[0] - a[2];
+ x1i = a[1] - a[3];
+ x2r = a[4] + a[6];
+ x2i = a[5] + a[7];
+ x3r = a[4] - a[6];
+ x3i = a[5] - a[7];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[8] + a[10];
+ x0i = a[9] + a[11];
+ x1r = a[8] - a[10];
+ x1i = a[9] - a[11];
+ x2r = a[12] + a[14];
+ x2i = a[13] + a[15];
+ x3r = a[12] - a[14];
+ x3i = a[13] - a[15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[2] = y1r + y5r;
+ a[3] = y1i + y5i;
+ a[10] = y1r - y5r;
+ a[11] = y1i - y5i;
+ a[6] = y3r - y7i;
+ a[7] = y3i + y7r;
+ a[14] = y3r + y7i;
+ a[15] = y3i - y7r;
+ a[0] = y0r + y4r;
+ a[1] = y0i + y4i;
+ a[8] = y0r - y4r;
+ a[9] = y0i - y4i;
+ a[4] = y2r - y6i;
+ a[5] = y2i + y6r;
+ a[12] = y2r + y6i;
+ a[13] = y2i - y6r;
+ if (n > 16) {
+ wk1r = w[4];
+ wk1i = w[5];
+ x0r = a[16] + a[18];
+ x0i = a[17] + a[19];
+ x1r = a[16] - a[18];
+ x1i = a[17] - a[19];
+ x2r = a[20] + a[22];
+ x2i = a[21] + a[23];
+ x3r = a[20] - a[22];
+ x3i = a[21] - a[23];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[24] + a[26];
+ x0i = a[25] + a[27];
+ x1r = a[24] - a[26];
+ x1i = a[25] - a[27];
+ x2r = a[28] + a[30];
+ x2i = a[29] + a[31];
+ x3r = a[28] - a[30];
+ x3i = a[29] - a[31];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x3r - x1i;
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ y7r = wk1r * x2r + wk1i * x2i;
+ y7i = wk1r * x2i - wk1i * x2r;
+ x0r = wk1r * y1r - wk1i * y1i;
+ x0i = wk1r * y1i + wk1i * y1r;
+ a[18] = x0r + y5r;
+ a[19] = x0i + y5i;
+ a[26] = y5i - x0i;
+ a[27] = x0r - y5r;
+ x0r = wk1i * y3r - wk1r * y3i;
+ x0i = wk1i * y3i + wk1r * y3r;
+ a[22] = x0r - y7r;
+ a[23] = x0i + y7i;
+ a[30] = y7i - x0i;
+ a[31] = x0r + y7r;
+ a[16] = y0r + y4r;
+ a[17] = y0i + y4i;
+ a[24] = y4i - y0i;
+ a[25] = y0r - y4r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[20] = wn4r * (x0r - x0i);
+ a[21] = wn4r * (x0i + x0r);
+ x0r = y6r - y2i;
+ x0i = y2r + y6i;
+ a[28] = wn4r * (x0r - x0i);
+ a[29] = wn4r * (x0i + x0r);
+ k1 = 4;
+ for (j = 32; j < n; j += 16) {
+ k1 += 4;
+ wk1r = w[k1];
+ wk1i = w[k1 + 1];
+ wk2r = w[k1 + 2];
+ wk2i = w[k1 + 3];
+ wtmp = 2 * wk2i;
+ wk3r = wk1r - wtmp * wk1i;
+ wk3i = wtmp * wk1r - wk1i;
+ wk4r = 1 - wtmp * wk2i;
+ wk4i = wtmp * wk2r;
+ wtmp = 2 * wk4i;
+ wk5r = wk3r - wtmp * wk1i;
+ wk5i = wtmp * wk1r - wk3i;
+ wk6r = wk2r - wtmp * wk2i;
+ wk6i = wtmp * wk2r - wk2i;
+ wk7r = wk1r - wtmp * wk3i;
+ wk7i = wtmp * wk3r - wk1i;
+ x0r = a[j] + a[j + 2];
+ x0i = a[j + 1] + a[j + 3];
+ x1r = a[j] - a[j + 2];
+ x1i = a[j + 1] - a[j + 3];
+ x2r = a[j + 4] + a[j + 6];
+ x2i = a[j + 5] + a[j + 7];
+ x3r = a[j + 4] - a[j + 6];
+ x3i = a[j + 5] - a[j + 7];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j + 8] + a[j + 10];
+ x0i = a[j + 9] + a[j + 11];
+ x1r = a[j + 8] - a[j + 10];
+ x1i = a[j + 9] - a[j + 11];
+ x2r = a[j + 12] + a[j + 14];
+ x2i = a[j + 13] + a[j + 15];
+ x3r = a[j + 12] - a[j + 14];
+ x3i = a[j + 13] - a[j + 15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ x0r = y1r + y5r;
+ x0i = y1i + y5i;
+ a[j + 2] = wk1r * x0r - wk1i * x0i;
+ a[j + 3] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y5r;
+ x0i = y1i - y5i;
+ a[j + 10] = wk5r * x0r - wk5i * x0i;
+ a[j + 11] = wk5r * x0i + wk5i * x0r;
+ x0r = y3r - y7i;
+ x0i = y3i + y7r;
+ a[j + 6] = wk3r * x0r - wk3i * x0i;
+ a[j + 7] = wk3r * x0i + wk3i * x0r;
+ x0r = y3r + y7i;
+ x0i = y3i - y7r;
+ a[j + 14] = wk7r * x0r - wk7i * x0i;
+ a[j + 15] = wk7r * x0i + wk7i * x0r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ x0r = y0r - y4r;
+ x0i = y0i - y4i;
+ a[j + 8] = wk4r * x0r - wk4i * x0i;
+ a[j + 9] = wk4r * x0i + wk4i * x0r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j + 4] = wk2r * x0r - wk2i * x0i;
+ a[j + 5] = wk2r * x0i + wk2i * x0r;
+ x0r = y2r + y6i;
+ x0i = y2i - y6r;
+ a[j + 12] = wk6r * x0r - wk6i * x0i;
+ a[j + 13] = wk6r * x0i + wk6i * x0r;
+ }
+ }
+}
+
+
+void cftmdl(int n, int l, smpl_t *a, smpl_t *w)
+{
+ int j, j1, j2, j3, j4, j5, j6, j7, k, k1, m;
+ smpl_t wn4r, wtmp, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ wk4r, wk4i, wk5r, wk5i, wk6r, wk6i, wk7r, wk7i;
+ smpl_t x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ m = l << 3;
+ wn4r = w[2];
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[j1] = y1r + y5r;
+ a[j1 + 1] = y1i + y5i;
+ a[j5] = y1r - y5r;
+ a[j5 + 1] = y1i - y5i;
+ a[j3] = y3r - y7i;
+ a[j3 + 1] = y3i + y7r;
+ a[j7] = y3r + y7i;
+ a[j7 + 1] = y3i - y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ a[j4] = y0r - y4r;
+ a[j4 + 1] = y0i - y4i;
+ a[j2] = y2r - y6i;
+ a[j2 + 1] = y2i + y6r;
+ a[j6] = y2r + y6i;
+ a[j6 + 1] = y2i - y6r;
+ }
+ if (m < n) {
+ wk1r = w[4];
+ wk1i = w[5];
+ for (j = m; j < l + m; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x3r - x1i;
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ y7r = wk1r * x2r + wk1i * x2i;
+ y7i = wk1r * x2i - wk1i * x2r;
+ x0r = wk1r * y1r - wk1i * y1i;
+ x0i = wk1r * y1i + wk1i * y1r;
+ a[j1] = x0r + y5r;
+ a[j1 + 1] = x0i + y5i;
+ a[j5] = y5i - x0i;
+ a[j5 + 1] = x0r - y5r;
+ x0r = wk1i * y3r - wk1r * y3i;
+ x0i = wk1i * y3i + wk1r * y3r;
+ a[j3] = x0r - y7r;
+ a[j3 + 1] = x0i + y7i;
+ a[j7] = y7i - x0i;
+ a[j7 + 1] = x0r + y7r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ a[j4] = y4i - y0i;
+ a[j4 + 1] = y0r - y4r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = y6r - y2i;
+ x0i = y2r + y6i;
+ a[j6] = wn4r * (x0r - x0i);
+ a[j6 + 1] = wn4r * (x0i + x0r);
+ }
+ k1 = 4;
+ for (k = 2 * m; k < n; k += m) {
+ k1 += 4;
+ wk1r = w[k1];
+ wk1i = w[k1 + 1];
+ wk2r = w[k1 + 2];
+ wk2i = w[k1 + 3];
+ wtmp = 2 * wk2i;
+ wk3r = wk1r - wtmp * wk1i;
+ wk3i = wtmp * wk1r - wk1i;
+ wk4r = 1 - wtmp * wk2i;
+ wk4i = wtmp * wk2r;
+ wtmp = 2 * wk4i;
+ wk5r = wk3r - wtmp * wk1i;
+ wk5i = wtmp * wk1r - wk3i;
+ wk6r = wk2r - wtmp * wk2i;
+ wk6i = wtmp * wk2r - wk2i;
+ wk7r = wk1r - wtmp * wk3i;
+ wk7i = wtmp * wk3r - wk1i;
+ for (j = k; j < l + k; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ j4 = j3 + l;
+ j5 = j4 + l;
+ j6 = j5 + l;
+ j7 = j6 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[j4] + a[j5];
+ x0i = a[j4 + 1] + a[j5 + 1];
+ x1r = a[j4] - a[j5];
+ x1i = a[j4 + 1] - a[j5 + 1];
+ x2r = a[j6] + a[j7];
+ x2i = a[j6 + 1] + a[j7 + 1];
+ x3r = a[j6] - a[j7];
+ x3i = a[j6 + 1] - a[j7 + 1];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ x0r = y1r + y5r;
+ x0i = y1i + y5i;
+ a[j1] = wk1r * x0r - wk1i * x0i;
+ a[j1 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y5r;
+ x0i = y1i - y5i;
+ a[j5] = wk5r * x0r - wk5i * x0i;
+ a[j5 + 1] = wk5r * x0i + wk5i * x0r;
+ x0r = y3r - y7i;
+ x0i = y3i + y7r;
+ a[j3] = wk3r * x0r - wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i + wk3i * x0r;
+ x0r = y3r + y7i;
+ x0i = y3i - y7r;
+ a[j7] = wk7r * x0r - wk7i * x0i;
+ a[j7 + 1] = wk7r * x0i + wk7i * x0r;
+ a[j] = y0r + y4r;
+ a[j + 1] = y0i + y4i;
+ x0r = y0r - y4r;
+ x0i = y0i - y4i;
+ a[j4] = wk4r * x0r - wk4i * x0i;
+ a[j4 + 1] = wk4r * x0i + wk4i * x0r;
+ x0r = y2r - y6i;
+ x0i = y2i + y6r;
+ a[j2] = wk2r * x0r - wk2i * x0i;
+ a[j2 + 1] = wk2r * x0i + wk2i * x0r;
+ x0r = y2r + y6i;
+ x0i = y2i - y6r;
+ a[j6] = wk6r * x0r - wk6i * x0i;
+ a[j6 + 1] = wk6r * x0i + wk6i * x0r;
+ }
+ }
+ }
+}
+
+
+void rftfsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = (smpl_t)0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr - wki * xi;
+ yi = wkr * xi + wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+void rftbsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr, xi, yr, yi;
+
+ a[1] = -a[1];
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = (smpl_t)0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr + wki * xi;
+ yi = wkr * xi - wki * xr;
+ a[j] -= yr;
+ a[j + 1] = yi - a[j + 1];
+ a[k] += yr;
+ a[k + 1] = yi - a[k + 1];
+ }
+ a[m + 1] = -a[m + 1];
+}
+
+
+void dctsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[j] - wkr * a[k];
+ a[j] = wkr * a[j] + wki * a[k];
+ a[k] = xr;
+ }
+ a[m] *= c[0];
+}
+
+
+void dstsub(int n, smpl_t *a, int nc, smpl_t *c)
+{
+ int j, k, kk, ks, m;
+ smpl_t wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[k] - wkr * a[j];
+ a[k] = wkr * a[k] + wki * a[j];
+ a[j] = xr;
+ }
+ a[m] *= c[0];
+}
+
diff --git a/aubio/src/spectral/phasevoc.c b/aubio/src/spectral/phasevoc.c
new file mode 100644
index 00000000..05ebdb06
--- /dev/null
+++ b/aubio/src/spectral/phasevoc.c
@@ -0,0 +1,224 @@
+/*
+ Copyright (C) 2003-2014 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "mathutils.h"
+#include "spectral/fft.h"
+#include "spectral/phasevoc.h"
+
+/** phasevocoder internal object */
+struct _aubio_pvoc_t {
+ uint_t win_s; /** grain length */
+ uint_t hop_s; /** overlap step */
+ aubio_fft_t * fft; /** fft object */
+ fvec_t * data; /** current input grain, [win_s] frames */
+ fvec_t * dataold; /** memory of past grain, [win_s-hop_s] frames */
+ fvec_t * synth; /** current output grain, [win_s] frames */
+ fvec_t * synthold; /** memory of past grain, [win_s-hop_s] frames */
+ fvec_t * w; /** grain window [win_s] */
+ uint_t start; /** where to start additive synthesis */
+ uint_t end; /** where to end it */
+ smpl_t scale; /** scaling factor for synthesis */
+ uint_t end_datasize; /** size of memory to end */
+ uint_t hop_datasize; /** size of memory to hop_s */
+};
+
+
+/** returns data and dataold slided by hop_s */
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new);
+
+/** do additive synthesis from 'old' and 'cur' */
+static void aubio_pvoc_addsynth(aubio_pvoc_t *pv, fvec_t * synthnew);
+
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t * datanew, cvec_t *fftgrain) {
+ /* slide */
+ aubio_pvoc_swapbuffers(pv, datanew);
+ /* windowing */
+ fvec_weight(pv->data, pv->w);
+ /* shift */
+ fvec_shift(pv->data);
+ /* calculate fft */
+ aubio_fft_do (pv->fft,pv->data,fftgrain);
+}
+
+void aubio_pvoc_rdo(aubio_pvoc_t *pv,cvec_t * fftgrain, fvec_t * synthnew) {
+ /* calculate rfft */
+ aubio_fft_rdo(pv->fft,fftgrain,pv->synth);
+ /* unshift */
+ fvec_ishift(pv->synth);
+ /* windowing */
+ // if overlap = 50%, do not apply window (identity)
+ if (pv->hop_s * 2 < pv->win_s) {
+ fvec_weight(pv->synth, pv->w);
+ }
+ /* additive synthesis */
+ aubio_pvoc_addsynth(pv, synthnew);
+}
+
+aubio_pvoc_t * new_aubio_pvoc (uint_t win_s, uint_t hop_s) {
+ aubio_pvoc_t * pv = AUBIO_NEW(aubio_pvoc_t);
+
+ /* if (win_s < 2*hop_s) {
+ AUBIO_WRN("Hop size bigger than half the window size!\n");
+ } */
+
+ if ((sint_t)hop_s < 1) {
+ AUBIO_ERR("pvoc: got hop_size %d, but can not be < 1\n", hop_s);
+ goto beach;
+ } else if ((sint_t)win_s < 2) {
+ AUBIO_ERR("pvoc: got buffer_size %d, but can not be < 2\n", win_s);
+ goto beach;
+ } else if (win_s < hop_s) {
+ AUBIO_ERR("pvoc: hop size (%d) is larger than win size (%d)\n", hop_s, win_s);
+ goto beach;
+ }
+
+ pv->fft = new_aubio_fft (win_s);
+ if (pv->fft == NULL) {
+ goto beach;
+ }
+
+ /* remember old */
+ pv->data = new_fvec (win_s);
+ pv->synth = new_fvec (win_s);
+
+ /* new input output */
+ if (win_s > hop_s) {
+ pv->dataold = new_fvec (win_s-hop_s);
+ pv->synthold = new_fvec (win_s-hop_s);
+ } else {
+ pv->dataold = new_fvec (1);
+ pv->synthold = new_fvec (1);
+ }
+ pv->w = new_aubio_window ("hanningz", win_s);
+
+ pv->hop_s = hop_s;
+ pv->win_s = win_s;
+
+ /* more than 50% overlap, overlap anyway */
+ if (win_s < 2 * hop_s) pv->start = 0;
+ /* less than 50% overlap, reset latest grain trail */
+ else pv->start = win_s - hop_s - hop_s;
+
+ if (win_s > hop_s) pv->end = win_s - hop_s;
+ else pv->end = 0;
+
+ pv->end_datasize = pv->end * sizeof(smpl_t);
+ pv->hop_datasize = pv->hop_s * sizeof(smpl_t);
+
+ // for reconstruction with 75% overlap
+ if (win_s == hop_s * 4) {
+ pv->scale = 2./3.;
+ } else if (win_s == hop_s * 8) {
+ pv->scale = 1./3.;
+ } else if (win_s == hop_s * 2) {
+ pv->scale = 1.;
+ } else {
+ pv->scale = .5;
+ }
+
+ return pv;
+
+beach:
+ AUBIO_FREE (pv);
+ return NULL;
+}
+
+uint_t aubio_pvoc_set_window(aubio_pvoc_t *pv, const char_t *window) {
+ return fvec_set_window(pv->w, (char_t*)window);
+}
+
+void del_aubio_pvoc(aubio_pvoc_t *pv) {
+ del_fvec(pv->data);
+ del_fvec(pv->synth);
+ del_fvec(pv->dataold);
+ del_fvec(pv->synthold);
+ del_fvec(pv->w);
+ del_aubio_fft(pv->fft);
+ AUBIO_FREE(pv);
+}
+
+static void aubio_pvoc_swapbuffers(aubio_pvoc_t *pv, const fvec_t *new)
+{
+ /* some convenience pointers */
+ smpl_t * data = pv->data->data;
+ smpl_t * dataold = pv->dataold->data;
+ smpl_t * datanew = new->data;
+#ifndef HAVE_MEMCPY_HACKS
+ uint_t i;
+ for (i = 0; i < pv->end; i++)
+ data[i] = dataold[i];
+ for (i = 0; i < pv->hop_s; i++)
+ data[pv->end + i] = datanew[i];
+ for (i = 0; i < pv->end; i++)
+ dataold[i] = data[i + pv->hop_s];
+#else
+ memcpy(data, dataold, pv->end_datasize);
+ data += pv->end;
+ memcpy(data, datanew, pv->hop_datasize);
+ data -= pv->end;
+ data += pv->hop_s;
+ memcpy(dataold, data, pv->end_datasize);
+#endif
+}
+
+static void aubio_pvoc_addsynth(aubio_pvoc_t *pv, fvec_t *synth_new)
+{
+ uint_t i;
+ /* some convenience pointers */
+ smpl_t * synth = pv->synth->data;
+ smpl_t * synthold = pv->synthold->data;
+ smpl_t * synthnew = synth_new->data;
+
+ /* put new result in synthnew */
+ for (i = 0; i < pv->hop_s; i++)
+ synthnew[i] = synth[i] * pv->scale;
+
+ /* no overlap, nothing else to do */
+ if (pv->end == 0) return;
+
+ /* add new synth to old one */
+ for (i = 0; i < pv->hop_s; i++)
+ synthnew[i] += synthold[i];
+
+ /* shift synthold */
+ for (i = 0; i < pv->start; i++)
+ synthold[i] = synthold[i + pv->hop_s];
+
+ /* erase last frame in synthold */
+ for (i = pv->start; i < pv->end; i++)
+ synthold[i] = 0.;
+
+ /* additive synth */
+ for (i = 0; i < pv->end; i++)
+ synthold[i] += synth[i + pv->hop_s] * pv->scale;
+}
+
+uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv)
+{
+ return pv->win_s;
+}
+
+uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv)
+{
+ return pv->hop_s;
+}
diff --git a/aubio/src/spectral/phasevoc.h b/aubio/src/spectral/phasevoc.h
new file mode 100644
index 00000000..e3caf2de
--- /dev/null
+++ b/aubio/src/spectral/phasevoc.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Phase vocoder object
+
+ This object implements a phase vocoder. The spectral frames are computed
+ using a HanningZ window and a swapped version of the signal to simplify the
+ phase relationships across frames. The window sizes and overlap are specified
+ at creation time.
+
+ \example spectral/test-phasevoc.c
+
+*/
+
+#ifndef AUBIO_PHASEVOC_H
+#define AUBIO_PHASEVOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** phasevocoder object */
+typedef struct _aubio_pvoc_t aubio_pvoc_t;
+
+/** create phase vocoder object
+
+ \param win_s size of analysis buffer (and length the FFT transform)
+ \param hop_s step size between two consecutive analysis
+
+*/
+aubio_pvoc_t * new_aubio_pvoc (uint_t win_s, uint_t hop_s);
+/** delete phase vocoder object
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+
+*/
+void del_aubio_pvoc(aubio_pvoc_t *pv);
+
+/** compute spectral frame
+
+ This function accepts an input vector of size [hop_s]. The
+ analysis buffer is rotated and filled with the new data. After windowing of
+ this signal window, the Fourier transform is computed and returned in
+ fftgrain as two vectors, magnitude and phase.
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+ \param in new input signal (hop_s long)
+ \param fftgrain output spectral frame
+
+*/
+void aubio_pvoc_do(aubio_pvoc_t *pv, const fvec_t *in, cvec_t * fftgrain);
+/** compute signal from spectral frame
+
+ This function takes an input spectral frame fftgrain of size
+ [buf_s] and computes its inverse Fourier transform. Overlap-add
+ synthesis is then computed using the previously synthetised frames, and the
+ output stored in out.
+
+ \param pv phase vocoder object as returned by new_aubio_pvoc
+ \param fftgrain input spectral frame
+ \param out output signal (hop_s long)
+
+*/
+void aubio_pvoc_rdo(aubio_pvoc_t *pv, cvec_t * fftgrain, fvec_t *out);
+
+/** get window size
+
+ \param pv phase vocoder to get the window size from
+
+*/
+uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv);
+
+/** get hop size
+
+ \param pv phase vocoder to get the hop size from
+
+*/
+uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv);
+
+/** set window type
+
+ \param pv phase vocoder to set the window type
+ \param window_type a string representing a window
+
+ \return 0 if successful, non-zero otherwise
+
+ */
+uint_t aubio_pvoc_set_window(aubio_pvoc_t *pv, const char_t *window_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PHASEVOC_H */
diff --git a/aubio/src/spectral/specdesc.c b/aubio/src/spectral/specdesc.c
new file mode 100644
index 00000000..cc1665a3
--- /dev/null
+++ b/aubio/src/spectral/specdesc.c
@@ -0,0 +1,429 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/fft.h"
+#include "spectral/specdesc.h"
+#include "mathutils.h"
+#include "utils/hist.h"
+
+void aubio_specdesc_energy(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_hfc(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_complex(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_phase(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_wphase(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specdiff(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset);
+
+extern void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+extern void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+
+/** onsetdetection types */
+typedef enum {
+ aubio_onset_energy, /**< energy based */
+ aubio_onset_specdiff, /**< spectral diff */
+ aubio_onset_hfc, /**< high frequency content */
+ aubio_onset_complex, /**< complex domain */
+ aubio_onset_phase, /**< phase fast */
+ aubio_onset_wphase, /**< weighted phase */
+ aubio_onset_kl, /**< Kullback Liebler */
+ aubio_onset_mkl, /**< modified Kullback Liebler */
+ aubio_onset_specflux, /**< spectral flux */
+ aubio_specmethod_centroid, /**< spectral centroid */
+ aubio_specmethod_spread, /**< spectral spread */
+ aubio_specmethod_skewness, /**< spectral skewness */
+ aubio_specmethod_kurtosis, /**< spectral kurtosis */
+ aubio_specmethod_slope, /**< spectral kurtosis */
+ aubio_specmethod_decrease, /**< spectral decrease */
+ aubio_specmethod_rolloff, /**< spectral rolloff */
+ aubio_onset_default = aubio_onset_hfc, /**< default mode, set to hfc */
+} aubio_specdesc_type;
+
+/** structure to store object state */
+struct _aubio_specdesc_t {
+ aubio_specdesc_type onset_type; /**< onset detection type */
+ /** Pointer to aubio_specdesc_ function */
+ void (*funcpointer)(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset);
+ smpl_t threshold; /**< minimum norm threshold for phase and specdiff */
+ fvec_t *oldmag; /**< previous norm vector */
+ fvec_t *dev1 ; /**< current onset detection measure vector */
+ fvec_t *theta1; /**< previous phase vector, one frame behind */
+ fvec_t *theta2; /**< previous phase vector, two frames behind */
+ aubio_hist_t * histog; /**< histogram */
+};
+
+
+/* Energy based onset detection function */
+void aubio_specdesc_energy (aubio_specdesc_t *o UNUSED,
+ const cvec_t * fftgrain, fvec_t * onset) {
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;jlength;j++) {
+ onset->data[0] += SQR(fftgrain->norm[j]);
+ }
+}
+
+/* High Frequency Content onset detection function */
+void aubio_specdesc_hfc(aubio_specdesc_t *o UNUSED,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;jlength;j++) {
+ onset->data[0] += (j+1)*fftgrain->norm[j];
+ }
+}
+
+
+/* Complex Domain Method onset detection function */
+void aubio_specdesc_complex (aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset) {
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.;
+ for (j=0;jdev1->data[j] = 2. * o->theta1->data[j] - o->theta2->data[j];
+ // compute the euclidean distance in the complex domain
+ // sqrt ( r_1^2 + r_2^2 - 2 * r_1 * r_2 * \cos ( \phi_1 - \phi_2 ) )
+ onset->data[0] +=
+ SQRT (ABS (SQR (o->oldmag->data[j]) + SQR (fftgrain->norm[j])
+ - 2 * o->oldmag->data[j] * fftgrain->norm[j]
+ * COS (o->dev1->data[j] - fftgrain->phas[j])));
+ /* swap old phase data (need to remember 2 frames behind)*/
+ o->theta2->data[j] = o->theta1->data[j];
+ o->theta1->data[j] = fftgrain->phas[j];
+ /* swap old magnitude data (1 frame is enough) */
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+}
+
+
+/* Phase Based Method onset detection function */
+void aubio_specdesc_phase(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.0;
+ o->dev1->data[0]=0.;
+ for ( j=0;jdev1->data[j] =
+ aubio_unwrap2pi(
+ fftgrain->phas[j]
+ -2.0*o->theta1->data[j]
+ +o->theta2->data[j]);
+ if ( o->threshold < fftgrain->norm[j] )
+ o->dev1->data[j] = ABS(o->dev1->data[j]);
+ else
+ o->dev1->data[j] = 0.0;
+ /* keep a track of the past frames */
+ o->theta2->data[j] = o->theta1->data[j];
+ o->theta1->data[j] = fftgrain->phas[j];
+ }
+ /* apply o->histogram */
+ aubio_hist_dyn_notnull(o->histog,o->dev1);
+ /* weight it */
+ aubio_hist_weight(o->histog);
+ /* its mean is the result */
+ onset->data[0] = aubio_hist_mean(o->histog);
+ //onset->data[0] = fvec_mean(o->dev1);
+}
+
+/* weighted phase */
+void
+aubio_specdesc_wphase(aubio_specdesc_t *o,
+ const cvec_t *fftgrain, fvec_t *onset) {
+ uint_t i;
+ aubio_specdesc_phase(o, fftgrain, onset);
+ for (i = 0; i < fftgrain->length; i++) {
+ o->dev1->data[i] *= fftgrain->norm[i];
+ }
+ /* apply o->histogram */
+ aubio_hist_dyn_notnull(o->histog,o->dev1);
+ /* weight it */
+ aubio_hist_weight(o->histog);
+ /* its mean is the result */
+ onset->data[0] = aubio_hist_mean(o->histog);
+}
+
+/* Spectral difference method onset detection function */
+void aubio_specdesc_specdiff(aubio_specdesc_t *o,
+ const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ uint_t nbins = fftgrain->length;
+ onset->data[0] = 0.0;
+ for (j=0;jdev1->data[j] = SQRT(
+ ABS(SQR( fftgrain->norm[j])
+ - SQR(o->oldmag->data[j])));
+ if (o->threshold < fftgrain->norm[j] )
+ o->dev1->data[j] = ABS(o->dev1->data[j]);
+ else
+ o->dev1->data[j] = 0.0;
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+
+ /* apply o->histogram (act somewhat as a low pass on the
+ * overall function)*/
+ aubio_hist_dyn_notnull(o->histog,o->dev1);
+ /* weight it */
+ aubio_hist_weight(o->histog);
+ /* its mean is the result */
+ onset->data[0] = aubio_hist_mean(o->histog);
+}
+
+/* Kullback Liebler onset detection function
+ * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
+ * negative (1.+) and infinite values (+1.e-10) */
+void aubio_specdesc_kl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;jlength;j++) {
+ onset->data[0] += fftgrain->norm[j]
+ *LOG(1.+fftgrain->norm[j]/(o->oldmag->data[j]+1.e-1));
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+ if (isnan(onset->data[0])) onset->data[0] = 0.;
+}
+
+/* Modified Kullback Liebler onset detection function
+ * note we use ln(1+Xn/(Xn-1+0.0001)) to avoid
+ * negative (1.+) and infinite values (+1.e-10) */
+void aubio_specdesc_mkl(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;jlength;j++) {
+ onset->data[0] += LOG(1.+fftgrain->norm[j]/(o->oldmag->data[j]+1.e-1));
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+ if (isnan(onset->data[0])) onset->data[0] = 0.;
+}
+
+/* Spectral flux */
+void aubio_specdesc_specflux(aubio_specdesc_t *o, const cvec_t * fftgrain, fvec_t * onset){
+ uint_t j;
+ onset->data[0] = 0.;
+ for (j=0;jlength;j++) {
+ if (fftgrain->norm[j] > o->oldmag->data[j])
+ onset->data[0] += fftgrain->norm[j] - o->oldmag->data[j];
+ o->oldmag->data[j] = fftgrain->norm[j];
+ }
+}
+
+/* Generic function pointing to the choosen one */
+void
+aubio_specdesc_do (aubio_specdesc_t *o, const cvec_t * fftgrain,
+ fvec_t * onset) {
+ o->funcpointer(o,fftgrain,onset);
+}
+
+/* Allocate memory for an onset detection
+ * depending on the choosen type, allocate memory as needed
+ */
+aubio_specdesc_t *
+new_aubio_specdesc (const char_t * onset_mode, uint_t size){
+ aubio_specdesc_t * o = AUBIO_NEW(aubio_specdesc_t);
+ uint_t rsize = size/2+1;
+ aubio_specdesc_type onset_type;
+ if (strcmp (onset_mode, "energy") == 0)
+ onset_type = aubio_onset_energy;
+ else if (strcmp (onset_mode, "specdiff") == 0)
+ onset_type = aubio_onset_specdiff;
+ else if (strcmp (onset_mode, "hfc") == 0)
+ onset_type = aubio_onset_hfc;
+ else if (strcmp (onset_mode, "complexdomain") == 0)
+ onset_type = aubio_onset_complex;
+ else if (strcmp (onset_mode, "complex") == 0)
+ onset_type = aubio_onset_complex;
+ else if (strcmp (onset_mode, "phase") == 0)
+ onset_type = aubio_onset_phase;
+ else if (strcmp (onset_mode, "wphase") == 0)
+ onset_type = aubio_onset_wphase;
+ else if (strcmp (onset_mode, "mkl") == 0)
+ onset_type = aubio_onset_mkl;
+ else if (strcmp (onset_mode, "kl") == 0)
+ onset_type = aubio_onset_kl;
+ else if (strcmp (onset_mode, "specflux") == 0)
+ onset_type = aubio_onset_specflux;
+ else if (strcmp (onset_mode, "centroid") == 0)
+ onset_type = aubio_specmethod_centroid;
+ else if (strcmp (onset_mode, "spread") == 0)
+ onset_type = aubio_specmethod_spread;
+ else if (strcmp (onset_mode, "skewness") == 0)
+ onset_type = aubio_specmethod_skewness;
+ else if (strcmp (onset_mode, "kurtosis") == 0)
+ onset_type = aubio_specmethod_kurtosis;
+ else if (strcmp (onset_mode, "slope") == 0)
+ onset_type = aubio_specmethod_slope;
+ else if (strcmp (onset_mode, "decrease") == 0)
+ onset_type = aubio_specmethod_decrease;
+ else if (strcmp (onset_mode, "rolloff") == 0)
+ onset_type = aubio_specmethod_rolloff;
+ else if (strcmp (onset_mode, "old_default") == 0)
+ onset_type = aubio_onset_default;
+ else if (strcmp (onset_mode, "default") == 0)
+ onset_type = aubio_onset_default;
+ else {
+ AUBIO_ERR("specdesc: unknown spectral descriptor type '%s'\n",
+ onset_mode);
+ AUBIO_FREE(o);
+ return NULL;
+ }
+ switch(onset_type) {
+ /* for both energy and hfc, only fftgrain->norm is required */
+ case aubio_onset_energy:
+ break;
+ case aubio_onset_hfc:
+ break;
+ /* the other approaches will need some more memory spaces */
+ case aubio_onset_complex:
+ o->oldmag = new_fvec(rsize);
+ o->dev1 = new_fvec(rsize);
+ o->theta1 = new_fvec(rsize);
+ o->theta2 = new_fvec(rsize);
+ break;
+ case aubio_onset_phase:
+ case aubio_onset_wphase:
+ o->dev1 = new_fvec(rsize);
+ o->theta1 = new_fvec(rsize);
+ o->theta2 = new_fvec(rsize);
+ o->histog = new_aubio_hist(0.0, PI, 10);
+ o->threshold = 0.1;
+ break;
+ case aubio_onset_specdiff:
+ o->oldmag = new_fvec(rsize);
+ o->dev1 = new_fvec(rsize);
+ o->histog = new_aubio_hist(0.0, PI, 10);
+ o->threshold = 0.1;
+ break;
+ case aubio_onset_kl:
+ case aubio_onset_mkl:
+ case aubio_onset_specflux:
+ o->oldmag = new_fvec(rsize);
+ break;
+ default:
+ break;
+ }
+
+ switch(onset_type) {
+ case aubio_onset_energy:
+ o->funcpointer = aubio_specdesc_energy;
+ break;
+ case aubio_onset_hfc:
+ o->funcpointer = aubio_specdesc_hfc;
+ break;
+ case aubio_onset_complex:
+ o->funcpointer = aubio_specdesc_complex;
+ break;
+ case aubio_onset_phase:
+ o->funcpointer = aubio_specdesc_phase;
+ break;
+ case aubio_onset_wphase:
+ o->funcpointer = aubio_specdesc_wphase;
+ break;
+ case aubio_onset_specdiff:
+ o->funcpointer = aubio_specdesc_specdiff;
+ break;
+ case aubio_onset_kl:
+ o->funcpointer = aubio_specdesc_kl;
+ break;
+ case aubio_onset_mkl:
+ o->funcpointer = aubio_specdesc_mkl;
+ break;
+ case aubio_onset_specflux:
+ o->funcpointer = aubio_specdesc_specflux;
+ break;
+ case aubio_specmethod_centroid:
+ o->funcpointer = aubio_specdesc_centroid;
+ break;
+ case aubio_specmethod_spread:
+ o->funcpointer = aubio_specdesc_spread;
+ break;
+ case aubio_specmethod_skewness:
+ o->funcpointer = aubio_specdesc_skewness;
+ break;
+ case aubio_specmethod_kurtosis:
+ o->funcpointer = aubio_specdesc_kurtosis;
+ break;
+ case aubio_specmethod_slope:
+ o->funcpointer = aubio_specdesc_slope;
+ break;
+ case aubio_specmethod_decrease:
+ o->funcpointer = aubio_specdesc_decrease;
+ break;
+ case aubio_specmethod_rolloff:
+ o->funcpointer = aubio_specdesc_rolloff;
+ break;
+ default:
+ break;
+ }
+ o->onset_type = onset_type;
+ return o;
+}
+
+void del_aubio_specdesc (aubio_specdesc_t *o){
+ switch(o->onset_type) {
+ case aubio_onset_energy:
+ break;
+ case aubio_onset_hfc:
+ break;
+ case aubio_onset_complex:
+ del_fvec(o->oldmag);
+ del_fvec(o->dev1);
+ del_fvec(o->theta1);
+ del_fvec(o->theta2);
+ break;
+ case aubio_onset_phase:
+ case aubio_onset_wphase:
+ del_fvec(o->dev1);
+ del_fvec(o->theta1);
+ del_fvec(o->theta2);
+ del_aubio_hist(o->histog);
+ break;
+ case aubio_onset_specdiff:
+ del_fvec(o->oldmag);
+ del_fvec(o->dev1);
+ del_aubio_hist(o->histog);
+ break;
+ case aubio_onset_kl:
+ case aubio_onset_mkl:
+ case aubio_onset_specflux:
+ del_fvec(o->oldmag);
+ break;
+ default:
+ break;
+ }
+ AUBIO_FREE(o);
+}
diff --git a/aubio/src/spectral/specdesc.h b/aubio/src/spectral/specdesc.h
new file mode 100644
index 00000000..0f688c14
--- /dev/null
+++ b/aubio/src/spectral/specdesc.h
@@ -0,0 +1,204 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Spectral description functions
+
+ All of the following spectral description functions take as arguments the FFT
+ of a windowed signal (as created with aubio_pvoc). They output one smpl_t per
+ buffer (stored in a vector of size [1]).
+
+ \section specdesc Spectral description functions
+
+ A list of the spectral description methods currently available follows.
+
+ \subsection onsetdesc Onset detection functions
+
+ These functions are designed to raise at notes attacks in music signals.
+
+ \b \p energy : Energy based onset detection function
+
+ This function calculates the local energy of the input spectral frame.
+
+ \b \p hfc : High Frequency Content onset detection function
+
+ This method computes the High Frequency Content (HFC) of the input spectral
+ frame. The resulting function is efficient at detecting percussive onsets.
+
+ Paul Masri. Computer modeling of Sound for Transformation and Synthesis of
+ Musical Signal. PhD dissertation, University of Bristol, UK, 1996.
+
+ \b \p complex : Complex Domain Method onset detection function
+
+ Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain
+ onset detection for musical signals. In Proceedings of the Digital Audio
+ Effects Conference, DAFx-03, pages 90-93, London, UK, 2003.
+
+ \b \p phase : Phase Based Method onset detection function
+
+ Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset
+ detection for music signals. In Proceedings of the IEEE International
+ Conference on Acoustics Speech and Signal Processing, pages 441444,
+ Hong-Kong, 2003.
+
+ \b \p wphase : Weighted Phase Deviation onset detection function
+
+ S. Dixon. Onset detection revisited. In Proceedings of the 9th International
+ Conference on Digital Audio Ef- fects (DAFx) , pages 133–137, 2006.
+
+ http://www.eecs.qmul.ac.uk/~simond/pub/2006/dafx.pdf
+
+ \b \p specdiff : Spectral difference method onset detection function
+
+ Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
+ rhythm analysis. In IEEE International Conference on Multimedia and Expo
+ (ICME 2001), pages 881884, Tokyo, Japan, August 2001.
+
+ \b \p kl : Kullback-Liebler onset detection function
+
+ Stephen Hainsworth and Malcom Macleod. Onset detection in music audio
+ signals. In Proceedings of the International Computer Music Conference
+ (ICMC), Singapore, 2003.
+
+ \b \p mkl : Modified Kullback-Liebler onset detection function
+
+ Paul Brossier, ``Automatic annotation of musical audio for interactive
+ systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital
+ music, Queen Mary University of London, London, UK, 2006.
+
+ \b \p specflux : Spectral Flux
+
+ Simon Dixon, Onset Detection Revisited, in ``Proceedings of the 9th
+ International Conference on Digital Audio Effects'' (DAFx-06), Montreal,
+ Canada, 2006.
+
+ \subsection shapedesc Spectral shape descriptors
+
+ The following descriptors are described in:
+
+ Geoffroy Peeters, A large set of audio features for sound description
+ (similarity and classification) in the CUIDADO project, CUIDADO I.S.T.
+ Project Report 2004 (pdf)
+
+ \b \p centroid : Spectral centroid
+
+ The spectral centroid represents the barycenter of the spectrum.
+
+ \e Note: This function returns the result in bin. To get the spectral
+ centroid in Hz, aubio_bintofreq() should be used.
+
+ \b \p spread : Spectral spread
+
+ The spectral spread is the variance of the spectral distribution around its
+ centroid.
+
+ See also Standard
+ deviation on Wikipedia.
+
+ \b \p skewness : Spectral skewness
+
+ Similarly, the skewness is computed from the third order moment of the
+ spectrum. A negative skewness indicates more energy on the lower part of the
+ spectrum. A positive skewness indicates more energy on the high frequency of
+ the spectrum.
+
+ See also Skewness on
+ Wikipedia.
+
+ \b \p kurtosis : Spectral kurtosis
+
+ The kurtosis is a measure of the flatness of the spectrum, computed from the
+ fourth order moment.
+
+ See also Kurtosis on
+ Wikipedia.
+
+ \b \p slope : Spectral slope
+
+ The spectral slope represents decreasing rate of the spectral amplitude,
+ computed using a linear regression.
+
+ \b \p decrease : Spectral decrease
+
+ The spectral decrease is another representation of the decreasing rate,
+ based on perceptual criteria.
+
+ \b \p rolloff : Spectral roll-off
+
+ This function returns the bin number below which 95% of the spectrum energy
+ is found.
+
+ \example spectral/test-specdesc.c
+
+*/
+
+
+#ifndef AUBIO_SPECDESC_H
+#define AUBIO_SPECDESC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** spectral description structure */
+typedef struct _aubio_specdesc_t aubio_specdesc_t;
+
+/** execute spectral description function on a spectral frame
+
+ Generic function to compute spectral description.
+
+ \param o spectral description object as returned by new_aubio_specdesc()
+ \param fftgrain input signal spectrum as computed by aubio_pvoc_do
+ \param desc output vector (one sample long, to send to the peak picking)
+
+*/
+void aubio_specdesc_do (aubio_specdesc_t * o, const cvec_t * fftgrain,
+ fvec_t * desc);
+
+/** creation of a spectral description object
+
+ \param method spectral description method
+ \param buf_size length of the input spectrum frame
+
+ The parameter \p method is a string that can be any of:
+
+ - onset novelty functions: `complex`, `energy`, `hfc`, `kl`, `mkl`,
+ `phase`, `specdiff`, `specflux`, `wphase`,
+
+ - spectral descriptors: `centroid`, `decrease`, `kurtosis`, `rolloff`,
+ `skewness`, `slope`, `spread`.
+
+*/
+aubio_specdesc_t *new_aubio_specdesc (const char_t * method, uint_t buf_size);
+
+/** deletion of a spectral descriptor
+
+ \param o spectral descriptor object as returned by new_aubio_specdesc()
+
+*/
+void del_aubio_specdesc (aubio_specdesc_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SPECDESC_H */
diff --git a/aubio/src/spectral/statistics.c b/aubio/src/spectral/statistics.c
new file mode 100644
index 00000000..d3033643
--- /dev/null
+++ b/aubio/src/spectral/statistics.c
@@ -0,0 +1,204 @@
+/*
+ Copyright (C) 2007-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+
+void aubio_specdesc_centroid (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_spread (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_skewness (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_kurtosis (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_slope (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_decrease (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+void aubio_specdesc_rolloff (aubio_specdesc_t * o, const cvec_t * spec,
+ fvec_t * desc);
+
+
+smpl_t cvec_sum (const cvec_t * s);
+smpl_t cvec_mean (const cvec_t * s);
+smpl_t cvec_centroid (const cvec_t * s);
+smpl_t cvec_moment (const cvec_t * s, uint_t moment);
+
+smpl_t
+cvec_sum (const cvec_t * s)
+{
+ uint_t j;
+ smpl_t tmp = 0.0;
+ for (j = 0; j < s->length; j++) {
+ tmp += s->norm[j];
+ }
+ return tmp;
+}
+
+smpl_t
+cvec_mean (const cvec_t * s)
+{
+ return cvec_sum (s) / (smpl_t) (s->length);
+}
+
+smpl_t
+cvec_centroid (const cvec_t * spec)
+{
+ smpl_t sum = 0., sc = 0.;
+ uint_t j;
+ sum = cvec_sum (spec);
+ if (sum == 0.) {
+ return 0.;
+ } else {
+ for (j = 0; j < spec->length; j++) {
+ sc += (smpl_t) j *spec->norm[j];
+ }
+ return sc / sum;
+ }
+}
+
+smpl_t
+cvec_moment (const cvec_t * spec, uint_t order)
+{
+ smpl_t sum = 0., centroid = 0., sc = 0.;
+ uint_t j;
+ sum = cvec_sum (spec);
+ if (sum == 0.) {
+ return 0.;
+ } else {
+ centroid = cvec_centroid (spec);
+ for (j = 0; j < spec->length; j++) {
+ sc += (smpl_t) POW(j - centroid, order) * spec->norm[j];
+ }
+ return sc / sum;
+ }
+}
+
+void
+aubio_specdesc_centroid (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ desc->data[0] = cvec_centroid (spec);
+}
+
+void
+aubio_specdesc_spread (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ desc->data[0] = cvec_moment (spec, 2);
+}
+
+void
+aubio_specdesc_skewness (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ smpl_t spread;
+ spread = cvec_moment (spec, 2);
+ if (spread == 0) {
+ desc->data[0] = 0.;
+ } else {
+ desc->data[0] = cvec_moment (spec, 3);
+ desc->data[0] /= POW ( SQRT (spread), 3);
+ }
+}
+
+void
+aubio_specdesc_kurtosis (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ smpl_t spread;
+ spread = cvec_moment (spec, 2);
+ if (spread == 0) {
+ desc->data[0] = 0.;
+ } else {
+ desc->data[0] = cvec_moment (spec, 4);
+ desc->data[0] /= SQR (spread);
+ }
+}
+
+void
+aubio_specdesc_slope (aubio_specdesc_t * o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ uint_t j;
+ smpl_t norm = 0, sum = 0.;
+ // compute N * sum(j**2) - sum(j)**2
+ for (j = 0; j < spec->length; j++) {
+ norm += j*j;
+ }
+ norm *= spec->length;
+ // sum_0^N(j) = length * (length + 1) / 2
+ norm -= SQR( (spec->length) * (spec->length - 1.) / 2. );
+ sum = cvec_sum (spec);
+ desc->data[0] = 0.;
+ if (sum == 0.) {
+ return;
+ } else {
+ for (j = 0; j < spec->length; j++) {
+ desc->data[0] += j * spec->norm[j];
+ }
+ desc->data[0] *= spec->length;
+ desc->data[0] -= sum * spec->length * (spec->length - 1) / 2.;
+ desc->data[0] /= norm;
+ desc->data[0] /= sum;
+ }
+}
+
+void
+aubio_specdesc_decrease (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
+ fvec_t * desc)
+{
+ uint_t j; smpl_t sum;
+ sum = cvec_sum (spec);
+ desc->data[0] = 0;
+ if (sum == 0.) {
+ return;
+ } else {
+ sum -= spec->norm[0];
+ for (j = 1; j < spec->length; j++) {
+ desc->data[0] += (spec->norm[j] - spec->norm[0]) / j;
+ }
+ desc->data[0] /= sum;
+ }
+}
+
+void
+aubio_specdesc_rolloff (aubio_specdesc_t *o UNUSED, const cvec_t * spec,
+ fvec_t *desc)
+{
+ uint_t j; smpl_t cumsum, rollsum;
+ cumsum = 0.; rollsum = 0.;
+ for (j = 0; j < spec->length; j++) {
+ cumsum += SQR (spec->norm[j]);
+ }
+ if (cumsum == 0) {
+ desc->data[0] = 0.;
+ } else {
+ cumsum *= 0.95;
+ j = 0;
+ while (rollsum < cumsum) {
+ rollsum += SQR (spec->norm[j]);
+ j++;
+ }
+ desc->data[0] = MAX (1, j) - 1.0f;
+ }
+}
diff --git a/aubio/src/spectral/tss.h b/aubio/src/spectral/tss.h
new file mode 100644
index 00000000..a4f54a15
--- /dev/null
+++ b/aubio/src/spectral/tss.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Transient / Steady-state Separation (TSS)
+
+ This file implement a Transient / Steady-state Separation (TSS) as described
+ in:
+
+ Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Separation of
+ transient information in musical audio using multiresolution analysis
+ techniques. In Proceedings of the Digital Audio Effects Conference, DAFx-01,
+ pages 1--5, Limerick, Ireland, 2001.
+
+ Available at http://www.csis.ul.ie/dafx01/proceedings/papers/duxbury.pdf
+
+ \example spectral/test-tss.c
+
+*/
+
+#ifndef AUBIO_TSS_H
+#define AUBIO_TSS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Transient / Steady-state Separation object */
+typedef struct _aubio_tss_t aubio_tss_t;
+
+/** create tss object
+
+ \param buf_size buffer size
+ \param hop_size step size
+
+*/
+aubio_tss_t *new_aubio_tss (uint_t buf_size, uint_t hop_size);
+
+/** delete tss object
+
+ \param o tss object as returned by new_aubio_tss()
+
+*/
+void del_aubio_tss (aubio_tss_t * o);
+
+/** split input into transient and steady states components
+
+ \param o tss object as returned by new_aubio_tss()
+ \param input input spectral frame
+ \param trans output transient components
+ \param stead output steady state components
+
+*/
+void aubio_tss_do (aubio_tss_t * o, const cvec_t * input, cvec_t * trans,
+ cvec_t * stead);
+
+/** set transient / steady state separation threshold
+
+ \param o tss object as returned by new_aubio_tss()
+ \param thrs new threshold value
+
+*/
+uint_t aubio_tss_set_threshold (aubio_tss_t * o, smpl_t thrs);
+
+/** set parameter a, defaults to 3
+
+ \param o tss object as returned by new_aubio_tss()
+ \param alpha new value for alpha parameter
+
+*/
+uint_t aubio_tss_set_alpha (aubio_tss_t * o, smpl_t alpha);
+
+/** set parameter b, defaults to 3
+
+ \param o tss object as returned by new_aubio_tss()
+ \param beta new value for beta parameter
+
+*/
+uint_t aubio_tss_set_beta (aubio_tss_t * o, smpl_t beta);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TSS_H */
diff --git a/aubio/src/synth/sampler.h b/aubio/src/synth/sampler.h
new file mode 100644
index 00000000..fb1304f3
--- /dev/null
+++ b/aubio/src/synth/sampler.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_SAMPLER_H
+#define AUBIO_SAMPLER_H
+
+/** \file
+
+ Load and play sound files.
+
+ This file loads a sample and gets ready to play it.
+
+ The `_do` function adds the new samples to the input, and write the result as
+ the output.
+
+ \example synth/test-sampler.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** sampler object */
+typedef struct _aubio_sampler_t aubio_sampler_t;
+
+/** create new sampler object
+
+ \param samplerate the sampling rate of the new sampler
+ \param hop_size the block size of the new sampler
+
+ \return the newly created ::aubio_sampler_t
+
+*/
+aubio_sampler_t * new_aubio_sampler(uint_t samplerate, uint_t hop_size);
+
+/** load source in sampler
+
+ \param o sampler, created by new_aubio_sampler()
+ \param uri the uri of the source to load
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri );
+
+/** process sampler function
+
+ \param o sampler, created by new_aubio_sampler()
+ \param input input of the sampler, to be added to the output
+ \param output output of the sampler
+
+This function adds the new samples from the playing source to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output);
+
+/** process sampler function, multiple channels
+
+ \param o sampler, created by new_aubio_sampler()
+ \param input input of the sampler, to be added to the output
+ \param output output of the sampler
+
+This function adds the new samples from the playing source to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output);
+
+/** get current playing state
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if not playing, 1 if playing
+
+*/
+uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o );
+
+/** set current playing state
+
+ \param o sampler, created by new_aubio_sampler()
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_set_playing ( aubio_sampler_t * o, uint_t playing );
+
+/** play sample from start
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_play ( aubio_sampler_t * o );
+
+/** stop sample
+
+ \param o sampler, created by new_aubio_sampler()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_sampler_stop ( aubio_sampler_t * o );
+
+/** destroy ::aubio_sampler_t object
+
+ \param o sampler, created by new_aubio_sampler()
+
+*/
+void del_aubio_sampler( aubio_sampler_t * o );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SAMPLER_H */
diff --git a/aubio/src/synth/wavetable.h b/aubio/src/synth/wavetable.h
new file mode 100644
index 00000000..7607fbe5
--- /dev/null
+++ b/aubio/src/synth/wavetable.h
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_WAVETABLE_H
+#define AUBIO_WAVETABLE_H
+
+/** \file
+
+ Wavetable synthesis.
+
+ This file creates a wavetable and plays it at different frequency.
+
+ The `_do` function adds the new samples to the input, and write the result as
+ the output.
+
+ \example synth/test-wavetable.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** wavetable object */
+typedef struct _aubio_wavetable_t aubio_wavetable_t;
+
+/** create new wavetable object
+
+ \param samplerate the sampling rate of the new wavetable
+ \param hop_size the block size of the new wavetable
+
+ \return the newly created aubio_wavetable_t
+
+*/
+aubio_wavetable_t * new_aubio_wavetable(uint_t samplerate, uint_t hop_size);
+
+/** load source in wavetable
+
+ TODO: This function is not implemented yet. See new_aubio_sampler() instead.
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param uri the uri of the source to load
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_wavetable_load( aubio_wavetable_t * o, const char_t * uri );
+
+/** process wavetable function
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing wavetable to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do ( aubio_wavetable_t * o, const fvec_t * input, fvec_t * output);
+
+/** process wavetable function, multiple channels
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing wavetable to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do_multi ( aubio_wavetable_t * o, const fmat_t * input, fmat_t * output);
+
+/** get current playing state
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if not playing, 1 if playing
+
+*/
+uint_t aubio_wavetable_get_playing ( const aubio_wavetable_t * o );
+
+/** set current playing state
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * o, uint_t playing );
+
+/** play sample from start
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_play ( aubio_wavetable_t * o );
+
+/** stop wavetable
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_stop ( aubio_wavetable_t * o );
+
+/** set wavetable frequency
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param freq new frequency value for the wavetable
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * o, smpl_t freq );
+
+/** get wavetable frequency
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return current frequency, in Hz
+
+*/
+smpl_t aubio_wavetable_get_freq ( const aubio_wavetable_t * o);
+
+/** set wavetable amplitude
+
+ \param o wavetable, created by new_aubio_wavetable()
+ \param amp new amplitude value for the wavetable
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * o, smpl_t amp );
+
+/** get wavetable amplitude
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+ \return current amplitude
+
+*/
+smpl_t aubio_wavetable_get_amp ( const aubio_wavetable_t * o);
+
+/** destroy aubio_wavetable_t object
+
+ \param o wavetable, created by new_aubio_wavetable()
+
+*/
+void del_aubio_wavetable( aubio_wavetable_t * o );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_WAVETABLE_H */
diff --git a/aubio/src/tempo/beattracking.c b/aubio/src/tempo/beattracking.c
new file mode 100644
index 00000000..96483f01
--- /dev/null
+++ b/aubio/src/tempo/beattracking.c
@@ -0,0 +1,449 @@
+/*
+ Copyright (C) 2005-2009 Matthew Davies and Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "mathutils.h"
+#include "tempo/beattracking.h"
+
+/** define to 1 to print out tracking difficulties */
+#define AUBIO_BEAT_WARNINGS 0
+
+uint_t fvec_gettimesig (fvec_t * acf, uint_t acflen, uint_t gp);
+void aubio_beattracking_checkstate (aubio_beattracking_t * bt);
+
+struct _aubio_beattracking_t
+{
+ uint_t hop_size; /** length of one tempo detection function sample, in audio samples */
+ uint_t samplerate; /** samplerate of the original signal */
+ fvec_t *rwv; /** rayleigh weighting for beat period in general model */
+ fvec_t *dfwv; /** exponential weighting for beat alignment in general model */
+ fvec_t *gwv; /** gaussian weighting for beat period in context dependant model */
+ fvec_t *phwv; /** gaussian weighting for beat alignment in context dependant model */
+ fvec_t *dfrev; /** reversed onset detection function */
+ fvec_t *acf; /** vector for autocorrelation function (of current detection function frame) */
+ fvec_t *acfout; /** store result of passing acf through s.i.c.f.b. */
+ fvec_t *phout;
+ uint_t timesig; /** time signature of input, set to zero until context dependent model activated */
+ uint_t step;
+ uint_t rayparam; /** Rayleigh parameter */
+ smpl_t lastbeat;
+ sint_t counter;
+ uint_t flagstep;
+ smpl_t g_var;
+ smpl_t gp;
+ smpl_t bp;
+ smpl_t rp;
+ smpl_t rp1;
+ smpl_t rp2;
+};
+
+aubio_beattracking_t *
+new_aubio_beattracking (uint_t winlen, uint_t hop_size, uint_t samplerate)
+{
+
+ aubio_beattracking_t *p = AUBIO_NEW (aubio_beattracking_t);
+ uint_t i = 0;
+ /* default value for rayleigh weighting - sets preferred tempo to 120bpm */
+ smpl_t rayparam = 60. * samplerate / 120. / hop_size;
+ smpl_t dfwvnorm = EXP ((LOG (2.0) / rayparam) * (winlen + 2));
+ /* length over which beat period is found [128] */
+ uint_t laglen = winlen / 4;
+ /* step increment - both in detection function samples -i.e. 11.6ms or
+ * 1 onset frame [128] */
+ uint_t step = winlen / 4; /* 1.5 seconds */
+
+ p->hop_size = hop_size;
+ p->samplerate = samplerate;
+ p->lastbeat = 0;
+ p->counter = 0;
+ p->flagstep = 0;
+ p->g_var = 3.901; // constthresh empirically derived!
+ p->rp = 1;
+ p->gp = 0;
+
+ p->rayparam = rayparam;
+ p->step = step;
+ p->rwv = new_fvec (laglen);
+ p->gwv = new_fvec (laglen);
+ p->dfwv = new_fvec (winlen);
+ p->dfrev = new_fvec (winlen);
+ p->acf = new_fvec (winlen);
+ p->acfout = new_fvec (laglen);
+ p->phwv = new_fvec (2 * laglen);
+ p->phout = new_fvec (winlen);
+
+ p->timesig = 0;
+
+ /* exponential weighting, dfwv = 0.5 when i = 43 */
+ for (i = 0; i < winlen; i++) {
+ p->dfwv->data[i] = (EXP ((LOG (2.0) / rayparam) * (i + 1)))
+ / dfwvnorm;
+ }
+
+ for (i = 0; i < (laglen); i++) {
+ p->rwv->data[i] = ((smpl_t) (i + 1.) / SQR ((smpl_t) rayparam)) *
+ EXP ((-SQR ((smpl_t) (i + 1.)) / (2. * SQR ((smpl_t) rayparam))));
+ }
+
+ return p;
+
+}
+
+void
+del_aubio_beattracking (aubio_beattracking_t * p)
+{
+ del_fvec (p->rwv);
+ del_fvec (p->gwv);
+ del_fvec (p->dfwv);
+ del_fvec (p->dfrev);
+ del_fvec (p->acf);
+ del_fvec (p->acfout);
+ del_fvec (p->phwv);
+ del_fvec (p->phout);
+ AUBIO_FREE (p);
+}
+
+
+void
+aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframe,
+ fvec_t * output)
+{
+
+ uint_t i, k;
+ uint_t step = bt->step;
+ uint_t laglen = bt->rwv->length;
+ uint_t winlen = bt->dfwv->length;
+ uint_t maxindex = 0;
+ //number of harmonics in shift invariant comb filterbank
+ uint_t numelem = 4;
+
+ smpl_t phase; // beat alignment (step - lastbeat)
+ smpl_t beat; // beat position
+ smpl_t bp; // beat period
+ uint_t a, b; // used to build shift invariant comb filterbank
+ uint_t kmax; // number of elements used to find beat phase
+
+ /* copy dfframe, apply detection function weighting, and revert */
+ fvec_copy (dfframe, bt->dfrev);
+ fvec_weight (bt->dfrev, bt->dfwv);
+ fvec_rev (bt->dfrev);
+
+ /* compute autocorrelation function */
+ aubio_autocorr (dfframe, bt->acf);
+
+ /* if timesig is unknown, use metrically unbiased version of filterbank */
+ if (!bt->timesig) {
+ numelem = 4;
+ } else {
+ numelem = bt->timesig;
+ }
+
+ /* first and last output values are left intentionally as zero */
+ fvec_zeros (bt->acfout);
+
+ /* compute shift invariant comb filterbank */
+ for (i = 1; i < laglen - 1; i++) {
+ for (a = 1; a <= numelem; a++) {
+ for (b = 1; b < 2 * a; b++) {
+ bt->acfout->data[i] += bt->acf->data[i * a + b - 1]
+ * 1. / (2. * a - 1.);
+ }
+ }
+ }
+ /* apply Rayleigh weight */
+ fvec_weight (bt->acfout, bt->rwv);
+
+ /* find non-zero Rayleigh period */
+ maxindex = fvec_max_elem (bt->acfout);
+ if (maxindex > 0 && maxindex < bt->acfout->length - 1) {
+ bt->rp = fvec_quadratic_peak_pos (bt->acfout, maxindex);
+ } else {
+ bt->rp = bt->rayparam;
+ }
+
+ /* activate biased filterbank */
+ aubio_beattracking_checkstate (bt);
+#if 0 // debug metronome mode
+ bt->bp = 36.9142;
+#endif
+ bp = bt->bp;
+ /* end of biased filterbank */
+
+ if (bp == 0) {
+ fvec_zeros(output);
+ return;
+ }
+
+ /* deliberate integer operation, could be set to 3 max eventually */
+ kmax = FLOOR (winlen / bp);
+
+ /* initialize output */
+ fvec_zeros (bt->phout);
+ for (i = 0; i < bp; i++) {
+ for (k = 0; k < kmax; k++) {
+ uint_t idx = i + (uint_t) ROUND (bp * k);
+ if (idx < bt->dfrev->length)
+ bt->phout->data[i] += bt->dfrev->data[idx];
+#if AUBIO_BEAT_WARNINGS
+ else
+ AUBIO_WRN ("[tempo] out of bounds index %d", idx);
+#endif
+ }
+ }
+ fvec_weight (bt->phout, bt->phwv);
+
+ /* find Rayleigh period */
+ maxindex = fvec_max_elem (bt->phout);
+ if (maxindex >= winlen - 1) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("no idea what this groove's phase is\n");
+#endif /* AUBIO_BEAT_WARNINGS */
+ phase = step - bt->lastbeat;
+ } else {
+ phase = fvec_quadratic_peak_pos (bt->phout, maxindex);
+ }
+ /* take back one frame delay */
+ phase += 1.;
+#if 0 // debug metronome mode
+ phase = step - bt->lastbeat;
+#endif
+
+ /* reset output */
+ fvec_zeros (output);
+
+ i = 1;
+ beat = bp - phase;
+
+ // AUBIO_DBG ("bp: %f, phase: %f, lastbeat: %f, step: %d, winlen: %d\n",
+ // bp, phase, bt->lastbeat, step, winlen);
+
+ /* the next beat will be earlier than 60% of the tempo period
+ skip this one */
+ if ( ( step - bt->lastbeat - phase ) < -0.40 * bp ) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("back off-beat error, skipping this beat\n");
+#endif /* AUBIO_BEAT_WARNINGS */
+ beat += bp;
+ }
+
+ /* start counting the beats */
+ while (beat + bp < 0) {
+ beat += bp;
+ }
+
+ if (beat >= 0) {
+ //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat);
+ output->data[i] = beat;
+ i++;
+ }
+
+ while (beat + bp <= step) {
+ beat += bp;
+ //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat);
+ output->data[i] = beat;
+ i++;
+ }
+
+ bt->lastbeat = beat;
+ /* store the number of beats in this frame as the first element */
+ output->data[0] = i;
+}
+
+uint_t
+fvec_gettimesig (fvec_t * acf, uint_t acflen, uint_t gp)
+{
+ sint_t k = 0;
+ smpl_t three_energy = 0., four_energy = 0.;
+ if (gp < 2) return 4;
+ if (acflen > 6 * gp + 2) {
+ for (k = -2; k < 2; k++) {
+ three_energy += acf->data[3 * gp + k];
+ four_energy += acf->data[4 * gp + k];
+ }
+ } else {
+ /*Expanded to be more accurate in time sig estimation */
+ for (k = -2; k < 2; k++) {
+ three_energy += acf->data[3 * gp + k] + acf->data[6 * gp + k];
+ four_energy += acf->data[4 * gp + k] + acf->data[2 * gp + k];
+ }
+ }
+ return (three_energy > four_energy) ? 3 : 4;
+}
+
+void
+aubio_beattracking_checkstate (aubio_beattracking_t * bt)
+{
+ uint_t i, j, a, b;
+ uint_t flagconst = 0;
+ sint_t counter = bt->counter;
+ uint_t flagstep = bt->flagstep;
+ smpl_t gp = bt->gp;
+ smpl_t bp = bt->bp;
+ smpl_t rp = bt->rp;
+ smpl_t rp1 = bt->rp1;
+ smpl_t rp2 = bt->rp2;
+ uint_t laglen = bt->rwv->length;
+ uint_t acflen = bt->acf->length;
+ uint_t step = bt->step;
+ fvec_t *acf = bt->acf;
+ fvec_t *acfout = bt->acfout;
+
+ if (gp) {
+ // compute shift invariant comb filterbank
+ fvec_zeros (acfout);
+ for (i = 1; i < laglen - 1; i++) {
+ for (a = 1; a <= bt->timesig; a++) {
+ for (b = 1; b < 2 * a; b++) {
+ acfout->data[i] += acf->data[i * a + b - 1];
+ }
+ }
+ }
+ // since gp is set, gwv has been computed in previous checkstate
+ fvec_weight (acfout, bt->gwv);
+ gp = fvec_quadratic_peak_pos (acfout, fvec_max_elem (acfout));
+ } else {
+ //still only using general model
+ gp = 0;
+ }
+
+ //now look for step change - i.e. a difference between gp and rp that
+ // is greater than 2*constthresh - always true in first case, since gp = 0
+ if (counter == 0) {
+ if (ABS (gp - rp) > 2. * bt->g_var) {
+ flagstep = 1; // have observed step change.
+ counter = 3; // setup 3 frame counter
+ } else {
+ flagstep = 0;
+ }
+ }
+ //i.e. 3rd frame after flagstep initially set
+ if (counter == 1 && flagstep == 1) {
+ //check for consistency between previous beatperiod values
+ if (ABS (2 * rp - rp1 - rp2) < bt->g_var) {
+ //if true, can activate context dependent model
+ flagconst = 1;
+ counter = 0; // reset counter and flagstep
+ } else {
+ //if not consistent, then don't flag consistency!
+ flagconst = 0;
+ counter = 2; // let it look next time
+ }
+ } else if (counter > 0) {
+ //if counter doesn't = 1,
+ counter = counter - 1;
+ }
+
+ rp2 = rp1;
+ rp1 = rp;
+
+ if (flagconst) {
+ /* first run of new hypothesis */
+ gp = rp;
+ bt->timesig = fvec_gettimesig (acf, acflen, gp);
+ for (j = 0; j < laglen; j++)
+ bt->gwv->data[j] =
+ EXP (-.5 * SQR ((smpl_t) (j + 1. - gp)) / SQR (bt->g_var));
+ flagconst = 0;
+ bp = gp;
+ /* flat phase weighting */
+ fvec_ones (bt->phwv);
+ } else if (bt->timesig) {
+ /* context dependant model */
+ bp = gp;
+ /* gaussian phase weighting */
+ if (step > bt->lastbeat) {
+ for (j = 0; j < 2 * laglen; j++) {
+ bt->phwv->data[j] =
+ EXP (-.5 * SQR ((smpl_t) (1. + j - step +
+ bt->lastbeat)) / (bp / 8.));
+ }
+ } else {
+ //AUBIO_DBG("NOT using phase weighting as step is %d and lastbeat %d \n",
+ // step,bt->lastbeat);
+ fvec_ones (bt->phwv);
+ }
+ } else {
+ /* initial state */
+ bp = rp;
+ /* flat phase weighting */
+ fvec_ones (bt->phwv);
+ }
+
+ /* do some further checks on the final bp value */
+
+ /* if tempo is > 206 bpm, half it */
+ while (0 < bp && bp < 25) {
+#if AUBIO_BEAT_WARNINGS
+ AUBIO_WRN ("doubling from %f (%f bpm) to %f (%f bpm)\n",
+ bp, 60.*44100./512./bp, bp/2., 60.*44100./512./bp/2. );
+ //AUBIO_DBG("warning, halving the tempo from %f\n", 60.*samplerate/hopsize/bp);
+#endif /* AUBIO_BEAT_WARNINGS */
+ bp = bp * 2;
+ }
+
+ //AUBIO_DBG("tempo:\t%3.5f bpm | ", 5168./bp);
+
+ /* smoothing */
+ //bp = (uint_t) (0.8 * (smpl_t)bp + 0.2 * (smpl_t)bp2);
+ //AUBIO_DBG("tempo:\t%3.5f bpm smoothed | bp2 %d | bp %d | ", 5168./bp, bp2, bp);
+ //bp2 = bp;
+ //AUBIO_DBG("time signature: %d \n", bt->timesig);
+ bt->counter = counter;
+ bt->flagstep = flagstep;
+ bt->gp = gp;
+ bt->bp = bp;
+ bt->rp1 = rp1;
+ bt->rp2 = rp2;
+}
+
+smpl_t
+aubio_beattracking_get_period (const aubio_beattracking_t * bt)
+{
+ return bt->hop_size * bt->bp;
+}
+
+smpl_t
+aubio_beattracking_get_period_s (const aubio_beattracking_t * bt)
+{
+ return aubio_beattracking_get_period(bt) / (smpl_t) bt->samplerate;
+}
+
+smpl_t
+aubio_beattracking_get_bpm (const aubio_beattracking_t * bt)
+{
+ if (bt->bp != 0) {
+ return 60. / aubio_beattracking_get_period_s(bt);
+ } else {
+ return 0.;
+ }
+}
+
+smpl_t
+aubio_beattracking_get_confidence (const aubio_beattracking_t * bt)
+{
+ if (bt->gp) {
+ smpl_t acf_sum = fvec_sum(bt->acfout);
+ if (acf_sum != 0.) {
+ return fvec_quadratic_peak_mag (bt->acfout, bt->gp) / acf_sum;
+ }
+ }
+ return 0.;
+}
diff --git a/aubio/src/tempo/beattracking.h b/aubio/src/tempo/beattracking.h
new file mode 100644
index 00000000..bc95a738
--- /dev/null
+++ b/aubio/src/tempo/beattracking.h
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2003-2015 Matthew Davies and Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Beat tracking using a context dependant model
+
+ This file implements the causal beat tracking algorithm designed by Matthew
+ Davies and described in the following articles:
+
+ Matthew E. P. Davies and Mark D. Plumbley. Causal tempo tracking of audio.
+ In Proceedings of the International Symposium on Music Information Retrieval
+ (ISMIR), pages 164169, Barcelona, Spain, 2004.
+
+ Matthew E. P. Davies, Paul Brossier, and Mark D. Plumbley. Beat tracking
+ towards automatic musical accompaniment. In Proceedings of the Audio
+ Engineering Society 118th Convention, Barcelona, Spain, May 2005.
+
+ \example tempo/test-beattracking.c
+
+*/
+#ifndef AUBIO_BEATTRACKING_H
+#define AUBIO_BEATTRACKING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** beat tracking object */
+typedef struct _aubio_beattracking_t aubio_beattracking_t;
+
+/** create beat tracking object
+
+ \param winlen length of the onset detection window
+ \param hop_size number of onset detection samples [512]
+ \param samplerate samplerate of the input signal
+
+*/
+aubio_beattracking_t * new_aubio_beattracking(uint_t winlen, uint_t hop_size,
+ uint_t samplerate);
+
+/** track the beat
+
+ \param bt beat tracking object
+ \param dfframes current input detection function frame, smoothed by
+ adaptive median threshold.
+ \param out stored detected beat locations
+
+*/
+void aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframes,
+ fvec_t * out);
+
+/** get current beat period in samples
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in samples, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_beattracking_get_period (const aubio_beattracking_t * bt);
+
+/** get current beat period in seconds
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in seconds, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_beattracking_get_period_s (const aubio_beattracking_t * bt);
+
+/** get current tempo in bpm
+
+ \param bt beat tracking object
+
+ Returns the currently observed tempo, in beats per minutes, or 0 if no
+ consistent value is found.
+
+*/
+smpl_t aubio_beattracking_get_bpm(const aubio_beattracking_t * bt);
+
+/** get current tempo confidence
+
+ \param bt beat tracking object
+
+ Returns the confidence with which the tempo has been observed, 0 if no
+ consistent value is found.
+
+*/
+smpl_t aubio_beattracking_get_confidence(const aubio_beattracking_t * bt);
+
+/** delete beat tracking object
+
+ \param p beat tracking object
+
+*/
+void del_aubio_beattracking(aubio_beattracking_t * p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_BEATTRACKING_H */
diff --git a/aubio/src/tempo/tempo.c b/aubio/src/tempo/tempo.c
new file mode 100644
index 00000000..5698b2bb
--- /dev/null
+++ b/aubio/src/tempo/tempo.c
@@ -0,0 +1,304 @@
+/*
+ Copyright (C) 2006-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "spectral/specdesc.h"
+#include "tempo/beattracking.h"
+#include "spectral/phasevoc.h"
+#include "onset/peakpicker.h"
+#include "mathutils.h"
+#include "tempo/tempo.h"
+
+/* structure to store object state */
+struct _aubio_tempo_t {
+ aubio_specdesc_t * od; /** onset detection */
+ aubio_pvoc_t * pv; /** phase vocoder */
+ aubio_peakpicker_t * pp; /** peak picker */
+ aubio_beattracking_t * bt; /** beat tracking */
+ cvec_t * fftgrain; /** spectral frame */
+ fvec_t * of; /** onset detection function value */
+ fvec_t * dfframe; /** peak picked detection function buffer */
+ fvec_t * out; /** beat tactus candidates */
+ fvec_t * onset; /** onset results */
+ smpl_t silence; /** silence parameter */
+ smpl_t threshold; /** peak picking threshold */
+ sint_t blockpos; /** current position in dfframe */
+ uint_t winlen; /** dfframe bufsize */
+ uint_t step; /** dfframe hopsize */
+ uint_t samplerate; /** sampling rate of the signal */
+ uint_t hop_size; /** get hop_size */
+ uint_t total_frames; /** total frames since beginning */
+ uint_t last_beat; /** time of latest detected beat, in samples */
+ sint_t delay; /** delay to remove to last beat, in samples */
+ uint_t last_tatum; /** time of latest detected tatum, in samples */
+ uint_t tatum_signature; /** number of tatum between each beats */
+};
+
+/* execute tempo detection function on iput buffer */
+void aubio_tempo_do(aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo)
+{
+ uint_t i;
+ uint_t winlen = o->winlen;
+ uint_t step = o->step;
+ fvec_t * thresholded;
+ aubio_pvoc_do (o->pv, input, o->fftgrain);
+ aubio_specdesc_do (o->od, o->fftgrain, o->of);
+ /*if (usedoubled) {
+ aubio_specdesc_do(o2,fftgrain, onset2);
+ onset->data[0] *= onset2->data[0];
+ }*/
+ /* execute every overlap_size*step */
+ if (o->blockpos == (signed)step -1 ) {
+ /* check dfframe */
+ aubio_beattracking_do(o->bt,o->dfframe,o->out);
+ /* rotate dfframe */
+ for (i = 0 ; i < winlen - step; i++ )
+ o->dfframe->data[i] = o->dfframe->data[i+step];
+ for (i = winlen - step ; i < winlen; i++ )
+ o->dfframe->data[i] = 0.;
+ o->blockpos = -1;
+ }
+ o->blockpos++;
+ aubio_peakpicker_do (o->pp, o->of, o->onset);
+ // store onset detection function in second sample of vector
+ //tempo->data[1] = o->onset->data[0];
+ thresholded = aubio_peakpicker_get_thresholded_input(o->pp);
+ o->dfframe->data[winlen - step + o->blockpos] = thresholded->data[0];
+ /* end of second level loop */
+ tempo->data[0] = 0; /* reset tactus */
+ //i=0;
+ for (i = 1; i < o->out->data[0]; i++ ) {
+ /* if current frame is a predicted tactus */
+ if (o->blockpos == FLOOR(o->out->data[i])) {
+ tempo->data[0] = o->out->data[i] - FLOOR(o->out->data[i]); /* set tactus */
+ /* test for silence */
+ if (aubio_silence_detection(input, o->silence)==1) {
+ tempo->data[0] = 0; // unset beat if silent
+ }
+ o->last_beat = o->total_frames + (uint_t)ROUND(tempo->data[0] * o->hop_size);
+ o->last_tatum = o->last_beat;
+ }
+ }
+ o->total_frames += o->hop_size;
+ return;
+}
+
+uint_t aubio_tempo_get_last (aubio_tempo_t *o)
+{
+ return o->last_beat + o->delay;
+}
+
+smpl_t aubio_tempo_get_last_s (aubio_tempo_t *o)
+{
+ return aubio_tempo_get_last (o) / (smpl_t) (o->samplerate);
+}
+
+smpl_t aubio_tempo_get_last_ms (aubio_tempo_t *o)
+{
+ return aubio_tempo_get_last_s (o) * 1000.;
+}
+
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay) {
+ o->delay = delay;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay) {
+ o->delay = delay * o->samplerate;
+ return AUBIO_OK;
+}
+
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay) {
+ return aubio_tempo_set_delay_s(o, delay / 1000.);
+}
+
+uint_t aubio_tempo_get_delay(aubio_tempo_t * o) {
+ return o->delay;
+}
+
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o) {
+ return o->delay / (smpl_t)(o->samplerate);
+}
+
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o) {
+ return aubio_tempo_get_delay_s(o) * 1000.;
+}
+
+uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence) {
+ o->silence = silence;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_tempo_get_silence(aubio_tempo_t * o) {
+ return o->silence;
+}
+
+uint_t aubio_tempo_set_threshold(aubio_tempo_t * o, smpl_t threshold) {
+ o->threshold = threshold;
+ aubio_peakpicker_set_threshold(o->pp, o->threshold);
+ return AUBIO_OK;
+}
+
+smpl_t aubio_tempo_get_threshold(aubio_tempo_t * o) {
+ return o->threshold;
+}
+
+/* Allocate memory for an tempo detection */
+aubio_tempo_t * new_aubio_tempo (const char_t * tempo_mode,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate)
+{
+ aubio_tempo_t * o = AUBIO_NEW(aubio_tempo_t);
+ char_t specdesc_func[PATH_MAX];
+ o->samplerate = samplerate;
+ // check parameters are valid
+ if ((sint_t)hop_size < 1) {
+ AUBIO_ERR("tempo: got hop size %d, but can not be < 1\n", hop_size);
+ goto beach;
+ } else if ((sint_t)buf_size < 2) {
+ AUBIO_ERR("tempo: got window size %d, but can not be < 2\n", buf_size);
+ goto beach;
+ } else if (buf_size < hop_size) {
+ AUBIO_ERR("tempo: hop size (%d) is larger than window size (%d)\n", buf_size, hop_size);
+ goto beach;
+ } else if ((sint_t)samplerate < 1) {
+ AUBIO_ERR("tempo: samplerate (%d) can not be < 1\n", samplerate);
+ goto beach;
+ }
+
+ /* length of observations, worth about 6 seconds */
+ o->winlen = aubio_next_power_of_two(5.8 * samplerate / hop_size);
+ if (o->winlen < 4) o->winlen = 4;
+ o->step = o->winlen/4;
+ o->blockpos = 0;
+ o->threshold = 0.3;
+ o->silence = -90.;
+ o->total_frames = 0;
+ o->last_beat = 0;
+ o->delay = 0;
+ o->hop_size = hop_size;
+ o->dfframe = new_fvec(o->winlen);
+ o->fftgrain = new_cvec(buf_size);
+ o->out = new_fvec(o->step);
+ o->pv = new_aubio_pvoc(buf_size, hop_size);
+ o->pp = new_aubio_peakpicker();
+ aubio_peakpicker_set_threshold (o->pp, o->threshold);
+ if ( strcmp(tempo_mode, "default") == 0 ) {
+ strncpy(specdesc_func, "specflux", PATH_MAX - 1);
+ } else {
+ strncpy(specdesc_func, tempo_mode, PATH_MAX - 1);
+ specdesc_func[PATH_MAX - 1] = '\0';
+ }
+ o->od = new_aubio_specdesc(specdesc_func,buf_size);
+ o->of = new_fvec(1);
+ o->bt = new_aubio_beattracking(o->winlen, o->hop_size, o->samplerate);
+ o->onset = new_fvec(1);
+ /*if (usedoubled) {
+ o2 = new_aubio_specdesc(type_onset2,buffer_size);
+ onset2 = new_fvec(1);
+ }*/
+ if (!o->dfframe || !o->fftgrain || !o->out || !o->pv ||
+ !o->pp || !o->od || !o->of || !o->bt || !o->onset) {
+ AUBIO_ERR("tempo: failed creating tempo object\n");
+ goto beach;
+ }
+ o->last_tatum = 0;
+ o->tatum_signature = 4;
+ return o;
+
+beach:
+ del_aubio_tempo(o);
+ return NULL;
+}
+
+smpl_t aubio_tempo_get_bpm(aubio_tempo_t *o) {
+ return aubio_beattracking_get_bpm(o->bt);
+}
+
+smpl_t aubio_tempo_get_period (aubio_tempo_t *o)
+{
+ return aubio_beattracking_get_period (o->bt);
+}
+
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t *o)
+{
+ return aubio_beattracking_get_period_s (o->bt);
+}
+
+smpl_t aubio_tempo_get_confidence(aubio_tempo_t *o) {
+ return aubio_beattracking_get_confidence(o->bt);
+}
+
+uint_t aubio_tempo_was_tatum (aubio_tempo_t *o)
+{
+ uint_t last_tatum_distance = o->total_frames - o->last_tatum;
+ smpl_t beat_period = aubio_tempo_get_period(o);
+ smpl_t tatum_period = beat_period / o->tatum_signature;
+ if (last_tatum_distance < o->hop_size) {
+ o->last_tatum = o->last_beat;
+ return 2;
+ }
+ else if (last_tatum_distance > tatum_period) {
+ if ( last_tatum_distance + o->hop_size > beat_period ) {
+ // next beat is too close, pass
+ return 0;
+ }
+ o->last_tatum = o->total_frames;
+ return 1;
+ }
+ return 0;
+}
+
+smpl_t aubio_tempo_get_last_tatum (aubio_tempo_t *o) {
+ return (smpl_t)o->last_tatum - o->delay;
+}
+
+uint_t aubio_tempo_set_tatum_signature (aubio_tempo_t *o, uint_t signature) {
+ if (signature < 1 || signature > 64) {
+ return AUBIO_FAIL;
+ } else {
+ o->tatum_signature = signature;
+ return AUBIO_OK;
+ }
+}
+
+void del_aubio_tempo (aubio_tempo_t *o)
+{
+ if (o->od)
+ del_aubio_specdesc(o->od);
+ if (o->bt)
+ del_aubio_beattracking(o->bt);
+ if (o->pp)
+ del_aubio_peakpicker(o->pp);
+ if (o->pv)
+ del_aubio_pvoc(o->pv);
+ if (o->out)
+ del_fvec(o->out);
+ if (o->of)
+ del_fvec(o->of);
+ if (o->fftgrain)
+ del_cvec(o->fftgrain);
+ if (o->dfframe)
+ del_fvec(o->dfframe);
+ if (o->onset)
+ del_fvec(o->onset);
+ AUBIO_FREE(o);
+}
diff --git a/aubio/src/tempo/tempo.h b/aubio/src/tempo/tempo.h
new file mode 100644
index 00000000..e2afe99c
--- /dev/null
+++ b/aubio/src/tempo/tempo.h
@@ -0,0 +1,255 @@
+/*
+ Copyright (C) 2006-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Tempo detection object
+
+ This object stores all the memory required for tempo detection algorithm
+ and returns the estimated beat locations.
+
+ \example tempo/test-tempo.c
+ \example examples/aubiotrack.c
+
+*/
+
+#ifndef AUBIO_TEMPO_H
+#define AUBIO_TEMPO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** tempo detection structure */
+typedef struct _aubio_tempo_t aubio_tempo_t;
+
+/** create tempo detection object
+
+ \param method beat tracking method, unused for now (use "default")
+ \param buf_size length of FFT
+ \param hop_size number of frames between two consecutive runs
+ \param samplerate sampling rate of the signal to analyze
+
+ \return newly created ::aubio_tempo_t if successful, `NULL` otherwise
+
+*/
+aubio_tempo_t * new_aubio_tempo (const char_t * method,
+ uint_t buf_size, uint_t hop_size, uint_t samplerate);
+
+/** execute tempo detection
+
+ \param o beat tracking object
+ \param input new samples
+ \param tempo output beats
+
+*/
+void aubio_tempo_do (aubio_tempo_t *o, const fvec_t * input, fvec_t * tempo);
+
+/** get the time of the latest beat detected, in samples
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+uint_t aubio_tempo_get_last (aubio_tempo_t *o);
+
+/** get the time of the latest beat detected, in seconds
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+smpl_t aubio_tempo_get_last_s (aubio_tempo_t *o);
+
+/** get the time of the latest beat detected, in milliseconds
+
+ \param o tempo detection object as returned by ::new_aubio_tempo
+
+*/
+smpl_t aubio_tempo_get_last_ms (aubio_tempo_t *o);
+
+/** set tempo detection silence threshold
+
+ \param o beat tracking object
+ \param silence new silence threshold, in dB
+
+ \return `0` if successful, non-zero otherwise
+
+*/
+uint_t aubio_tempo_set_silence(aubio_tempo_t * o, smpl_t silence);
+
+/** get tempo detection silence threshold
+
+ \param o tempo detection object as returned by new_aubio_tempo()
+
+ \return current silence threshold
+
+*/
+smpl_t aubio_tempo_get_silence(aubio_tempo_t * o);
+
+/** set tempo detection peak picking threshold
+
+ \param o beat tracking object
+ \param threshold new threshold
+
+ \return `0` if successful, non-zero otherwise
+
+*/
+uint_t aubio_tempo_set_threshold(aubio_tempo_t * o, smpl_t threshold);
+
+/** get tempo peak picking threshold
+
+ \param o tempo detection object as returned by new_aubio_tempo()
+
+ \return current tempo detection threshold
+
+*/
+smpl_t aubio_tempo_get_threshold(aubio_tempo_t * o);
+
+/** get current beat period in samples
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in samples, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_tempo_get_period (aubio_tempo_t * bt);
+
+/** get current beat period in seconds
+
+ \param bt beat tracking object
+
+ Returns the currently observed period, in seconds, or 0 if no consistent
+ value is found.
+
+*/
+smpl_t aubio_tempo_get_period_s (aubio_tempo_t * bt);
+
+/** get current tempo
+
+ \param o beat tracking object
+
+ \return the currently observed tempo, or `0` if no consistent value is found
+
+*/
+smpl_t aubio_tempo_get_bpm(aubio_tempo_t * o);
+
+/** get current tempo confidence
+
+ \param o beat tracking object
+
+ \return confidence with which the tempo has been observed, the higher the
+ more confidence, `0` if no consistent value is found.
+
+*/
+smpl_t aubio_tempo_get_confidence(aubio_tempo_t * o);
+
+/** set number of tatum per beat
+
+ \param o beat tracking object
+ \param signature number of tatum per beat (between 1 and 64)
+
+*/
+uint_t aubio_tempo_set_tatum_signature(aubio_tempo_t *o, uint_t signature);
+
+/** check whether a tatum was detected in the current frame
+
+ \param o beat tracking object
+
+ \return 2 if a beat was detected, 1 if a tatum was detected, 0 otherwise
+
+*/
+uint_t aubio_tempo_was_tatum(aubio_tempo_t *o);
+
+/** get position of last_tatum, in samples
+
+ \param o beat tracking object
+
+*/
+smpl_t aubio_tempo_get_last_tatum(aubio_tempo_t *o);
+
+/** get current delay
+
+ \param o beat tracking object
+
+ \return current delay, in samples
+
+ */
+uint_t aubio_tempo_get_delay(aubio_tempo_t * o);
+
+/** get current delay in seconds
+
+ \param o beat tracking object
+
+ \return current delay, in seconds
+
+ */
+smpl_t aubio_tempo_get_delay_s(aubio_tempo_t * o);
+
+/** get current delay in ms
+
+ \param o beat tracking object
+
+ \return current delay, in milliseconds
+
+ */
+smpl_t aubio_tempo_get_delay_ms(aubio_tempo_t * o);
+
+/** set current delay
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in samples
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay(aubio_tempo_t * o, sint_t delay);
+
+/** set current delay in seconds
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in seconds
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_s(aubio_tempo_t * o, smpl_t delay);
+
+/** set current delay
+
+ \param o beat tracking object
+ \param delay delay to set tempo to, in samples
+
+ \return `0` if successful, non-zero otherwise
+
+ */
+uint_t aubio_tempo_set_delay_ms(aubio_tempo_t * o, smpl_t delay);
+
+/** delete tempo detection object
+
+ \param o beat tracking object
+
+*/
+void del_aubio_tempo(aubio_tempo_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TEMPO_H */
diff --git a/aubio/src/temporal/a_weighting.c b/aubio/src/temporal/a_weighting.c
new file mode 100644
index 00000000..f19f566f
--- /dev/null
+++ b/aubio/src/temporal/a_weighting.c
@@ -0,0 +1,262 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/a_weighting.h"
+
+uint_t
+aubio_filter_set_a_weighting (aubio_filter_t * f, uint_t samplerate)
+{
+ uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
+
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERROR("aubio_filter: failed setting A-weighting with samplerate %d\n", samplerate);
+ return AUBIO_FAIL;
+ }
+ if (f == NULL) {
+ AUBIO_ERROR("aubio_filter: failed setting A-weighting with filter NULL\n");
+ return AUBIO_FAIL;
+ }
+
+ order = aubio_filter_get_order (f);
+ if (order != 7) {
+ AUBIO_ERROR ("aubio_filter: order of A-weighting filter must be 7, not %d\n", order);
+ return 1;
+ }
+
+ aubio_filter_set_samplerate (f, samplerate);
+ bs = aubio_filter_get_feedforward (f);
+ as = aubio_filter_get_feedback (f);
+ b = bs->data, a = as->data;
+
+ /* select coefficients according to sampling frequency */
+ switch (samplerate) {
+
+ case 8000:
+ b[0] = 6.306209468238731519207362907764036208391189575195312500e-01;
+ b[1] = -1.261241893647746525886077506584115326404571533203125000e+00;
+ b[2] = -6.306209468238730408984338282607495784759521484375000000e-01;
+ b[3] = 2.522483787295493051772155013168230652809143066406250000e+00;
+ b[4] = -6.306209468238730408984338282607495784759521484375000000e-01;
+ b[5] = -1.261241893647746525886077506584115326404571533203125000e+00;
+ b[6] = 6.306209468238731519207362907764036208391189575195312500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.128467193009123015201566886389628052711486816406250000e+00;
+ a[2] = 2.948668980101234460278192273108288645744323730468750000e-01;
+ a[3] = 1.824183830735050637628091863007284700870513916015625000e+00;
+ a[4] = -8.056628943119792385374466903158463537693023681640625000e-01;
+ a[5] = -3.947497982842933517133587884018197655677795410156250000e-01;
+ a[6] = 2.098548546080332977137317129745497368276119232177734375e-01;
+ break;
+
+ case 11025:
+ b[0] = 6.014684165832374640459079273568931967020034790039062500e-01;
+ b[1] = -1.202936833166475150136420779745094478130340576171875000e+00;
+ b[2] = -6.014684165832373530236054648412391543388366699218750000e-01;
+ b[3] = 2.405873666332950300272841559490188956260681152343750000e+00;
+ b[4] = -6.014684165832373530236054648412391543388366699218750000e-01;
+ b[5] = -1.202936833166475150136420779745094478130340576171875000e+00;
+ b[6] = 6.014684165832374640459079273568931967020034790039062500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.463578747722854345170162559952586889266967773437500000e+00;
+ a[2] = 1.096799662705210121060872552334330976009368896484375000e+00;
+ a[3] = 1.381222210556041218865175324026495218276977539062500000e+00;
+ a[4] = -1.013875696476876031582037285261321812868118286132812500e+00;
+ a[5] = -1.839132734476921215982514468123554252088069915771484375e-01;
+ a[6] = 1.833526393172056623281918064094497822225093841552734375e-01;
+ break;
+
+ case 16000:
+ b[0] = 5.314898298235570806014038680586963891983032226562500000e-01;
+ b[1] = -1.062979659647114161202807736117392778396606445312500000e+00;
+ b[2] = -5.314898298235570806014038680586963891983032226562500000e-01;
+ b[3] = 2.125959319294228322405615472234785556793212890625000000e+00;
+ b[4] = -5.314898298235570806014038680586963891983032226562500000e-01;
+ b[5] = -1.062979659647114161202807736117392778396606445312500000e+00;
+ b[6] = 5.314898298235570806014038680586963891983032226562500000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.867832572992162987191022693878039717674255371093750000e+00;
+ a[2] = 2.221144410202312347024644623161293566226959228515625000e+00;
+ a[3] = 4.552683347886614662058946123579517006874084472656250000e-01;
+ a[4] = -9.833868636162828025248927588108927011489868164062500000e-01;
+ a[5] = 5.592994142413361402521587706360151059925556182861328125e-02;
+ a[6] = 1.188781038285612462468421313133148942142724990844726562e-01;
+ break;
+
+ case 22050:
+ b[0] = 4.492998504299193784916610638902056962251663208007812500e-01;
+ b[1] = -8.985997008598388680056245902960654348134994506835937500e-01;
+ b[2] = -4.492998504299192674693586013745516538619995117187500000e-01;
+ b[3] = 1.797199401719677958055854105623438954353332519531250000e+00;
+ b[4] = -4.492998504299192674693586013745516538619995117187500000e-01;
+ b[5] = -8.985997008598388680056245902960654348134994506835937500e-01;
+ b[6] = 4.492998504299193784916610638902056962251663208007812500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.229078805225074955131958631682209670543670654296875000e+00;
+ a[2] = 3.354494881236033787530459449044428765773773193359375000e+00;
+ a[3] = -7.317843680657351024265722116979304701089859008789062500e-01;
+ a[4] = -6.271627581807257545420952737913466989994049072265625000e-01;
+ a[5] = 1.772142005020879151899748649157118052244186401367187500e-01;
+ a[6] = 5.631716697383508385410522123493137769401073455810546875e-02;
+ break;
+
+ case 24000:
+ b[0] = 4.256263892891054001488271296693710610270500183105468750e-01;
+ b[1] = -8.512527785782106892753517968230880796909332275390625000e-01;
+ b[2] = -4.256263892891054556599783609271980822086334228515625000e-01;
+ b[3] = 1.702505557156421378550703593646176159381866455078125000e+00;
+ b[4] = -4.256263892891054556599783609271980822086334228515625000e-01;
+ b[5] = -8.512527785782106892753517968230880796909332275390625000e-01;
+ b[6] = 4.256263892891054001488271296693710610270500183105468750e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.325996004241962733516402295208536088466644287109375000e+00;
+ a[2] = 3.677161079286316969216841243905946612358093261718750000e+00;
+ a[3] = -1.106476076828482035807610373012721538543701171875000000e+00;
+ a[4] = -4.726706734908718843257702246773988008499145507812500000e-01;
+ a[5] = 1.861941760230954034938122276798821985721588134765625000e-01;
+ a[6] = 4.178771337829546850262119050967157818377017974853515625e-02;
+ break;
+
+ case 32000:
+ b[0] = 3.434583386824304196416335344110848382115364074707031250e-01;
+ b[1] = -6.869166773648609503055695313378237187862396240234375000e-01;
+ b[2] = -3.434583386824303641304823031532578170299530029296875000e-01;
+ b[3] = 1.373833354729721900611139062675647437572479248046875000e+00;
+ b[4] = -3.434583386824303641304823031532578170299530029296875000e-01;
+ b[5] = -6.869166773648609503055695313378237187862396240234375000e-01;
+ b[6] = 3.434583386824304196416335344110848382115364074707031250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.656446043233668063976438133977353572845458984375000000e+00;
+ a[2] = 4.831468450652579349480220116674900054931640625000000000e+00;
+ a[3] = -2.557597496581567764195597192156128585338592529296875000e+00;
+ a[4] = 2.533680394205302666144064005493419244885444641113281250e-01;
+ a[5] = 1.224430322452567110325105659285327419638633728027343750e-01;
+ a[6] = 6.764072168342137418572956875095769646577537059783935547e-03;
+ break;
+
+ case 44100:
+ b[0] = 2.557411252042575133813784304948057979345321655273437500e-01;
+ b[1] = -5.114822504085150267627568609896115958690643310546875000e-01;
+ b[2] = -2.557411252042575133813784304948057979345321655273437500e-01;
+ b[3] = 1.022964500817030053525513721979223191738128662109375000e+00;
+ b[4] = -2.557411252042575133813784304948057979345321655273437500e-01;
+ b[5] = -5.114822504085150267627568609896115958690643310546875000e-01;
+ b[6] = 2.557411252042575133813784304948057979345321655273437500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.019576181115832369528106937650591135025024414062500000e+00;
+ a[2] = 6.189406442920693862674852425698190927505493164062500000e+00;
+ a[3] = -4.453198903544116404873420833609998226165771484375000000e+00;
+ a[4] = 1.420842949621876627475103305187076330184936523437500000e+00;
+ a[5] = -1.418254738303044160119270600262098014354705810546875000e-01;
+ a[6] = 4.351177233495117681327801761881346465088427066802978516e-03;
+ break;
+
+ case 48000:
+ b[0] = 2.343017922995132285013397677175817079842090606689453125e-01;
+ b[1] = -4.686035845990265125138307666929904371500015258789062500e-01;
+ b[2] = -2.343017922995132007457641520886681973934173583984375000e-01;
+ b[3] = 9.372071691980530250276615333859808743000030517578125000e-01;
+ b[4] = -2.343017922995132007457641520886681973934173583984375000e-01;
+ b[5] = -4.686035845990265125138307666929904371500015258789062500e-01;
+ b[6] = 2.343017922995132285013397677175817079842090606689453125e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.113043408775872045168853219365701079368591308593750000e+00;
+ a[2] = 6.553121752655050258340452273841947317123413085937500000e+00;
+ a[3] = -4.990849294163385074796224216697737574577331542968750000e+00;
+ a[4] = 1.785737302937575599059982778271660208702087402343750000e+00;
+ a[5] = -2.461905953194876706113802811159985139966011047363281250e-01;
+ a[6] = 1.122425003323123879339640041052916785702109336853027344e-02;
+ break;
+
+ case 88200:
+ b[0] = 1.118876366882113199130444058937428053468465805053710938e-01;
+ b[1] = -2.237752733764226120705131961585721001029014587402343750e-01;
+ b[2] = -1.118876366882113337908322137081995606422424316406250000e-01;
+ b[3] = 4.475505467528452241410263923171442002058029174804687500e-01;
+ b[4] = -1.118876366882113337908322137081995606422424316406250000e-01;
+ b[5] = -2.237752733764226120705131961585721001029014587402343750e-01;
+ b[6] = 1.118876366882113199130444058937428053468465805053710938e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.726938565651158441482948546763509511947631835937500000e+00;
+ a[2] = 9.076897983832765248735086061060428619384765625000000000e+00;
+ a[3] = -9.014855113464800950850985827855765819549560546875000000e+00;
+ a[4] = 4.852772261031594425162438710685819387435913085937500000e+00;
+ a[5] = -1.333877820398965186043938047077972441911697387695312500e+00;
+ a[6] = 1.460012549591642450064199465487035922706127166748046875e-01;
+ break;
+
+ case 96000:
+ b[0] = 9.951898975972744976203898659150581806898117065429687500e-02;
+ b[1] = -1.990379795194548995240779731830116361379623413085937500e-01;
+ b[2] = -9.951898975972744976203898659150581806898117065429687500e-02;
+ b[3] = 3.980759590389097990481559463660232722759246826171875000e-01;
+ b[4] = -9.951898975972744976203898659150581806898117065429687500e-02;
+ b[5] = -1.990379795194548995240779731830116361379623413085937500e-01;
+ b[6] = 9.951898975972744976203898659150581806898117065429687500e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -4.802203044225376693532325589330866932868957519531250000e+00;
+ a[2] = 9.401807218627226347962277941405773162841796875000000000e+00;
+ a[3] = -9.566143943569164420637207513209432363510131835937500000e+00;
+ a[4] = 5.309775930392619081032989925006404519081115722656250000e+00;
+ a[5] = -1.517333360452622237346531619550660252571105957031250000e+00;
+ a[6] = 1.740971994228911745583587844521389342844486236572265625e-01;
+ break;
+
+ case 192000:
+ b[0] = 3.433213424548713782469278044118254911154508590698242188e-02;
+ b[1] = -6.866426849097426177159775306790834292769432067871093750e-02;
+ b[2] = -3.433213424548714476358668434841092675924301147460937500e-02;
+ b[3] = 1.373285369819485235431955061358166858553886413574218750e-01;
+ b[4] = -3.433213424548714476358668434841092675924301147460937500e-02;
+ b[5] = -6.866426849097426177159775306790834292769432067871093750e-02;
+ b[6] = 3.433213424548713782469278044118254911154508590698242188e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -5.305923689674640009172890131594613194465637207031250000e+00;
+ a[2] = 1.165952437466175695135461864992976188659667968750000000e+01;
+ a[3] = -1.357560092700591525272102444432675838470458984375000000e+01;
+ a[4] = 8.828906932824192921316353022120893001556396484375000000e+00;
+ a[5] = -3.039490120988216581565666274400427937507629394531250000e+00;
+ a[6] = 4.325834301870381537469256727490574121475219726562500000e-01;
+ break;
+
+ default:
+ AUBIO_ERROR ("sampling rate of A-weighting filter is %d, should be one of\
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 192000.\n", samplerate);
+ return 1;
+
+ }
+
+ return 0;
+}
+
+aubio_filter_t *
+new_aubio_filter_a_weighting (uint_t samplerate)
+{
+ aubio_filter_t *f = new_aubio_filter (7);
+ if (aubio_filter_set_a_weighting(f,samplerate) != AUBIO_OK) {
+ del_aubio_filter(f);
+ return NULL;
+ }
+ return f;
+}
diff --git a/aubio/src/temporal/a_weighting.h b/aubio/src/temporal/a_weighting.h
new file mode 100644
index 00000000..49dd4d5c
--- /dev/null
+++ b/aubio/src/temporal/a_weighting.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FILTER_A_DESIGN_H
+#define AUBIO_FILTER_A_DESIGN_H
+
+/** \file
+
+ A-weighting filter coefficients
+
+ This file creates an A-weighting digital filter, which reduces low and high
+ frequencies and enhance the middle ones to reflect the ability of the human
+ hearing.
+
+ The implementation is based on the following standard:
+
+ - IEC/CD 1672: Electroacoustics-Sound Level Meters, IEC, Geneva, Nov. 1996,
+ for A- and C-weighting filters.
+
+ See also:
+
+ - A-Weighting on
+ Wikipedia
+ - Weighting filter on
+ Wikipedia
+ - Christophe
+ Couvreur's 'octave' toolbox
+
+ The coefficients in this file have been computed using Christophe Couvreur's
+ scripts in octave 3.0 (debian package 1:3.0.5-6+b2 with octave-signal
+ 1.0.9-1+b1 on i386), with
[b, a] = adsign(1/Fs)
for various
+ sampling frequencies (8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, and 192000 Hz).
+
+ The sampling frequency should normally be higher than 20kHz, but most common
+ file sampling rates have been included for completeness.
+
+ \example temporal/test-a_weighting.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create new A-design filter
+
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+ \return a new filter object
+
+*/
+aubio_filter_t *new_aubio_filter_a_weighting (uint_t samplerate);
+
+/** set feedback and feedforward coefficients of a A-weighting filter
+
+ \param f filter object to get coefficients from
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+*/
+uint_t aubio_filter_set_a_weighting (aubio_filter_t * f, uint_t samplerate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_A_DESIGN_H */
diff --git a/aubio/src/temporal/biquad.c b/aubio/src/temporal/biquad.c
new file mode 100644
index 00000000..426b64fb
--- /dev/null
+++ b/aubio/src/temporal/biquad.c
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/biquad.h"
+
+uint_t
+aubio_filter_set_biquad (aubio_filter_t * f, lsmp_t b0, lsmp_t b1, lsmp_t b2,
+ lsmp_t a1, lsmp_t a2)
+{
+ uint_t order = aubio_filter_get_order (f);
+ lvec_t *bs = aubio_filter_get_feedforward (f);
+ lvec_t *as = aubio_filter_get_feedback (f);
+
+ if (order != 3) {
+ AUBIO_ERROR ("order of biquad filter must be 3, not %d\n", order);
+ return AUBIO_FAIL;
+ }
+ bs->data[0] = b0;
+ bs->data[1] = b1;
+ bs->data[2] = b2;
+ as->data[0] = 1.;
+ as->data[1] = a1;
+ as->data[2] = a2;
+ return AUBIO_OK;
+}
+
+aubio_filter_t *
+new_aubio_filter_biquad (lsmp_t b0, lsmp_t b1, lsmp_t b2, lsmp_t a1, lsmp_t a2)
+{
+ aubio_filter_t *f = new_aubio_filter (3);
+ aubio_filter_set_biquad (f, b0, b1, b2, a1, a2);
+ return f;
+}
diff --git a/aubio/src/temporal/biquad.h b/aubio/src/temporal/biquad.h
new file mode 100644
index 00000000..1d19d942
--- /dev/null
+++ b/aubio/src/temporal/biquad.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FILTER_BIQUAD_H
+#define AUBIO_FILTER_BIQUAD_H
+
+/** \file
+
+ Second order Infinite Impulse Response filter
+
+ This file implements a normalised biquad filter (second order IIR):
+
+ \f$ y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] - a_1 y[n-1] - a_2 y[n-2] \f$
+
+ The filtfilt version runs the filter twice, forward and backward, to
+ compensate the phase shifting of the forward operation.
+
+ See also Digital
+ biquad filter on wikipedia.
+
+ \example temporal/test-biquad.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** set coefficients of a biquad filter
+
+ \param f filter object as returned by new_aubio_filter()
+ \param b0 forward filter coefficient
+ \param b1 forward filter coefficient
+ \param b2 forward filter coefficient
+ \param a1 feedback filter coefficient
+ \param a2 feedback filter coefficient
+
+*/
+uint_t aubio_filter_set_biquad (aubio_filter_t * f, lsmp_t b0, lsmp_t b1,
+ lsmp_t b2, lsmp_t a1, lsmp_t a2);
+
+/** create biquad filter with `b0`, `b1`, `b2`, `a1`, `a2` coeffs
+
+ \param b0 forward filter coefficient
+ \param b1 forward filter coefficient
+ \param b2 forward filter coefficient
+ \param a1 feedback filter coefficient
+ \param a2 feedback filter coefficient
+
+*/
+aubio_filter_t *new_aubio_filter_biquad (lsmp_t b0, lsmp_t b1, lsmp_t b2,
+ lsmp_t a1, lsmp_t a2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_BIQUAD_H */
diff --git a/aubio/src/temporal/c_weighting.c b/aubio/src/temporal/c_weighting.c
new file mode 100644
index 00000000..91ada717
--- /dev/null
+++ b/aubio/src/temporal/c_weighting.c
@@ -0,0 +1,217 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "temporal/filter.h"
+#include "temporal/c_weighting.h"
+
+uint_t
+aubio_filter_set_c_weighting (aubio_filter_t * f, uint_t samplerate)
+{
+ uint_t order; lsmp_t *a, *b; lvec_t *as, *bs;
+
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERROR("aubio_filter: failed setting C-weighting with samplerate %d\n", samplerate);
+ return AUBIO_FAIL;
+ }
+ if (f == NULL) {
+ AUBIO_ERROR("aubio_filter: failed setting C-weighting with filter NULL\n");
+ return AUBIO_FAIL;
+ }
+
+ order = aubio_filter_get_order (f);
+ if ( order != 5 ) {
+ AUBIO_ERROR ("aubio_filter: order of C-weighting filter must be 5, not %d\n", order);
+ return 1;
+ }
+
+ aubio_filter_set_samplerate (f, samplerate);
+ bs = aubio_filter_get_feedforward (f);
+ as = aubio_filter_get_feedback (f);
+ b = bs->data, a = as->data;
+
+ /* select coefficients according to sampling frequency */
+ switch (samplerate) {
+
+ case 8000:
+ b[0] = 6.782173932405135552414776611840352416038513183593750000e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.356434786481027110482955322368070483207702636718750000e+00;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 6.782173932405135552414776611840352416038513183593750000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -6.589092811505605773447769024642184376716613769531250000e-01;
+ a[2] = -1.179445664897062595599663836765103042125701904296875000e+00;
+ a[3] = 4.243329729632123736848825501510873436927795410156250000e-01;
+ a[4] = 4.147270002091348328754349950031610205769538879394531250e-01;
+ break;
+
+ case 11025:
+ b[0] = 6.002357155402652244546857218665536493062973022460937500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.200471431080530448909371443733107298612594604492187500e+00;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 6.002357155402652244546857218665536493062973022460937500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -8.705602141280316397242700077185872942209243774414062500e-01;
+ a[2] = -9.037199507150940336330791069485712796449661254882812500e-01;
+ a[3] = 4.758433040929530011275971901341108605265617370605468750e-01;
+ a[4] = 2.987653956523212417373258631414500996470451354980468750e-01;
+ break;
+
+ case 16000:
+ b[0] = 4.971057193673903418229542694461997598409652709960937500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -9.942114387347806836459085388923995196819305419921875000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 4.971057193673903418229542694461997598409652709960937500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.162322939286873690889478893950581550598144531250000000e+00;
+ a[2] = -4.771961355734982701548574368644040077924728393554687500e-01;
+ a[3] = 4.736145114694704227886745684372726827859878540039062500e-01;
+ a[4] = 1.660337524309875301131711466950946487486362457275390625e-01;
+ break;
+
+ case 22050:
+ b[0] = 4.033381299002754549754001800465630367398262023925781250e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -8.066762598005509099508003600931260734796524047851562500e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 4.033381299002754549754001800465630367398262023925781250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.449545371157945350404361306573264300823211669921875000e+00;
+ a[2] = -1.030104190885922088583015465701464563608169555664062500e-02;
+ a[3] = 3.881857047554073680828423675848171114921569824218750000e-01;
+ a[4] = 7.171589940116777917022972133054281584918498992919921875e-02;
+ break;
+
+ case 24000:
+ b[0] = 3.786678621924967069745093795063439756631851196289062500e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -7.573357243849934139490187590126879513263702392578125000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 3.786678621924967069745093795063439756631851196289062500e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.529945307555420797029910318087786436080932617187500000e+00;
+ a[2] = 1.283553182116208835061854642844991758465766906738281250e-01;
+ a[3] = 3.494608072385725350272878131363540887832641601562500000e-01;
+ a[4] = 5.217291949300089520802359288609295617789030075073242188e-02;
+ break;
+
+ case 32000:
+ b[0] = 2.977986488230693340462096330156782642006874084472656250e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -5.955972976461386680924192660313565284013748168945312500e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.977986488230693340462096330156782642006874084472656250e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -1.812455387128179218336754274787381291389465332031250000e+00;
+ a[2] = 6.425013281155662614452239722595550119876861572265625000e-01;
+ a[3] = 1.619857574578579817448087396769551560282707214355468750e-01;
+ a[4] = 7.987649713547682189807019881300220731645822525024414062e-03;
+ break;
+
+ case 44100:
+ b[0] = 2.170085619492190254220531642204150557518005371093750000e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -4.340171238984380508441063284408301115036010742187500000e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.170085619492190254220531642204150557518005371093750000e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.134674963687040794013682898366823792457580566406250000e+00;
+ a[2] = 1.279333533236062692139967111870646476745605468750000000e+00;
+ a[3] = -1.495598460893957093453821016737492755055427551269531250e-01;
+ a[4] = 4.908700174624683852664386307651511742733418941497802734e-03;
+ break;
+
+ case 48000:
+ b[0] = 1.978871200263932761398422144338837824761867523193359375e-01;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -3.957742400527865522796844288677675649523735046386718750e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 1.978871200263932761398422144338837824761867523193359375e-01;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.219172914052801814932536217384040355682373046875000000e+00;
+ a[2] = 1.455135878947171557129536267893854528665542602539062500e+00;
+ a[3] = -2.484960738877830532800317087094299495220184326171875000e-01;
+ a[4] = 1.253882314727246607977129144728678511455655097961425781e-02;
+ break;
+
+ case 88200:
+ b[0] = 9.221909851156021020734954163344809785485267639160156250e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.844381970231204204146990832668961957097053527832031250e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 9.221909851156021020734954163344809785485267639160156250e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.785795902923448696952846148633398115634918212890625000e+00;
+ a[2] = 2.727736758747444145711824603495188057422637939453125000e+00;
+ a[3] = -1.097007502819661528548067508381791412830352783203125000e+00;
+ a[4] = 1.550674356752141103132913713125162757933139801025390625e-01;
+ break;
+
+ case 96000:
+ b[0] = 8.182864044979756834585771230194950476288795471191406250e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -1.636572808995951366917154246038990095257759094238281250e-01;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 8.182864044979756834585771230194950476288795471191406250e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -2.856378516857566829401093855267390608787536621093750000e+00;
+ a[2] = 2.897640237559524045707348705036565661430358886718750000e+00;
+ a[3] = -1.225265958339703198376469117647502571344375610351562500e+00;
+ a[4] = 1.840048283551226071530493300087982788681983947753906250e-01;
+ break;
+
+ case 192000:
+ b[0] = 2.784755468532278815940728122768632601946592330932617188e-02;
+ b[1] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[2] = -5.569510937064557631881456245537265203893184661865234375e-02;
+ b[3] = 0.000000000000000000000000000000000000000000000000000000e+00;
+ b[4] = 2.784755468532278815940728122768632601946592330932617188e-02;
+ a[0] = 1.000000000000000000000000000000000000000000000000000000e+00;
+ a[1] = -3.333298856144166322224009491037577390670776367187500000e+00;
+ a[2] = 4.111467536240339448738723149290308356285095214843750000e+00;
+ a[3] = -2.222889041651291641699117462849244475364685058593750000e+00;
+ a[4] = 4.447204118126878991112960193277103826403617858886718750e-01;
+ break;
+
+ default:
+ AUBIO_ERROR ( "sampling rate of C-weighting filter is %d, should be one of\
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 192000.\n",
+ samplerate );
+ return 1;
+
+ }
+
+ return 0;
+}
+
+aubio_filter_t * new_aubio_filter_c_weighting (uint_t samplerate) {
+ aubio_filter_t * f = new_aubio_filter(5);
+ if (aubio_filter_set_c_weighting(f,samplerate) != AUBIO_OK) {
+ del_aubio_filter(f);
+ return NULL;
+ }
+ return f;
+}
diff --git a/aubio/src/temporal/c_weighting.h b/aubio/src/temporal/c_weighting.h
new file mode 100644
index 00000000..d87f61fa
--- /dev/null
+++ b/aubio/src/temporal/c_weighting.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FILTER_C_DESIGN_H
+#define AUBIO_FILTER_C_DESIGN_H
+
+/** \file
+
+ C-weighting filter coefficients
+
+ This file creates a C-weighting digital filter, which reduces low and high
+ frequencies and enhance the middle ones to reflect the ability of the human
+ hearing.
+
+ The implementation is based on the following standard:
+
+ - IEC/CD 1672: Electroacoustics-Sound Level Meters, IEC, Geneva, Nov. 1996,
+ for A- and C-weighting filters.
+
+ See also:
+
+ - A-Weighting on
+ Wikipedia
+ - Weighting filter on
+ Wikipedia
+ - Christophe
+ Couvreur's 'octave' toolbox
+
+ The coefficients in this file have been computed using Christophe Couvreur's
+ scripts in octave 3.0 (debian package 1:3.0.5-6+b2 with octave-signal
+ 1.0.9-1+b1 on i386), with
[b, a] = cdsign(1/Fs)
for various
+ sampling frequencies (8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000, and 192000 Hz).
+
+ The sampling frequency should normally be higher than 20kHz, but most common
+ file sampling rates have been included for completeness.
+
+ \example temporal/test-c_weighting.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** create new C-design filter
+
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+ \return a new filter object
+
+*/
+aubio_filter_t *new_aubio_filter_c_weighting (uint_t samplerate);
+
+/** set feedback and feedforward coefficients of a C-weighting filter
+
+ \param f filter object to get coefficients from
+ \param samplerate sampling frequency of the signal to filter. Should be one of
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, and
+ 192000 Hz
+
+*/
+uint_t aubio_filter_set_c_weighting (aubio_filter_t * f, uint_t samplerate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_C_DESIGN_H */
diff --git a/aubio/src/temporal/filter.c b/aubio/src/temporal/filter.c
new file mode 100644
index 00000000..776d2e6f
--- /dev/null
+++ b/aubio/src/temporal/filter.c
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+
+/* Requires lsmp_t to be long or double. float will NOT give reliable
+ * results */
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "lvec.h"
+#include "mathutils.h"
+#include "temporal/filter.h"
+
+struct _aubio_filter_t
+{
+ uint_t order;
+ uint_t samplerate;
+ lvec_t *a;
+ lvec_t *b;
+ lvec_t *y;
+ lvec_t *x;
+};
+
+void
+aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out)
+{
+ fvec_copy (in, out);
+ aubio_filter_do (f, out);
+}
+
+void
+aubio_filter_do (aubio_filter_t * f, fvec_t * in)
+{
+ uint_t j, l, order = f->order;
+ lsmp_t *x = f->x->data;
+ lsmp_t *y = f->y->data;
+ lsmp_t *a = f->a->data;
+ lsmp_t *b = f->b->data;
+
+ for (j = 0; j < in->length; j++) {
+ /* new input */
+ x[0] = KILL_DENORMAL (in->data[j]);
+ y[0] = b[0] * x[0];
+ for (l = 1; l < order; l++) {
+ y[0] += b[l] * x[l];
+ y[0] -= a[l] * y[l];
+ }
+ /* new output */
+ in->data[j] = y[0];
+ /* store for next sample */
+ for (l = order - 1; l > 0; l--) {
+ x[l] = x[l - 1];
+ y[l] = y[l - 1];
+ }
+ }
+}
+
+/* The rough way: reset memory of filter between each run to avoid end effects. */
+void
+aubio_filter_do_filtfilt (aubio_filter_t * f, fvec_t * in, fvec_t * tmp)
+{
+ uint_t j;
+ uint_t length = in->length;
+ /* apply filtering */
+ aubio_filter_do (f, in);
+ aubio_filter_do_reset (f);
+ /* mirror */
+ for (j = 0; j < length; j++)
+ tmp->data[length - j - 1] = in->data[j];
+ /* apply filtering on mirrored */
+ aubio_filter_do (f, tmp);
+ aubio_filter_do_reset (f);
+ /* invert back */
+ for (j = 0; j < length; j++)
+ in->data[j] = tmp->data[length - j - 1];
+}
+
+lvec_t *
+aubio_filter_get_feedback (const aubio_filter_t * f)
+{
+ return f->a;
+}
+
+lvec_t *
+aubio_filter_get_feedforward (const aubio_filter_t * f)
+{
+ return f->b;
+}
+
+uint_t
+aubio_filter_get_order (const aubio_filter_t * f)
+{
+ return f->order;
+}
+
+uint_t
+aubio_filter_get_samplerate (const aubio_filter_t * f)
+{
+ return f->samplerate;
+}
+
+uint_t
+aubio_filter_set_samplerate (aubio_filter_t * f, uint_t samplerate)
+{
+ f->samplerate = samplerate;
+ return AUBIO_OK;
+}
+
+void
+aubio_filter_do_reset (aubio_filter_t * f)
+{
+ lvec_zeros (f->x);
+ lvec_zeros (f->y);
+}
+
+aubio_filter_t *
+new_aubio_filter (uint_t order)
+{
+ aubio_filter_t *f = AUBIO_NEW (aubio_filter_t);
+ if ((sint_t)order < 1) {
+ AUBIO_FREE(f);
+ return NULL;
+ }
+ f->x = new_lvec (order);
+ f->y = new_lvec (order);
+ f->a = new_lvec (order);
+ f->b = new_lvec (order);
+ /* by default, samplerate is not set */
+ f->samplerate = 0;
+ f->order = order;
+ /* set default to identity */
+ f->a->data[0] = 1.;
+ f->b->data[0] = 1.;
+ return f;
+}
+
+void
+del_aubio_filter (aubio_filter_t * f)
+{
+ del_lvec (f->a);
+ del_lvec (f->b);
+ del_lvec (f->x);
+ del_lvec (f->y);
+ AUBIO_FREE (f);
+ return;
+}
diff --git a/aubio/src/temporal/filter.h b/aubio/src/temporal/filter.h
new file mode 100644
index 00000000..b8b678e8
--- /dev/null
+++ b/aubio/src/temporal/filter.h
@@ -0,0 +1,176 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_FILTER_H
+#define AUBIO_FILTER_H
+
+/** \file
+
+ Digital filter
+
+ This object stores a digital filter of order \f$n\f$.
+ It contains the following data:
+ - \f$ n*1 b_i \f$ feedforward coefficients
+ - \f$ n*1 a_i \f$ feedback coefficients
+ - \f$ n*c x_i \f$ input signal
+ - \f$ n*c y_i \f$ output signal
+
+ For convenience, the samplerate of the input signal is also stored in the
+ object.
+
+ Feedforward and feedback parameters can be modified using
+ aubio_filter_get_feedback() and aubio_filter_get_feedforward().
+
+ The function aubio_filter_do_outplace() computes the following output signal
+ \f$ y[n] \f$ from the input signal \f$ x[n] \f$:
+
+ \f{eqnarray*}{
+ y[n] = b_0 x[n] & + & b_1 x[n-1] + b_2 x[n-2] + ... + b_P x[n-P] \\
+ & - & a_1 y[n-1] - a_2 y[n-2] - ... - a_P y[n-P] \\
+ \f}
+
+ The function aubio_filter_do() executes the same computation but modifies
+ directly the input signal (in-place).
+
+ The function aubio_filter_do_filtfilt() version runs the filter twice, first
+ forward then backward, to compensate with the phase shifting of the forward
+ operation.
+
+ Some convenience functions are provided:
+ - new_aubio_filter_a_weighting() and aubio_filter_set_a_weighting(),
+ - new_aubio_filter_c_weighting() and aubio_filter_set_c_weighting().
+ - new_aubio_filter_biquad() and aubio_filter_set_biquad().
+
+ \example temporal/test-filter.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Digital filter
+
+*/
+typedef struct _aubio_filter_t aubio_filter_t;
+
+/** filter input vector (in-place)
+
+ \param f filter object as returned by new_aubio_filter()
+ \param in input vector to filter
+
+*/
+void aubio_filter_do (aubio_filter_t * f, fvec_t * in);
+
+/** filter input vector (out-of-place)
+
+ \param f filter object as returned by new_aubio_filter()
+ \param in input vector to filter
+ \param out output vector to store filtered input
+
+*/
+void aubio_filter_do_outplace (aubio_filter_t * f, const fvec_t * in, fvec_t * out);
+
+/** filter input vector forward and backward
+
+ \param f ::aubio_filter_t object as returned by new_aubio_filter()
+ \param in ::fvec_t input vector to filter
+ \param tmp memory space to use for computation
+
+*/
+void aubio_filter_do_filtfilt (aubio_filter_t * f, fvec_t * in, fvec_t * tmp);
+
+/** returns a pointer to feedback coefficients \f$ a_i \f$
+
+ \param f filter object to get parameters from
+
+ \return a pointer to the \f$ a_0 ... a_i ... a_P \f$ coefficients
+
+*/
+lvec_t *aubio_filter_get_feedback (const aubio_filter_t * f);
+
+/** returns a pointer to feedforward coefficients \f$ b_i \f$
+
+ \param f filter object to get coefficients from
+
+ \return a pointer to the \f$ b_0 ... b_i ... b_P \f$ coefficients
+
+*/
+lvec_t *aubio_filter_get_feedforward (const aubio_filter_t * f);
+
+/** get order of the filter
+
+ \param f filter to get order from
+
+ \return the order of the filter
+
+*/
+uint_t aubio_filter_get_order (const aubio_filter_t * f);
+
+/** get sampling rate of the filter
+
+ \param f filter to get sampling rate from
+
+ \return the sampling rate of the filter, in Hz
+
+*/
+uint_t aubio_filter_get_samplerate (const aubio_filter_t * f);
+
+/** get sampling rate of the filter
+
+ \param f filter to get sampling rate from
+ \param samplerate sample rate to set the filter to
+
+ \return the sampling rate of the filter, in Hz
+
+*/
+uint_t aubio_filter_set_samplerate (aubio_filter_t * f, uint_t samplerate);
+
+/** reset filter memory
+
+ \param f filter object as returned by new_aubio_filter()
+
+*/
+void aubio_filter_do_reset (aubio_filter_t * f);
+
+/** create new filter object
+
+ This function creates a new ::aubio_filter_t object, given the order of the
+ filter.
+
+ \param order order of the filter (number of coefficients)
+
+ \return the newly created filter object
+
+*/
+aubio_filter_t *new_aubio_filter (uint_t order);
+
+/** delete a filter object
+
+ \param f filter object to delete
+
+*/
+void del_aubio_filter (aubio_filter_t * f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_FILTER_H */
diff --git a/aubio/src/temporal/resampler.h b/aubio/src/temporal/resampler.h
new file mode 100644
index 00000000..7528e8ac
--- /dev/null
+++ b/aubio/src/temporal/resampler.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_RESAMPLER_H
+#define AUBIO_RESAMPLER_H
+
+/** \file
+
+ Resampling object
+
+ This object resamples an input vector into an output vector using
+ libsamplerate. See http://www.mega-nerd.com/SRC/
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** resampler object */
+typedef struct _aubio_resampler_t aubio_resampler_t;
+
+/** create resampler object
+
+ \param ratio output_sample_rate / input_sample_rate
+ \param type libsamplerate resampling type, see http://www.mega-nerd.com/SRC/api_misc.html#Converters
+
+*/
+aubio_resampler_t *new_aubio_resampler (smpl_t ratio, uint_t type);
+
+/** delete resampler object */
+void del_aubio_resampler (aubio_resampler_t * s);
+
+/** resample input in output
+
+ \param s resampler object
+ \param input input buffer of size N
+ \param output output buffer of size N*ratio
+
+*/
+void aubio_resampler_do (aubio_resampler_t * s, const fvec_t * input,
+ fvec_t * output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_RESAMPLER_H */
diff --git a/aubio/src/types.h b/aubio/src/types.h
new file mode 100644
index 00000000..57df2e0d
--- /dev/null
+++ b/aubio/src/types.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2003-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_TYPES_H
+#define AUBIO_TYPES_H
+
+/** \file
+
+ Definition of data types used in aubio
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HAVE_AUBIO_DOUBLE
+/** defined to 1 if aubio is compiled in double precision */
+#define HAVE_AUBIO_DOUBLE 0
+#endif
+
+/** short sample format (32 or 64 bits) */
+#if !HAVE_AUBIO_DOUBLE
+typedef float smpl_t;
+/** print format for sample in single precision */
+#define AUBIO_SMPL_FMT "%f"
+#else
+typedef double smpl_t;
+/** print format for double in single precision */
+#define AUBIO_SMPL_FMT "%lf"
+#endif
+/** long sample format (64 bits or more) */
+#if !HAVE_AUBIO_DOUBLE
+typedef double lsmp_t;
+/** print format for sample in double precision */
+#define AUBIO_LSMP_FMT "%lf"
+#else
+typedef long double lsmp_t;
+/** print format for double in double precision */
+#define AUBIO_LSMP_FMT "%Lf"
+#endif
+/** unsigned integer */
+typedef unsigned int uint_t;
+/** signed integer */
+typedef int sint_t;
+/** character */
+typedef char char_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TYPES_H */
diff --git a/aubio/src/utils/hist.c b/aubio/src/utils/hist.c
new file mode 100644
index 00000000..2dcc4432
--- /dev/null
+++ b/aubio/src/utils/hist.c
@@ -0,0 +1,151 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "utils/scale.h"
+#include "mathutils.h" //fvec_min fvec_max
+#include "utils/hist.h"
+
+/********
+ * Object Structure
+ */
+
+struct _aubio_hist_t {
+ fvec_t * hist;
+ uint_t nelems;
+ fvec_t * cent;
+ aubio_scale_t *scaler;
+};
+
+/**
+ * Object creation/deletion calls
+ */
+aubio_hist_t * new_aubio_hist (smpl_t flow, smpl_t fhig, uint_t nelems){
+ aubio_hist_t * s = AUBIO_NEW(aubio_hist_t);
+ smpl_t step = (fhig-flow)/(smpl_t)(nelems);
+ smpl_t accum = step;
+ uint_t i;
+ if ((sint_t)nelems <= 0) {
+ AUBIO_FREE(s);
+ return NULL;
+ }
+ s->nelems = nelems;
+ s->hist = new_fvec(nelems);
+ s->cent = new_fvec(nelems);
+
+ /* use scale to map flow/fhig -> 0/nelems */
+ s->scaler = new_aubio_scale(flow,fhig,0,nelems);
+ /* calculate centers now once */
+ s->cent->data[0] = flow + 0.5 * step;
+ for (i=1; i < s->nelems; i++, accum+=step )
+ s->cent->data[i] = s->cent->data[0] + accum;
+
+ return s;
+}
+
+void del_aubio_hist(aubio_hist_t *s) {
+ del_fvec(s->hist);
+ del_fvec(s->cent);
+ del_aubio_scale(s->scaler);
+ AUBIO_FREE(s);
+}
+
+/***
+ * do it
+ */
+void aubio_hist_do (aubio_hist_t *s, fvec_t *input) {
+ uint_t j;
+ sint_t tmp = 0;
+ aubio_scale_do(s->scaler, input);
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (j=0; j < input->length; j++)
+ {
+ tmp = (sint_t)FLOOR(input->data[j]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems)) {
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+void aubio_hist_do_notnull (aubio_hist_t *s, fvec_t *input) {
+ uint_t j;
+ sint_t tmp = 0;
+ aubio_scale_do(s->scaler, input);
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (j=0; j < input->length; j++) {
+ if (input->data[j] != 0) {
+ tmp = (sint_t)FLOOR(input->data[j]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+
+void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input) {
+ uint_t i;
+ sint_t tmp = 0;
+ smpl_t ilow = fvec_min(input);
+ smpl_t ihig = fvec_max(input);
+ smpl_t step = (ihig-ilow)/(smpl_t)(s->nelems);
+
+ /* readapt */
+ aubio_scale_set_limits (s->scaler, ilow, ihig, 0, s->nelems);
+
+ /* recalculate centers */
+ s->cent->data[0] = ilow + 0.5f * step;
+ for (i=1; i < s->nelems; i++)
+ s->cent->data[i] = s->cent->data[0] + i * step;
+
+ /* scale */
+ aubio_scale_do(s->scaler, input);
+
+ /* reset data */
+ fvec_zeros(s->hist);
+ /* run accum */
+ for (i=0; i < input->length; i++) {
+ if (input->data[i] != 0) {
+ tmp = (sint_t)FLOOR(input->data[i]);
+ if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+ s->hist->data[tmp] += 1;
+ }
+ }
+}
+
+void aubio_hist_weight (aubio_hist_t *s) {
+ uint_t j;
+ for (j=0; j < s->nelems; j++) {
+ s->hist->data[j] *= s->cent->data[j];
+ }
+}
+
+smpl_t aubio_hist_mean (const aubio_hist_t *s) {
+ uint_t j;
+ smpl_t tmp = 0.0;
+ for (j=0; j < s->nelems; j++)
+ tmp += s->hist->data[j];
+ return tmp/(smpl_t)(s->nelems);
+}
+
diff --git a/aubio/src/utils/hist.h b/aubio/src/utils/hist.h
new file mode 100644
index 00000000..d39091a4
--- /dev/null
+++ b/aubio/src/utils/hist.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** @file
+ *
+ * Histogram function
+ *
+ * Big hacks to implement an histogram
+ */
+
+#ifndef AUBIO_HIST_H
+#define AUBIO_HIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** histogram object */
+typedef struct _aubio_hist_t aubio_hist_t;
+
+/** histogram creation
+
+ \param flow minimum input
+ \param fhig maximum input
+ \param nelems number of histogram columns
+
+*/
+aubio_hist_t * new_aubio_hist(smpl_t flow, smpl_t fhig, uint_t nelems);
+/** histogram deletion */
+void del_aubio_hist(aubio_hist_t *s);
+/** compute the histogram */
+void aubio_hist_do(aubio_hist_t *s, fvec_t * input);
+/** compute the histogram ignoring null elements */
+void aubio_hist_do_notnull(aubio_hist_t *s, fvec_t * input);
+/** compute the mean of the histogram */
+smpl_t aubio_hist_mean(const aubio_hist_t *s);
+/** weight the histogram */
+void aubio_hist_weight(aubio_hist_t *s);
+/** compute dynamic histogram for non-null elements */
+void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_HIST_H */
diff --git a/aubio/src/utils/log.c b/aubio/src/utils/log.c
new file mode 100644
index 00000000..967c2d6c
--- /dev/null
+++ b/aubio/src/utils/log.c
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "log.h"
+
+/** array of pointers to logging functions, one per level */
+static aubio_log_function_t aubio_log_function[AUBIO_LOG_LAST_LEVEL];
+/** array of pointers to closure passed to logging functions, one per level */
+static void* aubio_log_user_data[AUBIO_LOG_LAST_LEVEL];
+/** buffer for logging messages */
+static char aubio_log_buffer[512];
+
+/** private function used by default by logging functions */
+void
+aubio_default_log(sint_t level, const char_t *message, void * data UNUSED)
+{
+ FILE *out;
+ out = stdout;
+ if (level == AUBIO_LOG_ERR || level == AUBIO_LOG_DBG || level == AUBIO_LOG_WRN) {
+ out = stderr;
+ }
+ fprintf(out, "%s", message);
+ //fflush(out);
+}
+
+uint_t
+aubio_log(sint_t level, const char_t *fmt, ...)
+{
+ aubio_log_function_t fun = NULL;
+
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(aubio_log_buffer, sizeof(aubio_log_buffer), fmt, args);
+ va_end(args);
+
+ if ((level >= 0) && (level < AUBIO_LOG_LAST_LEVEL)) {
+ fun = aubio_log_function[level];
+ if (fun != NULL) {
+ (*fun)(level, aubio_log_buffer, aubio_log_user_data[level]);
+ } else {
+ aubio_default_log(level, aubio_log_buffer, NULL);
+ }
+ }
+ return AUBIO_FAIL;
+}
+
+void
+aubio_log_reset(void)
+{
+ uint_t i = 0;
+ for (i = 0; i < AUBIO_LOG_LAST_LEVEL; i++) {
+ aubio_log_set_level_function(i, aubio_default_log, NULL);
+ }
+}
+
+aubio_log_function_t
+aubio_log_set_level_function(sint_t level, aubio_log_function_t fun, void * data)
+{
+ aubio_log_function_t old = NULL;
+ if ((level >= 0) && (level < AUBIO_LOG_LAST_LEVEL)) {
+ old = aubio_log_function[level];
+ aubio_log_function[level] = fun;
+ aubio_log_user_data[level] = data;
+ }
+ return old;
+}
+
+void
+aubio_log_set_function(aubio_log_function_t fun, void * data) {
+ uint_t i = 0;
+ for (i = 0; i < AUBIO_LOG_LAST_LEVEL; i++) {
+ aubio_log_set_level_function(i, fun, data);
+ }
+}
diff --git a/aubio/src/utils/log.h b/aubio/src/utils/log.h
new file mode 100644
index 00000000..091e91d4
--- /dev/null
+++ b/aubio/src/utils/log.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_LOG_H
+#define AUBIO_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Logging features
+
+ This file specifies ::aubio_log_set_function and
+ ::aubio_log_set_level_function, which let you define one or several custom
+ logging functions to redirect warnings and errors from aubio to your
+ application. The custom function should have the prototype defined in
+ ::aubio_log_function_t.
+
+ After a call to ::aubio_log_set_level_function, ::aubio_log_reset can be used
+ to reset each logging functions to the default ones.
+
+ \example utils/test-log.c
+
+*/
+
+/** list of logging levels */
+enum aubio_log_level {
+ AUBIO_LOG_ERR, /**< critical errors */
+ AUBIO_LOG_INF, /**< infos */
+ AUBIO_LOG_MSG, /**< general messages */
+ AUBIO_LOG_DBG, /**< debug messages */
+ AUBIO_LOG_WRN, /**< warnings */
+ AUBIO_LOG_LAST_LEVEL, /**< number of valid levels */
+};
+
+/** Logging function prototype, to be passed to ::aubio_log_set_function
+
+ \param level log level
+ \param message text to log
+ \param data optional closure used by the callback
+
+ See @ref utils/test-log.c for an example of logging function.
+
+ */
+typedef void (*aubio_log_function_t)(sint_t level, const char_t *message, void
+ *data);
+
+/** Set logging function for all levels
+
+ \param fun the function to be used to log, of type ::aubio_log_function_t
+ \param data optional closure to be passed to the function (can be NULL if
+ nothing to pass)
+
+ */
+void aubio_log_set_function(aubio_log_function_t fun, void* data);
+
+/** Set logging function for a given level
+
+ \param level the level for which to set the logging function
+ \param fun the function to be used to log, of type ::aubio_log_function_t
+ \param data optional closure to be passed to the function (can be NULL if
+ nothing to pass)
+
+*/
+aubio_log_function_t aubio_log_set_level_function(sint_t level,
+ aubio_log_function_t fun, void* data);
+
+/** Reset all logging functions to the default one
+
+ After calling this function, the default logging function will be used to
+ print error, warning, normal, and debug messages to `stdout` or `stderr`.
+
+ */
+void aubio_log_reset(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_LOG_H */
diff --git a/aubio/src/utils/parameter.c b/aubio/src/utils/parameter.c
new file mode 100644
index 00000000..00b39799
--- /dev/null
+++ b/aubio/src/utils/parameter.c
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "parameter.h"
+
+#define AUBIO_PARAM_MAX_STEPS 2000
+#define AUBIO_PARAM_MIN_STEPS 1
+
+struct _aubio_parameter_t {
+ smpl_t current_value;
+ smpl_t target_value;
+ smpl_t increment;
+
+ smpl_t max_value;
+ smpl_t min_value;
+
+ uint_t steps;
+};
+
+aubio_parameter_t * new_aubio_parameter (smpl_t min_value, smpl_t max_value, uint_t steps )
+{
+ aubio_parameter_t * param = AUBIO_NEW(aubio_parameter_t);
+
+ param->min_value = min_value;
+ param->max_value = max_value;
+ param->steps = steps;
+
+ param->current_value = param->min_value;
+ param->target_value = param->current_value;
+ param->increment = 0.;
+
+ return param;
+}
+
+uint_t aubio_parameter_set_target_value ( aubio_parameter_t * param, smpl_t value )
+{
+ uint_t err = AUBIO_OK;
+ if (value < param->min_value ) {
+ param->target_value = param->min_value;
+ err = AUBIO_FAIL;
+ } else if ( value > param->max_value ) {
+ param->target_value = param->max_value;
+ err = AUBIO_FAIL;
+ } else {
+ param->target_value = value;
+ }
+ param->increment = ( param->target_value - param->current_value ) / param->steps;
+ return err;
+}
+
+uint_t aubio_parameter_set_current_value ( aubio_parameter_t * param, smpl_t value )
+{
+ uint_t err = AUBIO_OK;
+ if (value < param->min_value ) {
+ param->current_value = param->min_value;
+ err = AUBIO_FAIL;
+ } else if ( value > param->max_value ) {
+ param->current_value = param->max_value;
+ err = AUBIO_FAIL;
+ } else {
+ param->current_value = value;
+ }
+ param->target_value = param->current_value;
+ param->increment = 0;
+ return err;
+}
+
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * s )
+{
+ return s->current_value;
+}
+
+smpl_t aubio_parameter_get_next_value ( aubio_parameter_t * s )
+{
+ if ( ABS(s->current_value - s->target_value) > ABS(s->increment) ) {
+ s->current_value += s->increment;
+ } else {
+ s->current_value = s->target_value;
+ }
+ return s->current_value;
+}
+
+uint_t aubio_parameter_set_steps ( aubio_parameter_t * param, uint_t steps )
+{
+ if (steps < AUBIO_PARAM_MIN_STEPS || steps > AUBIO_PARAM_MAX_STEPS) {
+ return AUBIO_FAIL;
+ }
+ param->steps = steps;
+ param->increment = ( param->target_value - param->current_value ) / param->steps;
+ return AUBIO_OK;
+}
+
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param )
+{
+ return param->steps;
+}
+
+uint_t aubio_parameter_set_min_value ( aubio_parameter_t * param, smpl_t min_value )
+{
+ param->min_value = min_value;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param )
+{
+ return param->min_value;
+}
+
+uint_t aubio_parameter_set_max_value ( aubio_parameter_t * param, smpl_t max_value )
+{
+ param->max_value = max_value;
+ return AUBIO_OK;
+}
+
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param )
+{
+ return param->max_value;
+}
+
+void del_aubio_parameter ( aubio_parameter_t * param )
+{
+ AUBIO_FREE(param);
+}
diff --git a/aubio/src/utils/parameter.h b/aubio/src/utils/parameter.h
new file mode 100644
index 00000000..9649eb8c
--- /dev/null
+++ b/aubio/src/utils/parameter.h
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#ifndef AUBIO_PARAMETER_H
+#define AUBIO_PARAMETER_H
+
+/** \file
+
+ Parameter with linear interpolation
+
+ This object manages a parameter, with minimum and maximum values, and a
+ number of steps to compute linear interpolation between two values.
+
+ \example utils/test-parameter.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** parameter object */
+typedef struct _aubio_parameter_t aubio_parameter_t;
+
+/** create new parameter object
+
+ \param min_value the minimum value of the new parameter
+ \param max_value the maximum value of the new parameter
+ \param steps the number of steps to interpolate from the old value to the target value
+
+ \return the newly created ::aubio_parameter_t
+
+*/
+aubio_parameter_t * new_aubio_parameter(smpl_t min_value, smpl_t max_value, uint_t steps);
+
+/** set target value of the parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param value new target value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_target_value ( aubio_parameter_t * param, smpl_t value );
+
+/** get next parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return new interpolated parameter value
+
+*/
+smpl_t aubio_parameter_get_next_value ( aubio_parameter_t * param );
+
+/** get current parameter value, without interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return current value
+
+*/
+smpl_t aubio_parameter_get_current_value ( const aubio_parameter_t * param );
+
+/** set current parameter value, skipping interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param value new parameter value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_current_value ( aubio_parameter_t * param, smpl_t value );
+
+/** set number of steps used for interpolation
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param steps new number of steps
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_steps ( aubio_parameter_t * param, uint_t steps );
+
+/** get number of steps of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return number of steps
+
+*/
+uint_t aubio_parameter_get_steps ( const aubio_parameter_t * param);
+
+/** set minimum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param min_value new minimum value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_min_value ( aubio_parameter_t * param, smpl_t min_value );
+
+/** get minimum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return minimum value
+
+*/
+smpl_t aubio_parameter_get_min_value ( const aubio_parameter_t * param );
+
+/** set maximum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+ \param max_value new maximum value
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_parameter_set_max_value ( aubio_parameter_t * param, smpl_t max_value );
+
+/** get maximum value of this parameter
+
+ \param param parameter, created by ::new_aubio_parameter
+
+ \return maximum value
+
+*/
+smpl_t aubio_parameter_get_max_value ( const aubio_parameter_t * param );
+
+/** destroy ::aubio_parameter_t object
+
+ \param param parameter, created by ::new_aubio_parameter
+
+*/
+void del_aubio_parameter( aubio_parameter_t * param );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PARAMETER_H */
diff --git a/aubio/src/utils/scale.c b/aubio/src/utils/scale.c
new file mode 100644
index 00000000..3bd116c8
--- /dev/null
+++ b/aubio/src/utils/scale.c
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2003-2009 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "utils/scale.h"
+
+struct _aubio_scale_t {
+ smpl_t ilow;
+ smpl_t ihig;
+ smpl_t olow;
+ smpl_t ohig;
+
+ smpl_t scaler;
+ smpl_t irange;
+
+ /* not implemented yet : type in/out data
+ bool inint;
+ bool outint;
+ */
+};
+
+aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig) {
+ aubio_scale_t * s = AUBIO_NEW(aubio_scale_t);
+ aubio_scale_set_limits (s, ilow, ihig, olow, ohig);
+ return s;
+}
+
+void del_aubio_scale(aubio_scale_t *s) {
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_scale_set_limits (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig) {
+ smpl_t inputrange = ihig - ilow;
+ smpl_t outputrange= ohig - olow;
+ s->ilow = ilow;
+ s->ihig = ihig;
+ s->olow = olow;
+ s->ohig = ohig;
+ if (inputrange == 0) {
+ s->scaler = 0.0;
+ } else {
+ s->scaler = outputrange/inputrange;
+ if (inputrange < 0) {
+ inputrange = inputrange * -1.0f;
+ }
+ }
+ return AUBIO_OK;
+}
+
+void aubio_scale_do (aubio_scale_t *s, fvec_t *input)
+{
+ uint_t j;
+ for (j=0; j < input->length; j++){
+ input->data[j] -= s->ilow;
+ input->data[j] *= s->scaler;
+ input->data[j] += s->olow;
+ }
+}
+
diff --git a/aubio/src/utils/scale.h b/aubio/src/utils/scale.h
new file mode 100644
index 00000000..da311140
--- /dev/null
+++ b/aubio/src/utils/scale.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Vector scaling function
+
+ This object, inspired from the scale object in FTS, the jMax engine, scales
+ the values of a vector according to an affine function defined as follow:
+
+ \f$ y = (x - ilow)*(ohig-olow)/(ihig-ilow) + olow \f$
+
+*/
+#ifndef AUBIO_SCALE_H
+#define AUBIO_SCALE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** scale object */
+typedef struct _aubio_scale_t aubio_scale_t;
+
+/** create a scale object
+
+ \param flow lower value of output function
+ \param fhig higher value of output function
+ \param ilow lower value of input function
+ \param ihig higher value of output function
+
+*/
+aubio_scale_t * new_aubio_scale(smpl_t flow, smpl_t fhig,
+ smpl_t ilow, smpl_t ihig);
+/** delete a scale object
+
+ \param s scale object as returned by new_aubio_scale
+
+*/
+void del_aubio_scale(aubio_scale_t *s);
+/** scale input vector
+
+ \param s scale object as returned by new_aubio_scale
+ \param input vector to scale
+
+*/
+void aubio_scale_do(aubio_scale_t *s, fvec_t * input);
+/** modify scale parameters after object creation
+
+ \param s scale object as returned by new_aubio_scale
+ \param olow lower value of output function
+ \param ohig higher value of output function
+ \param ilow lower value of input function
+ \param ihig higher value of output function
+
+*/
+uint_t aubio_scale_set_limits (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+ smpl_t olow, smpl_t ohig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_SCALE_H */
diff --git a/aubio/src/utils/strutils.c b/aubio/src/utils/strutils.c
new file mode 100644
index 00000000..8b695ff4
--- /dev/null
+++ b/aubio/src/utils/strutils.c
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2018 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_WIN_HACKS
+#define strncasecmp _strnicmp
+#endif
+
+const char_t *aubio_str_get_extension(const char_t *filename)
+{
+ // find last occurence of dot character
+ const char_t *ext;
+ if (!filename) return NULL;
+ ext = strrchr(filename, '.');
+ if (!ext || ext == filename) return "";
+ else return ext + 1;
+}
+
+uint_t aubio_str_extension_matches(const char_t *ext, const char_t *pattern)
+{
+ return ext && pattern && (strncasecmp(ext, pattern, PATH_MAX) == 0);
+}
+
+uint_t aubio_str_path_has_extension(const char_t *filename,
+ const char_t *pattern)
+{
+ const char_t *ext = aubio_str_get_extension(filename);
+ return aubio_str_extension_matches(ext, pattern);
+}
diff --git a/aubio/src/utils/windll.c b/aubio/src/utils/windll.c
new file mode 100644
index 00000000..cad04439
--- /dev/null
+++ b/aubio/src/utils/windll.c
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2016 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** @file
+
+ Windows dll entry point.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_WIN_HACKS
+
+#ifndef __GNUC__ // do not include msvc headers when using gcc/mingw32
+
+// latest version
+#include
+// for earlier versions, include WinSDKVer.h and set _WIN32_WINNT macro
+
+#endif /* __GNUC__ */
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#include "aubio.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule UNUSED,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved UNUSED)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+#endif
diff --git a/aubio/src/vecutils.c b/aubio/src/vecutils.c
new file mode 100644
index 00000000..8907b5ec
--- /dev/null
+++ b/aubio/src/vecutils.c
@@ -0,0 +1,36 @@
+#include "aubio_priv.h"
+#include "types.h"
+#include "fvec.h"
+#include "cvec.h"
+#include "vecutils.h"
+
+#define AUBIO_OP(OPNAME, OP, TYPE, OBJ) \
+void TYPE ## _ ## OPNAME (TYPE ## _t *o) \
+{ \
+ uint_t j; \
+ for (j = 0; j < o->length; j++) { \
+ o->OBJ[j] = OP (o->OBJ[j]); \
+ } \
+}
+
+#define AUBIO_OP_C(OPNAME, OP) \
+ AUBIO_OP(OPNAME, OP, fvec, data)
+
+AUBIO_OP_C(exp, EXP)
+AUBIO_OP_C(cos, COS)
+AUBIO_OP_C(sin, SIN)
+AUBIO_OP_C(abs, ABS)
+AUBIO_OP_C(sqrt, SQRT)
+AUBIO_OP_C(log10, SAFE_LOG10)
+AUBIO_OP_C(log, SAFE_LOG)
+AUBIO_OP_C(floor, FLOOR)
+AUBIO_OP_C(ceil, CEIL)
+AUBIO_OP_C(round, ROUND)
+
+void fvec_pow (fvec_t *s, smpl_t power)
+{
+ uint_t j;
+ for (j = 0; j < s->length; j++) {
+ s->data[j] = POW(s->data[j], power);
+ }
+}
diff --git a/aubio/src/vecutils.h b/aubio/src/vecutils.h
new file mode 100644
index 00000000..f0ed96e5
--- /dev/null
+++ b/aubio/src/vecutils.h
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2009-2015 Paul Brossier
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see .
+
+*/
+
+/** \file
+
+ Utility functions for ::fvec_t
+
+ */
+
+#ifndef AUBIO_VECUTILS_H
+#define AUBIO_VECUTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** compute \f$e^x\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_exp (fvec_t *s);
+
+/** compute \f$cos(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_cos (fvec_t *s);
+
+/** compute \f$sin(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_sin (fvec_t *s);
+
+/** compute the \f$abs(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_abs (fvec_t *s);
+
+/** compute the \f$sqrt(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_sqrt (fvec_t *s);
+
+/** compute the \f$log10(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_log10 (fvec_t *s);
+
+/** compute the \f$log(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_log (fvec_t *s);
+
+/** compute the \f$floor(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_floor (fvec_t *s);
+
+/** compute the \f$ceil(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_ceil (fvec_t *s);
+
+/** compute the \f$round(x)\f$ of each vector elements
+
+ \param s vector to modify
+
+*/
+void fvec_round (fvec_t *s);
+
+/** raise each vector elements to the power pow
+
+ \param s vector to modify
+ \param pow power to raise to
+
+*/
+void fvec_pow (fvec_t *s, smpl_t pow);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_VECUTILS_H */
diff --git a/client_generic/Client/AudioAnalyzer.cpp b/client_generic/Client/AudioAnalyzer.cpp
new file mode 100644
index 00000000..17a1ef74
--- /dev/null
+++ b/client_generic/Client/AudioAnalyzer.cpp
@@ -0,0 +1,462 @@
+#include "AudioAnalyzer.h"
+
+extern "C" {
+#include "aubio.h"
+}
+
+#include "BeatDetektor.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "Settings.h"
+
+namespace
+{
+constexpr uint_t kSampleRate = 44100;
+constexpr uint_t kWinSize = 2048;
+constexpr uint_t kHopSize = 512;
+constexpr uint_t kNumBins = kWinSize / 2 + 1;
+
+float Clamp01(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
+
+float SmoothAttackRelease(float previous, float current, float attack, float release)
+{
+ const float a = current > previous ? attack : release;
+ return previous * (1.0f - a) + current * a;
+}
+
+float DbToLinear(float db) { return std::pow(10.0f, db / 20.0f); }
+
+} // namespace
+
+constexpr uint_t kMelBands = 40;
+
+struct AubioState
+{
+ aubio_pvoc_t* pvoc = nullptr;
+ cvec_t* fftgrain = nullptr;
+ fvec_t* hopIn = nullptr;
+ fvec_t* tempoOut = nullptr;
+ aubio_tempo_t* tempo = nullptr;
+ aubio_filterbank_t* filterbank = nullptr;
+ fvec_t* melOut = nullptr;
+ bool ready = false;
+
+ void Init()
+ {
+ hopIn = new_fvec(kHopSize);
+ fftgrain = new_cvec(kWinSize);
+ tempoOut = new_fvec(2);
+ melOut = new_fvec(kMelBands);
+
+ pvoc = new_aubio_pvoc(kWinSize, kHopSize);
+ tempo = new_aubio_tempo("complex", kWinSize, kHopSize, kSampleRate);
+ filterbank = new_aubio_filterbank(kMelBands, kWinSize);
+ if (filterbank)
+ aubio_filterbank_set_mel_coeffs(filterbank, (smpl_t)kSampleRate, 20.0f, 11000.0f);
+
+ if (pvoc && tempo && filterbank)
+ ready = true;
+ }
+
+ ~AubioState()
+ {
+ if (pvoc) del_aubio_pvoc(pvoc);
+ if (fftgrain) del_cvec(fftgrain);
+ if (hopIn) del_fvec(hopIn);
+ if (tempoOut) del_fvec(tempoOut);
+ if (tempo) del_aubio_tempo(tempo);
+ if (filterbank) del_aubio_filterbank(filterbank);
+ if (melOut) del_fvec(melOut);
+ }
+};
+
+// ── Manual BPM control ────────────────────────────────────────────────────────
+static std::atomic s_bpmOverride{0.0f};
+static std::atomic s_liveBpm{120.0f};
+static std::atomic s_liveBeatPhase{0.0f};
+static std::atomic s_liveBeatCount{0};
+static std::atomic s_resetBeatPhase{false};
+
+void AudioAnalyzer_SetBpmOverride(float bpm)
+{
+ s_bpmOverride.store(bpm, std::memory_order_relaxed);
+}
+
+float AudioAnalyzer_GetCurrentBpm()
+{
+ return s_liveBpm.load(std::memory_order_relaxed);
+}
+
+float AudioAnalyzer_GetBeatPhase()
+{
+ return s_liveBeatPhase.load(std::memory_order_relaxed);
+}
+
+uint32_t AudioAnalyzer_GetBeatCount()
+{
+ return s_liveBeatCount.load(std::memory_order_relaxed);
+}
+
+void AudioAnalyzer_ResetBeatPhase()
+{
+ s_resetBeatPhase.store(true, std::memory_order_relaxed);
+ s_liveBeatCount.store(0, std::memory_order_relaxed);
+}
+
+float AudioAnalyzer_TapTempo()
+{
+ using Clock = std::chrono::steady_clock;
+ using Sec = std::chrono::duration;
+
+ static constexpr int kMaxTaps = 8;
+ static Clock::time_point s_taps[kMaxTaps];
+ static int s_tapCount = 0;
+
+ const auto now = Clock::now();
+
+ if (s_tapCount > 0)
+ {
+ if (Sec(now - s_taps[(s_tapCount - 1) % kMaxTaps]).count() > 3.0)
+ s_tapCount = 0;
+ }
+
+ s_taps[s_tapCount % kMaxTaps] = now;
+ ++s_tapCount;
+
+ if (s_tapCount < 2)
+ return 0.0f;
+
+ const int n = std::min(s_tapCount, kMaxTaps);
+ const int oldest = (s_tapCount - n) % kMaxTaps;
+ const int newest = (s_tapCount - 1) % kMaxTaps;
+ const double totalSec = Sec(s_taps[newest] - s_taps[oldest]).count();
+ if (totalSec <= 0.0)
+ return 0.0f;
+
+ const float bpm = static_cast(60.0 * (n - 1) / totalSec);
+ return (bpm >= 40.0f && bpm <= 250.0f) ? bpm : 0.0f;
+}
+
+// ── Background thread ─────────────────────────────────────────────────────────
+
+void AudioAnalyzer::Start()
+{
+ if (m_Running.exchange(true))
+ return; // already running
+ m_Thread = std::thread(&AudioAnalyzer::ThreadProc, this);
+}
+
+void AudioAnalyzer::Stop()
+{
+ if (!m_Running.exchange(false))
+ return; // already stopped
+ if (m_Thread.joinable())
+ m_Thread.join();
+}
+
+AudioFeatures AudioAnalyzer::GetFeaturesSnapshot() const
+{
+ std::lock_guard lock(m_FeaturesMutex);
+ return m_Features;
+}
+
+void AudioAnalyzer::ThreadProc()
+{
+ using Clock = std::chrono::steady_clock;
+
+ std::deque sampleBuffer;
+ AubioState aubio;
+
+ // Per-thread state (was static locals in Update())
+ float bassPeak = 0.001f, midPeak = 0.001f, highPeak = 0.001f;
+ int warmup = 0;
+ float s_prevBass = 0.0f, s_prevMid = 0.0f, s_prevHigh = 0.0f;
+ float s_acfBpm = 120.0f;
+ uint_t s_totalHops = 0;
+ BeatDetektor bd_slow(60.0f, 119.0f); // covers 60–119 BPM
+ BeatDetektor bd_fast(120.0f, 239.0f); // covers 120–239 BPM
+ std::vector bdFftVec(kNumBins, 0.0f);
+ float s_beatPhase = 0.0f;
+ float s_beatInterval = 60.0f / 120.0f;
+ int s_beatCount = 0;
+ float volume = 0.0f;
+ float spectralCentroid = 0.0f;
+ float kick = 0.0f, snare = 0.0f, transient = 0.0f;
+
+ // Silence tracking uses wall clock since audio may be sparse
+ auto silenceStart = Clock::now();
+ bool inSilence = false;
+
+ if (!m_AudioInput.IsRunning())
+ m_AudioInput.Start();
+
+ aubio.Init();
+
+ while (m_Running.load(std::memory_order_relaxed))
+ {
+ // Pull new samples from WASAPI
+ std::vector newSamples = m_AudioInput.GetSamples();
+ for (float s : newSamples)
+ sampleBuffer.push_back(s);
+
+ // Bound the backlog (~200 ms) so start-up after a stall stays smooth
+ constexpr size_t kMaxBufferSamples = kHopSize * 18;
+ if (sampleBuffer.size() > kMaxBufferSamples)
+ sampleBuffer.erase(sampleBuffer.begin(),
+ sampleBuffer.begin() +
+ static_cast(sampleBuffer.size() - kMaxBufferSamples));
+
+ if (sampleBuffer.size() < kHopSize)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ continue;
+ }
+
+ if (!aubio.ready)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ continue;
+ }
+
+ // Process all available hops — thread runs continuously so no per-call cap needed
+ float bassEnergyAcc = 0.0f, midEnergyAcc = 0.0f, highEnergyAcc = 0.0f;
+ float centroidNum = 0.0f, centroidDen = 0.0f;
+ float rmsAcc = 0.0f;
+ int hops = 0;
+ bool beatFired = false;
+
+ while (sampleBuffer.size() >= kHopSize)
+ {
+ for (uint_t i = 0; i < kHopSize; ++i)
+ {
+ const float s = sampleBuffer[i];
+ aubio.hopIn->data[i] = s;
+ rmsAcc += s * s;
+ }
+ for (uint_t i = 0; i < kHopSize; ++i)
+ sampleBuffer.pop_front();
+
+ aubio_pvoc_do(aubio.pvoc, aubio.hopIn, aubio.fftgrain);
+
+ for (uint_t bin = 1; bin < kNumBins; ++bin)
+ {
+ const float mag = aubio.fftgrain->norm[bin];
+ const float f = (float)kSampleRate * bin / (float)kWinSize;
+ if (f >= 20.0f && f < 20000.0f)
+ {
+ centroidNum += f * mag;
+ centroidDen += mag;
+ }
+ }
+
+ aubio_filterbank_do(aubio.filterbank, aubio.fftgrain, aubio.melOut);
+ float bassEnergy = 0.0f, midEnergy = 0.0f, highEnergy = 0.0f;
+ for (uint_t b = 0; b < 8; ++b) bassEnergy += aubio.melOut->data[b];
+ for (uint_t b = 8; b < 28; ++b) midEnergy += aubio.melOut->data[b];
+ for (uint_t b = 28; b < 40; ++b) highEnergy += aubio.melOut->data[b];
+ bassEnergy /= 8.0f;
+ midEnergy /= 20.0f;
+ highEnergy /= 12.0f;
+
+ bassEnergyAcc += bassEnergy;
+ midEnergyAcc += midEnergy;
+ highEnergyAcc += highEnergy;
+
+ aubio_tempo_do(aubio.tempo, aubio.hopIn, aubio.tempoOut);
+ if (aubio.tempoOut->data[0] > 0.0f) beatFired = true;
+
+ // Feed BeatDetektor — reuse aubio's per-hop FFT magnitudes, zero extra FFT cost
+ ++s_totalHops;
+ {
+ const float hopTimeSec = float(s_totalHops) * float(kHopSize) / float(kSampleRate);
+ for (uint_t bin = 0; bin < kNumBins; ++bin)
+ bdFftVec[bin] = aubio.fftgrain->norm[bin];
+ bd_slow.process(hopTimeSec, bdFftVec);
+ bd_fast.process(hopTimeSec, bdFftVec);
+ }
+
+ ++hops;
+ }
+
+ if (hops == 0)
+ continue;
+
+ const float bassEnergy = bassEnergyAcc / hops;
+ const float midEnergy = midEnergyAcc / hops;
+ const float highEnergy = highEnergyAcc / hops;
+ const float rawLevel = std::sqrt(rmsAcc / (hops * (int)kHopSize));
+
+ // RMS volume
+ float clampedLevel = rawLevel;
+ if (clampedLevel < DbToLinear(-60.0f))
+ clampedLevel = 0.0f;
+ clampedLevel = Clamp01(clampedLevel * 3.0f);
+ volume = SmoothAttackRelease(volume, clampedLevel, 0.35f, 0.08f);
+
+ // Spectral centroid
+ float rawCentroid = 0.0f;
+ if (centroidDen > 0.0f)
+ rawCentroid = centroidNum / centroidDen;
+ const float logMin = std::log(20.0f);
+ const float logMax = std::log(20000.0f);
+ float logCentroid = 0.0f;
+ if (rawCentroid > 0.0f)
+ logCentroid = (std::log(rawCentroid) - logMin) / (logMax - logMin);
+ spectralCentroid = SmoothAttackRelease(spectralCentroid, Clamp01(logCentroid), 0.3f, 0.1f);
+
+ // Adaptive normalisation — read settings once per thread iteration, not per hop
+ const float kPeakDecay = g_Settings()->Get("settings.player.audio_peak_decay", 0.999f);
+ const float kPeakFloor = g_Settings()->Get("settings.player.audio_peak_floor", 0.01f);
+ const float bassMult = g_Settings()->Get("settings.player.audio_bass_mult", 0.7f);
+ const float midMult = g_Settings()->Get("settings.player.audio_mid_mult", 0.8f);
+ const float highMult = g_Settings()->Get("settings.player.audio_high_mult", 0.7f);
+
+ bassPeak = std::max({bassEnergy, bassPeak * kPeakDecay, kPeakFloor});
+ midPeak = std::max({midEnergy, midPeak * kPeakDecay, kPeakFloor});
+ highPeak = std::max({highEnergy, highPeak * kPeakDecay, kPeakFloor});
+
+ // gamma=2: squares the normalised ratio so quiet passages (e.g. 20% of peak)
+ // read ~0.04 instead of 0.20. Peaks still reach 1.0; only the curve changes.
+ constexpr float kGamma = 2.0f;
+
+ float normBass, normMid, normHigh;
+ if (warmup < 90)
+ {
+ ++warmup;
+ normBass = Clamp01(std::pow(bassEnergy * 120.0f, kGamma));
+ normMid = Clamp01(std::pow(midEnergy * 80.0f, kGamma));
+ normHigh = Clamp01(std::pow(highEnergy * 60.0f, kGamma));
+ }
+ else
+ {
+ normBass = Clamp01(std::pow(bassEnergy / bassPeak, kGamma) * bassMult);
+ normMid = Clamp01(std::pow(midEnergy / midPeak, kGamma) * midMult);
+ normHigh = Clamp01(std::pow(highEnergy / highPeak, kGamma) * highMult);
+ }
+
+ // Kick / snare / transient
+ // volume is RMS-based and doesn't adapt away like normBass/normMid, so it's a reliable
+ // gate against ambient content in quiet sections where the adaptive peak has decayed to floor.
+ const float bassDelta = normBass - s_prevBass;
+ const float midDelta = normMid - s_prevMid;
+ const float highDelta = normHigh - s_prevHigh;
+ // Require onset from a low prior level: percussion attacks from near-silence;
+ // sustained bass/mid content (guitar, synth) keeps s_prevBass/s_prevMid elevated.
+ const bool kickFired = volume > 0.30f && normBass > 0.35f && bassDelta > 0.22f && s_prevBass < 0.25f;
+ const bool snareFired = volume > 0.30f && normMid > 0.25f && midDelta > 0.22f && midDelta > bassDelta * 1.5f && s_prevMid < 0.20f;
+ const bool transientFired = volume > 0.25f && std::max({normBass, normMid, normHigh}) > 0.20f &&
+ (bassDelta + midDelta + highDelta) / 3.0f > 0.26f;
+ s_prevBass = normBass; s_prevMid = normMid; s_prevHigh = normHigh;
+
+ // BPM — BeatDetektor primary; aubio onset confidence still drives phase correction below
+ const float overrideBpm = s_bpmOverride.load(std::memory_order_relaxed);
+ const float aubioConf = aubio_tempo_get_confidence(aubio.tempo);
+ if (overrideBpm > 0.0f)
+ {
+ s_acfBpm = overrideBpm;
+ }
+ else
+ {
+ const bool slowWins = (bd_slow.win_val >= bd_fast.win_val);
+ const float bdPeriod = slowWins ? bd_slow.winning_bpm : bd_fast.winning_bpm; // seconds per beat
+ const float bdConf = slowWins ? bd_slow.win_val : bd_fast.win_val;
+ const float bdBpm = (bdPeriod > 0.0f) ? (60.0f / bdPeriod) : 0.0f;
+
+ // win_val >= 20 is the minimum reliable reading; 60 = finish line (high confidence)
+ if (bdConf >= 20.0f && bdBpm >= 40.0f && bdBpm <= 250.0f)
+ {
+ // Fold octave errors: BeatDetektor sometimes locks onto 2x or 0.5x the true tempo
+ float candidate = bdBpm;
+ if (s_acfBpm > 0.0f)
+ {
+ const float r = candidate / s_acfBpm;
+ if (r > 1.8f && r < 2.2f) candidate *= 0.5f;
+ else if (r > 0.45f && r < 0.55f) candidate *= 2.0f;
+ }
+ // Scale alpha by proximity: full rate within 8% of current estimate, zero at 20%+
+ // This prevents a bad detection frame from yanking the estimate far off track.
+ const float baseAlpha = Clamp01((bdConf - 20.0f) / 40.0f) * 0.05f;
+ const float deviation = (s_acfBpm > 0.0f) ? std::abs(candidate / s_acfBpm - 1.0f) : 0.0f;
+ const float alpha = baseAlpha * Clamp01(1.0f - deviation / 0.15f);
+ s_acfBpm = s_acfBpm * (1.0f - alpha) + candidate * alpha;
+ s_acfBpm = std::max(40.0f, std::min(250.0f, s_acfBpm));
+ }
+ }
+ s_liveBpm.store(s_acfBpm, std::memory_order_relaxed);
+
+ // Beat phase — advance driven by BeatDetektor BPM; aubio onsets correct phase
+ if (s_resetBeatPhase.exchange(false, std::memory_order_relaxed))
+ {
+ s_beatPhase = 0.0f;
+ s_beatCount = 0;
+ }
+
+ if (beatFired && aubioConf > 0.12f) ++s_beatCount;
+
+ s_beatInterval = 60.0f / s_acfBpm;
+
+ const float audioDt = float(hops) * float(kHopSize) / float(kSampleRate);
+ s_beatPhase += audioDt / s_beatInterval;
+
+ if (s_beatPhase >= 1.0f)
+ {
+ const uint32_t wraps = static_cast(s_beatPhase);
+ s_beatPhase = std::fmod(s_beatPhase, 1.0f);
+ s_liveBeatCount.fetch_add(wraps, std::memory_order_relaxed);
+ }
+
+ const bool bpmLocked = (overrideBpm > 0.0f);
+ if (!bpmLocked && beatFired && aubioConf > 0.12f && s_beatCount >= 4)
+ {
+ const float err = s_beatPhase > 0.5f ? s_beatPhase - 1.0f : s_beatPhase;
+ const float gain = 0.5f + aubioConf * 0.4f;
+ s_beatPhase -= err * gain;
+ if (s_beatPhase < 0.0f) s_beatPhase += 1.0f;
+ }
+
+ s_liveBeatPhase.store(s_beatPhase, std::memory_order_relaxed);
+
+ // Silence gate — use wall clock (audio thread runs even when signal is absent)
+ bool hasSignal;
+ if (clampedLevel > 0.005f)
+ {
+ silenceStart = Clock::now();
+ inSilence = false;
+ hasSignal = true;
+ }
+ else
+ {
+ using FSec = std::chrono::duration;
+ const float silenceSec = FSec(Clock::now() - silenceStart).count();
+ inSilence = (silenceSec > 1.5f);
+ hasSignal = !inSilence;
+ }
+
+ // Publish features — brief lock, render thread gets a copy
+ kick = SmoothAttackRelease(kick, kickFired ? 1.0f : 0.0f, 0.90f, 0.06f);
+ snare = SmoothAttackRelease(snare, snareFired ? 1.0f : 0.0f, 0.85f, 0.07f);
+ transient = SmoothAttackRelease(transient, transientFired ? 1.0f : 0.0f, 0.80f, 0.08f);
+
+ {
+ std::lock_guard lock(m_FeaturesMutex);
+ m_Features.volume = volume;
+ m_Features.bass = normBass;
+ m_Features.mid = normMid;
+ m_Features.high = normHigh;
+ m_Features.spectralCentroid = spectralCentroid;
+ m_Features.kick = kick;
+ m_Features.snare = snare;
+ m_Features.transient = transient;
+ m_Features.beatPhase = s_beatPhase;
+ m_Features.bpm = s_acfBpm;
+ m_Features.hasSignal = hasSignal;
+ m_Features.sampleCount = static_cast(sampleBuffer.size());
+ }
+ }
+}
diff --git a/client_generic/Client/AudioAnalyzer.h b/client_generic/Client/AudioAnalyzer.h
new file mode 100644
index 00000000..307ba668
--- /dev/null
+++ b/client_generic/Client/AudioAnalyzer.h
@@ -0,0 +1,56 @@
+#ifndef AUDIO_ANALYZER_H_INCLUDED
+#define AUDIO_ANALYZER_H_INCLUDED
+
+#include
+#include
+#include
+#include
+
+// Manual BPM control — callable from any thread/UI
+void AudioAnalyzer_SetBpmOverride(float bpm); // 0 = release override, resume auto-detect
+float AudioAnalyzer_TapTempo(); // call on each tap; returns new BPM (0 if < 2 taps yet)
+float AudioAnalyzer_GetCurrentBpm(); // live read of the current BPM estimate
+float AudioAnalyzer_GetBeatPhase(); // 0..1 position within current beat cycle
+uint32_t AudioAnalyzer_GetBeatCount(); // monotonically increasing beat counter (wraps at 4B beats)
+void AudioAnalyzer_ResetBeatPhase(); // snap beat phase to 0 (beat 1) on next process loop
+
+#include "AudioInputWasapi.h"
+
+struct AudioFeatures
+{
+ float volume = 0.0f;
+ float bass = 0.0f;
+ float mid = 0.0f;
+ float high = 0.0f;
+ float spectralCentroid = 0.0f;
+ float kick = 0.0f; // narrowband onset pulse: 30–200 Hz
+ float snare = 0.0f; // narrowband onset pulse: 200–800 Hz
+ float transient = 0.0f; // broadband onset pulse: any transient
+ float beatPhase = 0.0f; // 0..1 position within current beat cycle
+ float bpm = 120.0f;
+ bool hasSignal = false;
+ int sampleCount = 0;
+};
+
+class AudioAnalyzer
+{
+ public:
+ ~AudioAnalyzer() { Stop(); }
+
+ void Start(); // launch background processing thread
+ void Stop(); // stop thread and join (safe to call multiple times)
+
+ // Thread-safe snapshot for the render loop — never blocks for more than a mutex acquire.
+ AudioFeatures GetFeaturesSnapshot() const;
+
+ private:
+ void ThreadProc();
+
+ AudioInputWasapi m_AudioInput;
+ AudioFeatures m_Features;
+ mutable std::mutex m_FeaturesMutex;
+ std::thread m_Thread;
+ std::atomic m_Running{false};
+};
+
+#endif
diff --git a/client_generic/Client/AudioInputWasapi.cpp b/client_generic/Client/AudioInputWasapi.cpp
new file mode 100644
index 00000000..6e8a98aa
--- /dev/null
+++ b/client_generic/Client/AudioInputWasapi.cpp
@@ -0,0 +1,244 @@
+#include "AudioInputWasapi.h"
+
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "Ole32.lib")
+
+AudioInputWasapi::AudioInputWasapi() {}
+
+AudioInputWasapi::~AudioInputWasapi() { Stop(); }
+
+bool AudioInputWasapi::Start()
+{
+ HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
+ {
+ return false;
+ }
+
+ IMMDeviceEnumerator* enumerator = nullptr;
+ hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
+ __uuidof(IMMDeviceEnumerator),
+ reinterpret_cast(&enumerator));
+
+ if (FAILED(hr) || !enumerator)
+ {
+ return false;
+ }
+
+ hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_Device);
+ enumerator->Release();
+
+ if (FAILED(hr) || !m_Device)
+ {
+ return false;
+ }
+
+ hr = m_Device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr,
+ reinterpret_cast(&m_AudioClient));
+
+ if (FAILED(hr) || !m_AudioClient)
+ {
+ return false;
+ }
+
+ WAVEFORMATEX* mixFormat = nullptr;
+ hr = m_AudioClient->GetMixFormat(&mixFormat);
+
+ if (FAILED(hr) || !mixFormat)
+ {
+ return false;
+ }
+ m_ChannelCount = mixFormat->nChannels;
+ if (m_ChannelCount <= 0)
+ m_ChannelCount = 2;
+
+ hr = m_AudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0,
+ mixFormat, nullptr);
+
+ CoTaskMemFree(mixFormat);
+
+ if (FAILED(hr))
+ {
+ return false;
+ }
+
+ hr = m_AudioClient->GetService(__uuidof(IAudioCaptureClient),
+ reinterpret_cast(&m_CaptureClient));
+
+ if (FAILED(hr) || !m_CaptureClient)
+ {
+ return false;
+ }
+
+ hr = m_AudioClient->Start();
+
+ if (FAILED(hr))
+ {
+ return false;
+ }
+
+ m_Running = true;
+ m_Level = 0.0f;
+
+ return true;
+}
+
+void AudioInputWasapi::Stop()
+{
+ if (m_AudioClient)
+ {
+ m_AudioClient->Stop();
+ }
+
+ if (m_CaptureClient)
+ {
+ m_CaptureClient->Release();
+ m_CaptureClient = nullptr;
+ }
+
+ if (m_AudioClient)
+ {
+ m_AudioClient->Release();
+ m_AudioClient = nullptr;
+ }
+
+ if (m_Device)
+ {
+ m_Device->Release();
+ m_Device = nullptr;
+ }
+
+ m_Running = false;
+ m_Level = 0.0f;
+}
+
+bool AudioInputWasapi::IsRunning() const { return m_Running; }
+
+float AudioInputWasapi::GetLevel() const
+{
+ if (!m_CaptureClient)
+ return 0.0f;
+
+ UINT32 packetLength = 0;
+ HRESULT hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+
+ float level = 0.0f;
+ int sampleCount = 0;
+
+ while (SUCCEEDED(hr) && packetLength > 0)
+ {
+ BYTE* data = nullptr;
+ UINT32 numFrames = 0;
+ DWORD flags = 0;
+
+ hr = m_CaptureClient->GetBuffer(&data, &numFrames, &flags, nullptr,
+ nullptr);
+
+ if (FAILED(hr))
+ break;
+
+ // assume float samples (common for WASAPI mix format)
+ float* samples = reinterpret_cast(data);
+
+ for (UINT32 i = 0; i < numFrames; ++i)
+ {
+ float s = samples[i];
+ level += s * s;
+ sampleCount++;
+ }
+
+ m_CaptureClient->ReleaseBuffer(numFrames);
+
+ hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+ }
+
+ if (sampleCount > 0)
+ {
+ level = std::sqrtf(level / sampleCount);
+ }
+
+ return level;
+}
+std::vector AudioInputWasapi::GetSamples()
+{
+ std::vector samplesOut;
+
+ if (!m_CaptureClient)
+ return samplesOut;
+
+ UINT32 packetLength = 0;
+ HRESULT hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+
+ while (SUCCEEDED(hr) && packetLength > 0)
+ {
+ BYTE* data = nullptr;
+ UINT32 numFrames = 0;
+ DWORD flags = 0;
+
+ hr = m_CaptureClient->GetBuffer(&data, &numFrames, &flags, nullptr,
+ nullptr);
+
+ if (FAILED(hr))
+ break;
+
+ float* samples = reinterpret_cast(data);
+
+ for (UINT32 frame = 0; frame < numFrames; ++frame)
+ {
+ float mono = 0.0f;
+
+ for (int ch = 0; ch < m_ChannelCount; ++ch)
+ {
+ mono += samples[(frame * m_ChannelCount) + ch];
+ }
+
+ mono /= static_cast(m_ChannelCount);
+ samplesOut.push_back(mono);
+ }
+
+ m_CaptureClient->ReleaseBuffer(numFrames);
+
+ hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+ }
+
+ return samplesOut;
+}
+StereoSamples AudioInputWasapi::GetStereoSamples()
+{
+ StereoSamples out;
+
+ if (!m_CaptureClient || m_ChannelCount < 2)
+ return out;
+
+ UINT32 packetLength = 0;
+ HRESULT hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+
+ while (SUCCEEDED(hr) && packetLength > 0)
+ {
+ BYTE* data = nullptr;
+ UINT32 numFrames = 0;
+ DWORD flags = 0;
+
+ hr = m_CaptureClient->GetBuffer(&data, &numFrames, &flags, nullptr,
+ nullptr);
+ if (FAILED(hr))
+ break;
+
+ float* samples = reinterpret_cast(data);
+ for (UINT32 frame = 0; frame < numFrames; ++frame)
+ {
+ out.left.push_back(samples[(frame * m_ChannelCount) + 0]);
+ out.right.push_back(samples[(frame * m_ChannelCount) + 1]);
+ }
+
+ m_CaptureClient->ReleaseBuffer(numFrames);
+ hr = m_CaptureClient->GetNextPacketSize(&packetLength);
+ }
+
+ return out;
+}
\ No newline at end of file
diff --git a/client_generic/Client/AudioInputWasapi.h b/client_generic/Client/AudioInputWasapi.h
new file mode 100644
index 00000000..c4f5ac2b
--- /dev/null
+++ b/client_generic/Client/AudioInputWasapi.h
@@ -0,0 +1,38 @@
+#ifndef AUDIO_INPUT_WASAPI_H_INCLUDED
+#define AUDIO_INPUT_WASAPI_H_INCLUDED
+
+#include
+#include
+#include
+
+struct StereoSamples
+{
+ std::vector left;
+ std::vector right;
+};
+
+class AudioInputWasapi
+{
+ public:
+ AudioInputWasapi();
+ ~AudioInputWasapi();
+
+ bool Start();
+ void Stop();
+
+ bool IsRunning() const;
+ float GetLevel() const;
+ std::vector GetSamples();
+ StereoSamples GetStereoSamples();
+
+ private:
+ bool m_Running = false;
+ float m_Level = 0.0f;
+ int m_ChannelCount = 2;
+
+ IAudioClient* m_AudioClient = nullptr;
+ IAudioCaptureClient* m_CaptureClient = nullptr;
+ IMMDevice* m_Device = nullptr;
+};
+
+#endif
\ No newline at end of file
diff --git a/client_generic/Client/AudioPanelWin32.cpp b/client_generic/Client/AudioPanelWin32.cpp
new file mode 100644
index 00000000..7ebb2686
--- /dev/null
+++ b/client_generic/Client/AudioPanelWin32.cpp
@@ -0,0 +1,457 @@
+#ifdef WIN32
+
+#include "AudioPanelWin32.h"
+#include "AudioAnalyzer.h"
+#include "Settings.h"
+
+#include "imgui.h"
+#include "imgui_impl_dx11.h"
+#include "imgui_impl_win32.h"
+#include "../DisplayOutput/D3D11/DisplayDX11.h"
+#include "Player.h"
+#include "SettingsDialogWin32.h"
+
+#include
+#include
+
+
+
+// ── Panel state ───────────────────────────────────────────────────────────────
+static std::atomic g_audioPanelVisible{false};
+static bool g_imguiInitialized = false;
+
+void AudioPanelWin32_SetVisible(bool visible)
+{
+ g_audioPanelVisible.store(visible, std::memory_order_release);
+}
+
+bool AudioPanelWin32_IsVisible()
+{
+ return g_audioPanelVisible.load(std::memory_order_acquire);
+}
+
+// ── ImGui init/shutdown ───────────────────────────────────────────────────────
+static void TryInitImGui(ID3D11Device* device, ID3D11DeviceContext* ctx)
+{
+ if (g_imguiInitialized)
+ return;
+ auto* dx =
+ dynamic_cast(g_Player().Display().get());
+ if (!dx)
+ return;
+ HWND hwnd = dx->GetWindowHandle();
+ if (!hwnd)
+ return;
+ IMGUI_CHECKVERSION();
+ ImGui::CreateContext();
+ ImGui::GetIO().IniFilename = nullptr;
+ ImGui_ImplWin32_Init(hwnd);
+ ImGui_ImplDX11_Init(device, ctx);
+ g_imguiInitialized = true;
+}
+
+static void ShutdownImGui()
+{
+ if (!g_imguiInitialized)
+ return;
+ if (g_Settings()->Storage())
+ g_Settings()->Storage()->Commit();
+ ImGui_ImplDX11_Shutdown();
+ ImGui_ImplWin32_Shutdown();
+ ImGui::DestroyContext();
+ g_imguiInitialized = false;
+}
+
+bool AudioPanelWin32_TryConsumeWndProc(HWND hWnd, UINT msg, WPARAM wParam,
+ LPARAM lParam, LRESULT* outResult)
+{
+ if (!g_audioPanelVisible.load(std::memory_order_acquire) ||
+ !g_imguiInitialized)
+ return false;
+
+ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(
+ HWND, UINT, WPARAM, LPARAM);
+ const LRESULT r = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
+
+ // Unlike modal dialogs, the audio panel is a non-modal overlay. Only consume
+ // input when ImGui actually wants it — otherwise native chrome interactions
+ // (close/min/max buttons) are swallowed even when the cursor isn't near the panel.
+ const ImGuiIO& io = ImGui::GetIO();
+ const bool isMouse = (msg == WM_MOUSEMOVE || msg == WM_LBUTTONDOWN ||
+ msg == WM_LBUTTONUP || msg == WM_RBUTTONDOWN ||
+ msg == WM_RBUTTONUP || msg == WM_MBUTTONDOWN ||
+ msg == WM_MBUTTONUP || msg == WM_MOUSEWHEEL ||
+ msg == WM_MOUSEHWHEEL);
+ const bool isKey = (msg == WM_KEYDOWN || msg == WM_KEYUP ||
+ msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP || msg == WM_CHAR);
+ if ((isMouse && !io.WantCaptureMouse) || (isKey && !io.WantCaptureKeyboard))
+ return false;
+
+ if (r != 0)
+ {
+ if (outResult)
+ *outResult = r;
+ return true;
+ }
+ return false;
+}
+
+// ── Main render function ──────────────────────────────────────────────────────
+bool AudioPanelWin32_RenderIfNeeded(ID3D11Device* device,
+ ID3D11DeviceContext* ctx,
+ ID3D11RenderTargetView* rtv,
+ float viewportW, float viewportH)
+{
+ const bool visible = g_audioPanelVisible.load(std::memory_order_acquire);
+
+ if (!visible)
+ {
+ if (g_imguiInitialized)
+ ShutdownImGui();
+ return false;
+ }
+
+ TryInitImGui(device, ctx);
+ if (!g_imguiInitialized)
+ return false;
+
+ ctx->OMSetRenderTargets(1, &rtv, nullptr);
+
+ ImGui_ImplDX11_NewFrame();
+ ImGui_ImplWin32_NewFrame();
+ ImGui::NewFrame();
+
+ const float margin = 16.0f;
+ const float panelW = 300.0f;
+ ImGui::SetNextWindowPos(ImVec2(margin, margin), ImGuiCond_Always);
+ ImGui::SetNextWindowSizeConstraints(ImVec2(panelW, 0), ImVec2(panelW, viewportH - margin * 2));
+ ImGui::SetNextWindowBgAlpha(0.6f);
+
+ ImGuiWindowFlags flags =
+ ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
+ ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
+ ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysAutoResize;
+
+ ImGui::Begin("##AudioPanel", nullptr, flags);
+
+ ImGui::TextUnformatted("Audio Reactive");
+ ImGui::Separator();
+
+ // ── Helpers ───────────────────────────────────────────────────────────────
+
+ static const char* kCutStyles[] = {"Hard (0.05s)", "Fast (0.2s)", "Slow (2.0s)"};
+ static const char* kMixSources[] = {"Bass", "Mid", "High", "Centroid", "Kick", "Snare", "Transient", "Beat Phase"};
+
+ const auto tip = [](const char* text) {
+ if (ImGui::IsItemHovered())
+ ImGui::SetTooltip("%s", text);
+ };
+
+ const auto drawSlider = [](const char* label, float* val, float vmin, float vmax,
+ const char* key, const char* fmt = "%.2f")
+ {
+ ImGui::TextUnformatted(label);
+ ImGui::SameLine(110.0f);
+ ImGui::PushItemWidth(-1);
+ if (ImGui::SliderFloat((std::string("##") + label).c_str(), val, vmin, vmax, fmt))
+ g_Settings()->Set(key, *val);
+ ImGui::PopItemWidth();
+ };
+
+ const auto drawSliderInt = [](const char* label, int* val, int vmin, int vmax, const char* key)
+ {
+ ImGui::TextUnformatted(label);
+ ImGui::SameLine(110.0f);
+ ImGui::PushItemWidth(-1);
+ if (ImGui::SliderInt((std::string("##") + label).c_str(), val, vmin, vmax))
+ g_Settings()->Set(key, *val);
+ ImGui::PopItemWidth();
+ };
+
+ const auto drawCombo = [](const char* label, int* val,
+ const char* const* items, int n, const char* key)
+ {
+ ImGui::TextUnformatted(label);
+ ImGui::SameLine(110.0f);
+ ImGui::PushItemWidth(-1);
+ if (ImGui::Combo((std::string("##") + label).c_str(), val, items, n))
+ g_Settings()->Set(key, *val);
+ ImGui::PopItemWidth();
+ };
+
+ const auto drawCheck = [](const char* label, bool* val, const char* key)
+ {
+ if (ImGui::Checkbox(label, val))
+ g_Settings()->Set(key, *val);
+ };
+
+ // Checkbox + slider on one row; slider is greyed when checkbox is off.
+ // checkTip shown on checkbox hover, sliderTip shown on slider hover (works even when disabled).
+ const auto drawWeightRow = [&](const char* checkId, bool* use, const char* useKey,
+ const char* label, float* val, const char* valKey,
+ const char* checkTip, const char* sliderTip)
+ {
+ if (ImGui::Checkbox(checkId, use))
+ g_Settings()->Set(useKey, *use);
+ if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", checkTip);
+ ImGui::SameLine(0, 2);
+ ImGui::BeginDisabled(!(*use));
+ ImGui::TextUnformatted(label);
+ ImGui::SameLine(110.0f);
+ ImGui::PushItemWidth(-1);
+ if (ImGui::SliderFloat((std::string("##") + label).c_str(), val, 0.0f, 1.0f, "%.2f"))
+ g_Settings()->Set(valKey, *val);
+ if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
+ ImGui::SetTooltip("%s", sliderTip);
+ ImGui::PopItemWidth();
+ ImGui::EndDisabled();
+ };
+
+ // ── Analyser ──────────────────────────────────────────────────────────────
+ if (ImGui::CollapsingHeader("Analyser", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ drawSlider("Bass", &g_audioBassMult, 0.5f, 2.0f, "settings.player.audio_bass_mult");
+ tip("Multiplier on normalised bass energy (20-200 Hz).");
+ drawSlider("Mid", &g_audioMidMult, 0.5f, 2.0f, "settings.player.audio_mid_mult");
+ tip("Multiplier on normalised mid energy (200-4000 Hz).");
+ drawSlider("High", &g_audioHighMult, 0.5f, 2.0f, "settings.player.audio_high_mult");
+ tip("Multiplier on normalised high energy (4-11 kHz).");
+ drawSlider("Peak decay", &g_audioPeakDecay, 0.95f, 0.99999f,"settings.player.audio_peak_decay", "%.5f");
+ tip("How slowly the per-band peak normalisation decays. Higher = longer memory, slower adaptation.");
+ drawSlider("Peak floor", &g_audioPeakFloor, 0.0f, 0.1f, "settings.player.audio_peak_floor", "%.4f");
+ tip("Minimum peak value — prevents normalisation from chasing the noise floor during quiet passages.\n"
+ "Raise this if bands read too high during silence or quiet sections.");
+ drawSlider("Dark brt", &g_audioDarkBrightness,-1.0f, 0.0f, "settings.player.audio_dark_brightness");
+ tip("Brightness floor when no audio signal is present.");
+ }
+
+ // ── Beat ──────────────────────────────────────────────────────────────────
+ if (ImGui::CollapsingHeader("Beat", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ static bool s_bpmLocked = false;
+ static float s_lockedBpm = 120.0f;
+
+ // Beat count is monotonically incremented by the audio thread on every beat wrap.
+ // Deriving beatIndex from it (rather than detecting phase wraps per frame) handles
+ // multiple beats per render frame correctly after a dream change drains audio backlog.
+ const uint32_t beatCount = AudioAnalyzer_GetBeatCount();
+ const float phase = AudioAnalyzer_GetBeatPhase();
+ const int s_beatIndex = static_cast(beatCount % 4);
+
+ // BPM readout + Tap + Reset on one row
+ const float liveBpm = AudioAnalyzer_GetCurrentBpm();
+ ImGui::Text("Live BPM: %.1f", liveBpm);
+ ImGui::SameLine(110.0f);
+ const float halfW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
+ if (ImGui::Button("Tap##bpm", ImVec2(halfW, 0)))
+ {
+ const float tapped = AudioAnalyzer_TapTempo();
+ if (tapped > 0.0f)
+ {
+ s_lockedBpm = tapped;
+ s_bpmLocked = true;
+ }
+ }
+ tip("Tap to the beat. Locks BPM automatically once two or more taps are recorded.\n"
+ "Resets if you stop tapping for more than 3 seconds.");
+ ImGui::SameLine();
+ if (ImGui::Button("Reset##beat", ImVec2(-1, 0)))
+ AudioAnalyzer_ResetBeatPhase();
+ tip("Snap beat phase to beat 1 immediately.");
+
+ // 4-box beat visualizer — box 1 is beat 1, pulses on each beat
+ {
+ const float avail = ImGui::GetContentRegionAvail().x;
+ const float gap = 4.0f;
+ const float boxW = (avail - gap * 3.0f) / 4.0f;
+ const float boxH = 22.0f;
+
+ ImDrawList* dl = ImGui::GetWindowDrawList();
+ const ImVec2 pos = ImGui::GetCursorScreenPos();
+
+ for (int i = 0; i < 4; ++i)
+ {
+ const float x = pos.x + i * (boxW + gap);
+ const bool active = (i == s_beatIndex);
+ // Pulse: bright at phase=0, half-bright at phase=1
+ const float pulse = active ? (1.0f - phase * 0.5f) : 0.0f;
+ const int alpha = active ? (int)(pulse * 200.0f) + 40 : 110;
+
+ ImU32 fillCol;
+ if (i == 0)
+ fillCol = active ? IM_COL32(255, 210, 40, alpha) // beat 1: gold
+ : IM_COL32(80, 65, 15, alpha);
+ else
+ fillCol = active ? IM_COL32(140, 140, 255, alpha) // beats 2-4: blue-white
+ : IM_COL32(45, 45, 45, alpha);
+
+ dl->AddRectFilled(ImVec2(x, pos.y), ImVec2(x + boxW, pos.y + boxH),
+ fillCol, 3.0f);
+
+ char num[4];
+ snprintf(num, sizeof(num), "%d", i + 1);
+ const ImVec2 tsz = ImGui::CalcTextSize(num);
+ dl->AddText(ImVec2(x + (boxW - tsz.x) * 0.5f, pos.y + (boxH - tsz.y) * 0.5f),
+ active ? IM_COL32(255, 255, 255, 255) : IM_COL32(160, 160, 160, 180),
+ num);
+ }
+ ImGui::Dummy(ImVec2(avail, boxH));
+ }
+
+ // Tempo nudge — hold to temporarily shift tempo ±5%; release restores locked BPM exactly.
+ // Auto-locks at current BPM on first press if not already locked.
+ float nudgeFactor = 0.0f;
+ {
+ const float nudgeW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
+ ImGui::Button("< Slow##nudge", ImVec2(nudgeW, 0));
+ if (ImGui::IsItemActivated() && !s_bpmLocked)
+ {
+ s_lockedBpm = AudioAnalyzer_GetCurrentBpm();
+ s_bpmLocked = true;
+ }
+ if (ImGui::IsItemActive()) nudgeFactor = -0.05f;
+ tip("Hold to slow tempo 5% — release to restore.\nUse to drift beat phase back into sync.");
+ ImGui::SameLine();
+ ImGui::Button("Fast >##nudge", ImVec2(-1, 0));
+ if (ImGui::IsItemActivated() && !s_bpmLocked)
+ {
+ s_lockedBpm = AudioAnalyzer_GetCurrentBpm();
+ s_bpmLocked = true;
+ }
+ if (ImGui::IsItemActive()) nudgeFactor = +0.05f;
+ tip("Hold to speed tempo 5% — release to restore.\nUse to drift beat phase forward into sync.");
+ }
+
+ // Lock BPM row
+ if (ImGui::Checkbox("Lock BPM", &s_bpmLocked) && !s_bpmLocked)
+ AudioAnalyzer_SetBpmOverride(0.0f);
+ ImGui::SameLine(110.0f);
+ ImGui::PushItemWidth(-1);
+ ImGui::BeginDisabled(!s_bpmLocked);
+ if (ImGui::InputFloat("##lockedbpm", &s_lockedBpm, 1.0f, 5.0f, "%.1f"))
+ s_lockedBpm = std::max(40.0f, std::min(250.0f, s_lockedBpm));
+ ImGui::EndDisabled();
+ ImGui::PopItemWidth();
+ tip("BPM used when locked. Drag or use +/- to nudge.");
+
+ // nudgeFactor temporarily scales the override while held; s_lockedBpm is never mutated
+ AudioAnalyzer_SetBpmOverride(s_bpmLocked ? s_lockedBpm * (1.0f + nudgeFactor) : 0.0f);
+ }
+
+ // ── FPS ───────────────────────────────────────────────────────────────────
+ if (ImGui::CollapsingHeader("FPS", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ drawCheck("Enable##fps", &g_audioFpsEnabled, "settings.player.audio_fps_enabled");
+ tip("Vary playback frame rate with audio intensity.");
+ drawSlider("Min FPS", &g_audioFpsMin, 1.0f, 240.0f, "settings.player.audio_fps_min");
+ tip("Frame rate when audio is quiet or absent.");
+ drawSlider("Max FPS", &g_audioFpsMax, 1.0f, 240.0f, "settings.player.audio_fps_max");
+ tip("Frame rate at peak audio intensity.");
+ drawWeightRow("##useC", &g_audioFpsUseCentroid, "settings.player.audio_fps_use_centroid",
+ "W centroid", &g_audioFpsWeightCentroid, "settings.player.audio_fps_weight_centroid",
+ "Tick to include spectral centroid in the FPS calculation.\n"
+ "Centroid is the weighted average frequency of the spectrum -a measure of perceptual brightness.\n"
+ "Unlike fixed bands, it shifts continuously as the tonal balance changes.",
+ "Relative influence of spectral centroid vs other active bands.\n"
+ "Centroid rises as music gets brighter (more treble) and falls for bass-heavy passages.\n"
+ "Good for tracking tonal shifts rather than raw energy level.");
+ drawWeightRow("##useM", &g_audioFpsUseMid, "settings.player.audio_fps_use_mid",
+ "W mid", &g_audioFpsWeightMid, "settings.player.audio_fps_weight_mid",
+ "Tick to include mid-range energy (200-3500 Hz) in the FPS calculation.\n"
+ "Covers vocals, guitars, synths, and most melodic content.",
+ "Relative influence of mid-range energy (200-3500 Hz) vs other active bands.\n"
+ "Mid is the most presence-heavy band -high during busy sections, lower during breakdowns.\n"
+ "Differs from centroid in that it measures raw energy in a fixed range, not tonal balance.");
+ drawWeightRow("##useH", &g_audioFpsUseHigh, "settings.player.audio_fps_use_high",
+ "W high", &g_audioFpsWeightHigh, "settings.player.audio_fps_weight_high",
+ "Tick to include high-frequency energy (3.5-20 kHz) in the FPS calculation.\n"
+ "Covers cymbals, hi-hats, sibilance, and air.",
+ "Relative influence of high-frequency energy (3.5-20 kHz) vs other active bands.\n"
+ "High tracks cymbal work and brightness -useful for driving FPS with rhythmic hi-hat patterns.\n"
+ "Quieter than mid or bass in most music, so weight often needs to be higher to compensate.");
+ drawWeightRow("##useB", &g_audioFpsUseBass, "settings.player.audio_fps_use_bass",
+ "W bass", &g_audioFpsWeightBass, "settings.player.audio_fps_weight_bass",
+ "Tick to include bass energy (30-200 Hz) in the FPS calculation.\n"
+ "Covers kick drums, bass guitar, and sub-bass.",
+ "Relative influence of bass energy (30-200 Hz) vs other active bands.\n"
+ "Bass is typically the most stable band -it provides a steady baseline FPS.\n"
+ "Less reactive to melodic dynamics than centroid or mid.");
+ drawSlider("Attack", &g_audioFpsAttack, 0.01f, 1.0f, "settings.player.audio_fps_attack");
+ tip("How quickly FPS rises toward the target (0 = never, 1 = instant).");
+ drawSlider("Release", &g_audioFpsRelease, 0.01f, 1.0f, "settings.player.audio_fps_release");
+ tip("How quickly FPS falls back toward minimum when audio quietens.");
+ }
+
+ // ── Cuts ──────────────────────────────────────────────────────────────────
+ if (ImGui::CollapsingHeader("Cuts"))
+ {
+ drawSlider("Global cooldown", &g_audioCutGlobalCooldown, 0.1f, 10.0f, "settings.player.audio_cut_global_cooldown");
+ tip("Minimum seconds between any two audio-triggered cuts.");
+ drawSlider("Min volume", &g_audioCutMinVolume, 0.0f, 1.0f, "settings.player.audio_cut_min_volume");
+ tip("Cuts only fire when overall volume is at or above this level.");
+ ImGui::Spacing();
+
+ drawCheck("Transient", &g_audioCutTransientEnabled, "settings.player.audio_cut_transient_enabled");
+ tip("Trigger a cut on broadband transients (sudden energy across all bands).");
+ drawSlider("Trans thresh", &g_audioCutTransientThreshold, 0.1f, 1.0f, "settings.player.audio_cut_transient_threshold");
+ tip("Smoothed transient level that triggers the cut.");
+ drawCombo("Trans style", &g_audioCutTransientStyle, kCutStyles, 3, "settings.player.audio_cut_transient_style");
+ tip("Transition style applied when a transient cut fires.");
+ ImGui::Spacing();
+
+ drawCheck("Kick", &g_audioCutKickEnabled, "settings.player.audio_cut_kick_enabled");
+ tip("Trigger a cut on bass kicks (sharp bass energy rise).");
+ drawSlider("Kick thresh",&g_audioCutKickThreshold, 0.1f, 1.0f, "settings.player.audio_cut_kick_threshold");
+ tip("Smoothed kick level that triggers the cut.");
+ drawCombo("Kick style", &g_audioCutKickStyle, kCutStyles, 3, "settings.player.audio_cut_kick_style");
+ tip("Transition style applied when a kick cut fires.");
+ ImGui::Spacing();
+
+ drawCheck("Snare", &g_audioCutSnareEnabled, "settings.player.audio_cut_snare_enabled");
+ tip("Trigger a cut on snare hits (mid-dominant transient, more mid than bass rise).");
+ drawSlider("Snare thresh",&g_audioCutSnareThreshold, 0.1f, 1.0f, "settings.player.audio_cut_snare_threshold");
+ tip("Smoothed snare level that triggers the cut.");
+ drawCombo("Snare style", &g_audioCutSnareStyle, kCutStyles, 3, "settings.player.audio_cut_snare_style");
+ tip("Transition style applied when a snare cut fires.");
+ ImGui::Spacing();
+
+ drawCheck("Beat trigger", &g_audioCutBeatEnabled, "settings.player.audio_cut_beat_enabled");
+ tip("Trigger a cut every N bars on beat 1.");
+ drawSliderInt("Bars", &g_audioCutBeatN, 1, 8, "settings.player.audio_cut_beat_n");
+ tip("Number of bars between beat-triggered cuts. Cuts only fire on beat 1.");
+ drawCombo("Beat style", &g_audioCutBeatStyle, kCutStyles, 3, "settings.player.audio_cut_beat_style");
+ tip("Transition style applied when a beat cut fires.");
+ ImGui::Spacing();
+
+ drawCheck("Volume trigger", &g_audioCutVolumeEnabled, "settings.player.audio_cut_volume_enabled");
+ tip("Trigger a cut when overall volume crosses a threshold.");
+ drawSlider("Vol thresh", &g_audioCutVolumeThreshold, 0.1f, 1.0f, "settings.player.audio_cut_volume_threshold");
+ tip("Volume level that triggers the cut.");
+ drawCombo("Vol style", &g_audioCutVolumeStyle, kCutStyles, 3, "settings.player.audio_cut_volume_style");
+ tip("Transition style applied when a volume cut fires.");
+ }
+
+ // ── Mixing ────────────────────────────────────────────────────────────────
+ if (ImGui::CollapsingHeader("Mixing"))
+ {
+ drawCheck("Enable##mix", &g_audioMixEnabled, "settings.player.audio_mix_enabled");
+ tip("Control the blend between two dream sequences using an audio signal.");
+ drawCombo("Source", &g_audioMixSource, kMixSources, 8, "settings.player.audio_mix_source");
+ tip("Audio signal that drives the mix position.");
+ drawSlider("Mix min", &g_audioMixMin, 0.0f, 1.0f, "settings.player.audio_mix_min");
+ tip("Blend position when the audio source is at zero.");
+ drawSlider("Mix max", &g_audioMixMax, 0.0f, 1.0f, "settings.player.audio_mix_max");
+ tip("Blend position when the audio source is at peak.");
+ drawSlider("Smooth", &g_audioMixSmooth, 0.01f, 1.0f, "settings.player.audio_mix_smooth");
+ tip("IIR smoothing applied to the mix position. Lower = smoother but slower to react.");
+ }
+
+ ImGui::End();
+
+ ImGui::Render();
+ ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
+
+ return true;
+}
+
+#endif
diff --git a/client_generic/Client/AudioPanelWin32.h b/client_generic/Client/AudioPanelWin32.h
new file mode 100644
index 00000000..2393b56d
--- /dev/null
+++ b/client_generic/Client/AudioPanelWin32.h
@@ -0,0 +1,17 @@
+#pragma once
+#ifdef WIN32
+#include
+#include
+
+/// Called from RendererDX11::EndFrame — renders ImGui audio sliders when F3 is open.
+bool AudioPanelWin32_RenderIfNeeded(ID3D11Device* device,
+ ID3D11DeviceContext* ctx,
+ ID3D11RenderTargetView* rtv,
+ float viewportW, float viewportH);
+
+/// Called from client.h when F3 is toggled.
+void AudioPanelWin32_SetVisible(bool visible);
+bool AudioPanelWin32_IsVisible();
+bool AudioPanelWin32_TryConsumeWndProc(HWND hWnd, UINT msg, WPARAM wParam,
+ LPARAM lParam, LRESULT* outResult);
+#endif
\ No newline at end of file
diff --git a/client_generic/Client/BeatDetektor.cpp b/client_generic/Client/BeatDetektor.cpp
new file mode 100644
index 00000000..1b04d4b3
--- /dev/null
+++ b/client_generic/Client/BeatDetektor.cpp
@@ -0,0 +1,296 @@
+/*
+ * BeatDetektor.cpp
+ *
+ * BeatDetektor - CubicFX Visualizer Beat Detection & Analysis Algorithm
+ *
+ * Copyright (c) 2009 Charles J. Cliffe.
+ * MIT License — http://opensource.org/licenses/MIT
+ */
+
+#include "BeatDetektor.h"
+
+void BeatDetektor::process(float timer_seconds, std::vector &fft_data)
+{
+ if (!last_timer) { last_timer = timer_seconds; return; }
+
+ if (timer_seconds < last_timer) { reset(); return; }
+
+ float timestamp = timer_seconds;
+
+ last_update = timer_seconds - last_timer;
+ last_timer = timer_seconds;
+ total_time += last_update;
+
+ unsigned int range_step = (unsigned int)(fft_data.size() / BD_DETECTION_RANGES);
+ if (range_step == 0) return;
+
+ unsigned int range = 0;
+ int i, x;
+ float v;
+
+ float bpm_floor = 60.0f / BPM_MAX;
+ float bpm_ceil = 60.0f / BPM_MIN;
+
+ if (current_bpm != current_bpm) current_bpm = 0.0f; // NaN guard
+
+ for (x = 0; x < (int)fft_data.size() && range < BD_DETECTION_RANGES; x += range_step)
+ {
+ if (!src)
+ {
+ a_freq_range[range] = 0.0f;
+ for (i = x; i < x + (int)range_step; i++)
+ {
+ v = fabs(fft_data[i]);
+ a_freq_range[range] += v;
+ }
+ a_freq_range[range] /= range_step;
+
+ ma_freq_range[range] -= (ma_freq_range[range] - a_freq_range[range]) * last_update * detection_rate;
+ maa_freq_range[range] -= (maa_freq_range[range] - ma_freq_range[range]) * last_update * detection_rate;
+ }
+ else
+ {
+ a_freq_range[range] = src->a_freq_range[range];
+ ma_freq_range[range] = src->ma_freq_range[range];
+ maa_freq_range[range] = src->maa_freq_range[range];
+ }
+
+ bool det = (ma_freq_range[range] * detection_factor >= maa_freq_range[range]);
+
+ if (ma_bpm_range[range] > bpm_ceil) ma_bpm_range[range] = bpm_ceil;
+ if (ma_bpm_range[range] < bpm_floor) ma_bpm_range[range] = bpm_floor;
+ if (maa_bpm_range[range] > bpm_ceil) maa_bpm_range[range] = bpm_ceil;
+ if (maa_bpm_range[range] < bpm_floor) maa_bpm_range[range] = bpm_floor;
+
+ bool rewarded = false;
+
+ if (!detection[range] && det)
+ {
+ float trigger_gap = timestamp - last_detection[range];
+
+#define REWARD_VALS 7
+ float reward_tolerances[REWARD_VALS] = { 0.001f, 0.005f, 0.01f, 0.02f, 0.04f, 0.08f, 0.10f };
+ float reward_multipliers[REWARD_VALS] = { 20.0f, 10.0f, 8.0f, 1.0f, 0.5f, 0.25f, 0.125f };
+
+ if (trigger_gap < bpm_ceil && trigger_gap > bpm_floor)
+ {
+ for (i = 0; i < REWARD_VALS; i++)
+ {
+ if (fabs(ma_bpm_range[range] - trigger_gap) < ma_bpm_range[range] * reward_tolerances[i])
+ {
+ detection_quality[range] += quality_reward * reward_multipliers[i];
+ rewarded = true;
+ }
+ }
+ if (rewarded)
+ last_detection[range] = timestamp;
+ }
+ else if (trigger_gap >= bpm_ceil)
+ {
+ trigger_gap /= 2.0f;
+ if (trigger_gap < bpm_ceil && trigger_gap > bpm_floor)
+ {
+ for (i = 0; i < REWARD_VALS; i++)
+ {
+ if (fabs(ma_bpm_range[range] - trigger_gap) < ma_bpm_range[range] * reward_tolerances[i])
+ {
+ detection_quality[range] += quality_reward * reward_multipliers[i];
+ rewarded = true;
+ }
+ }
+ }
+ if (!rewarded) trigger_gap *= 2.0f;
+ last_detection[range] = timestamp;
+ }
+
+ float qmp = (detection_quality[range] / quality_avg) * BD_QUALITY_STEP;
+ if (qmp > 1.0f) qmp = 1.0f;
+
+ if (rewarded)
+ {
+ ma_bpm_range[range] -= (ma_bpm_range[range] - trigger_gap) * qmp;
+ maa_bpm_range[range] -= (maa_bpm_range[range] - ma_bpm_range[range]) * qmp;
+ }
+ else if (trigger_gap >= bpm_floor && trigger_gap <= bpm_ceil)
+ {
+ if (detection_quality[range] < quality_avg * BD_QUALITY_TOLERANCE && current_bpm)
+ {
+ ma_bpm_range[range] -= (ma_bpm_range[range] - trigger_gap) * BD_QUALITY_STEP;
+ maa_bpm_range[range] -= (maa_bpm_range[range] - ma_bpm_range[range]) * BD_QUALITY_STEP;
+ }
+ detection_quality[range] -= BD_QUALITY_STEP;
+ }
+ else if (trigger_gap >= bpm_ceil)
+ {
+ if (detection_quality[range] < quality_avg * BD_QUALITY_TOLERANCE && current_bpm)
+ {
+ ma_bpm_range[range] -= (ma_bpm_range[range] - current_bpm) * 0.5f;
+ maa_bpm_range[range] -= (maa_bpm_range[range] - ma_bpm_range[range]) * 0.5f;
+ }
+ detection_quality[range] -= quality_reward * BD_QUALITY_STEP;
+ }
+ }
+
+ if ((!rewarded && timestamp - last_detection[range] > bpm_ceil) ||
+ (det && fabs(ma_bpm_range[range] - current_bpm) > bpm_offset))
+ {
+ detection_quality[range] -= detection_quality[range] * BD_QUALITY_STEP * quality_decay * last_update;
+ }
+
+ if (detection_quality[range] <= 0.0f) detection_quality[range] = 0.001f;
+
+ detection[range] = det;
+ range++;
+ }
+
+ quality_total = 0.0f;
+ float bpm_total = 0.0f;
+ int bpm_contributions = 0;
+
+ for (x = 0; x < BD_DETECTION_RANGES; x++)
+ quality_total += detection_quality[x];
+
+ quality_avg = quality_total / (float)BD_DETECTION_RANGES;
+
+ ma_quality_avg += (quality_avg - ma_quality_avg) * last_update * detection_rate / 2.0f;
+ maa_quality_avg += (ma_quality_avg - maa_quality_avg) * last_update;
+ ma_quality_total += (quality_total - ma_quality_total) * last_update * detection_rate / 2.0f;
+
+ ma_quality_avg -= 0.98f * ma_quality_avg * last_update * 3.0f;
+
+ if (ma_quality_total <= 0.0f) ma_quality_total = 1.0f;
+ if (ma_quality_avg <= 0.0f) ma_quality_avg = 1.0f;
+
+ float avg_bpm_offset = 0.0f;
+ float offset_test_bpm = current_bpm;
+ std::map draft;
+
+ for (x = 0; x < BD_DETECTION_RANGES; x++)
+ {
+ if (detection_quality[x] * BD_QUALITY_TOLERANCE >= ma_quality_avg)
+ {
+ if (maa_bpm_range[x] < bpm_ceil && maa_bpm_range[x] > bpm_floor)
+ {
+ bpm_total += maa_bpm_range[x];
+
+ float draft_float = roundf((60.0f / maa_bpm_range[x]) * 1000.0f);
+ draft_float = (fabsf(ceilf(draft_float) - (60.0f / current_bpm) * 1000.0f) <
+ fabsf(floorf(draft_float) - (60.0f / current_bpm) * 1000.0f))
+ ? ceilf(draft_float / 10.0f) : floorf(draft_float / 10.0f);
+ int draft_int = (int)(draft_float / 10.0f);
+
+ draft[draft_int] += (detection_quality[x] / quality_avg);
+ bpm_contributions++;
+
+ if (offset_test_bpm == 0.0f) offset_test_bpm = maa_bpm_range[x];
+ else avg_bpm_offset += fabsf(offset_test_bpm - maa_bpm_range[x]);
+ }
+ }
+ }
+
+ bool has_prediction = (bpm_contributions >= minimum_contributions);
+
+ if (has_prediction)
+ {
+ int draft_winner = 0;
+ float win_max = 0.0f;
+
+ for (auto &kv : draft)
+ {
+ if (kv.second > win_max)
+ {
+ win_max = kv.second;
+ draft_winner = kv.first;
+ }
+ }
+
+ if (draft_winner != 0)
+ bpm_predict = 60.0f / (float)(draft_winner / 10.0f);
+
+ avg_bpm_offset /= (float)bpm_contributions;
+ bpm_offset = avg_bpm_offset;
+
+ if (!current_bpm) current_bpm = bpm_predict;
+
+ if (current_bpm && bpm_predict)
+ current_bpm -= (current_bpm - bpm_predict) * last_update;
+ if (current_bpm != current_bpm || current_bpm < 0.0f) current_bpm = 0.0f;
+
+ float contest_max = 0.0f;
+ for (auto &kv : bpm_contest)
+ {
+ if (contest_max < kv.second) contest_max = kv.second;
+ if (kv.second > BD_FINISH_LINE / 2.0f)
+ bpm_contest_lo[(int)roundf((float)kv.first / 10.0f)] += (kv.second / 10.0f) * last_update;
+ }
+
+ if (contest_max > finish_line)
+ {
+ for (auto &kv : bpm_contest)
+ kv.second = (kv.second / contest_max) * finish_line;
+ }
+
+ contest_max = 0.0f;
+ for (auto &kv : bpm_contest_lo)
+ if (contest_max < kv.second) contest_max = kv.second;
+
+ if (contest_max > finish_line)
+ {
+ for (auto &kv : bpm_contest_lo)
+ kv.second = (kv.second / contest_max) * finish_line;
+ }
+
+ for (auto &kv : bpm_contest)
+ kv.second -= kv.second * (last_update / detection_rate);
+ for (auto &kv : bpm_contest_lo)
+ kv.second -= kv.second * (last_update / detection_rate);
+
+ bpm_timer += last_update;
+
+ int winner = 0;
+ int winner_lo = 0;
+
+ if (bpm_timer > winning_bpm / 4.0f && current_bpm)
+ {
+ if (winning_bpm)
+ while (bpm_timer > winning_bpm / 4.0f)
+ bpm_timer -= winning_bpm / 4.0f;
+
+ quarter_counter++;
+ half_counter = quarter_counter / 2;
+ beat_counter = quarter_counter / 4;
+
+ bpm_contest[(int)roundf((60.0f / current_bpm) * 10.0f)] += quality_reward;
+
+ win_val = 0.0f;
+ for (auto &kv : bpm_contest)
+ {
+ if (win_val < kv.second)
+ {
+ winner = kv.first;
+ win_val = kv.second;
+ }
+ }
+ if (winner)
+ {
+ win_bpm_int = winner;
+ winning_bpm = 60.0f / (float)(winner / 10.0f);
+ }
+
+ win_val_lo = 0.0f;
+ for (auto &kv : bpm_contest_lo)
+ {
+ if (win_val_lo < kv.second)
+ {
+ winner_lo = kv.first;
+ win_val_lo = kv.second;
+ }
+ }
+ if (winner_lo)
+ {
+ win_bpm_int_lo = winner_lo;
+ winning_bpm_lo = 60.0f / (float)(winner_lo);
+ }
+ }
+ }
+}
diff --git a/client_generic/Client/BeatDetektor.h b/client_generic/Client/BeatDetektor.h
new file mode 100644
index 00000000..cb7242cb
--- /dev/null
+++ b/client_generic/Client/BeatDetektor.h
@@ -0,0 +1,135 @@
+#pragma once
+
+/*
+ * BeatDetektor.h
+ *
+ * BeatDetektor - CubicFX Visualizer Beat Detection & Analysis Algorithm
+ *
+ * Copyright (c) 2009 Charles J. Cliffe.
+ * MIT License — http://opensource.org/licenses/MIT
+ */
+
+#include