diff --git a/.gitmodules b/.gitmodules
index f604849..72ddb71 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "lib/MIPP"]
path = lib/MIPP
url = https://github.com/hayguen/MIPP.git
+[submodule "lib/gaborator"]
+ path = lib/gaborator
+ url = https://git.gammaspectra.live/S.O.N.G/TheGaborator.git
diff --git a/lib/gaborator b/lib/gaborator
new file mode 160000
index 0000000..80ef6d4
--- /dev/null
+++ b/lib/gaborator
@@ -0,0 +1 @@
+Subproject commit 80ef6d4c8703d165660f7ef8d321fce9b526adfc
diff --git a/lib/gaborator/CHANGES b/lib/gaborator/CHANGES
deleted file mode 100644
index 3294dc5..0000000
--- a/lib/gaborator/CHANGES
+++ /dev/null
@@ -1,99 +0,0 @@
-
-1.7
-
-Miscellaneous bug fixes.
-
-Support lower numbers of bands per octave, down to 4.
-
-Further improve the performance of analyzing short signal blocks.
-
-The "Frequency-Domain Filtering" and "Streaming" examples now use
-a white noise and impulse signal, respectively.
-
-1.6
-
-Add "API Introduction" documentation section that was missing
-from version 1.5, causing broken links.
-
-Improve analysis and resynthesis performance when using PFFFT or vDSP
-by automatically enabling the use of real rather than complex FFTs
-where applicable.
-
-1.5
-
-Add navigation links to the HTML documentation.
-
-Add a code example demonstrating synthesis of musical notes.
-
-Add a function process() for iterating over coefficients sets with
-greater flexibility than apply(). Also add a function fill() for
-algorithmically creating new coefficients.
-
-Make the C++ declarations in the API reference documents more closely
-resemble actual C++ code.
-
-Add a method gaborator::analyzer::band_ref() returning the band number
-corresponding to the reference frequency.
-
-1.4
-
-Support building the library as C++17, while retaining compatibility
-with C++11.
-
-Further improve the performance of analyzing short signal blocks, and
-of signal blocks not aligned to large powers of two.
-
-Add a code example mesasuring the resynthesis signal-to-noise
-ratio (SNR).
-
-1.3
-
-Eliminate some compiler warnings.
-
-Declare gaborator::analyzer::band_ff() const, making the code match
-the documentation.
-
-Fix incorrect return type of gaborator::analyzer::band_ff() in the
-documentation.
-
-Improve performance of analyzing short signal blocks.
-
-Remove special-case optimization of analyzing signal slices of all
-zeros, as it caused incorrect results.
-
-Support up to 384 bands per octave.
-
-1.2
-
-Add overview documentation.
-
-Add real-time FAQ.
-
-Actually include version.h in the release.
-
-Fix off-by-one error in defintion of analyzer constructor ff_min
-argument.
-
-Fix incorrect return value of band_ff() for DC band.
-
-Add streaming example code.
-
-Add analyzer::analysis_support() and analyzer::synthesis_support().
-
-Document analyzer::band_ff().
-
-Improve signal to noise ratio at low numbers of bands per octave.
-
-Note the need for -mfpu=neon on ARM in render.html.
-
-1.1
-
-Added CHANGES file.
-
-Added reference documentation.
-
-New include file gaborator/version.h.
-
-1.0
-
-Initial release
diff --git a/lib/gaborator/LICENSE b/lib/gaborator/LICENSE
deleted file mode 100644
index abcfc9f..0000000
--- a/lib/gaborator/LICENSE
+++ /dev/null
@@ -1,11 +0,0 @@
-
-The Gaborator library is Copyright (C) 1992-2019 Andreas Gustafsson.
-
-License to distribute and modify the code is hereby granted under the
-terms of the GNU Affero General Public License, version 3 (henceforth,
-the AGPLv3), but not under other versions of the AGPL. See the file
-doc/agpl-3.0.txt for the full text of the AGPLv3.
-
-If the terms of the AGPLv3 are not acceptable to you, commercial
-licensing under different terms is possible. Please contact
-info@gaborator.com for more information.
diff --git a/lib/gaborator/README b/lib/gaborator/README
deleted file mode 100644
index 582593b..0000000
--- a/lib/gaborator/README
+++ /dev/null
@@ -1 +0,0 @@
-See doc/index.html for HTML documentation.
diff --git a/lib/gaborator/doc/agpl-3.0.txt b/lib/gaborator/doc/agpl-3.0.txt
deleted file mode 100644
index be3f7b2..0000000
--- a/lib/gaborator/doc/agpl-3.0.txt
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 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 Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are 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.
-
- 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.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- 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 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 work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- 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 AGPL, see
-.
diff --git a/lib/gaborator/doc/doc.css b/lib/gaborator/doc/doc.css
deleted file mode 100644
index 86aab82..0000000
--- a/lib/gaborator/doc/doc.css
+++ /dev/null
@@ -1,53 +0,0 @@
-body {
- background-color: #000;
- font-family: sans-serif;
- margin: 10%;
- color: #eee;
-}
-a:link, a:visited, a:hover, a:active {
- color: currentColor;
-}
-pre {
- border: 1px solid #888;
- margin: 20px;
- margin-left: 0px;
- padding: 10px;
- background: #222;
- /* To avoid text extending outside the border on narrow displays */
- white-space:pre-wrap;
-}
-img {
- border: 1px solid #888;
- margin: 20px;
- margin-left: 0px;
- padding: 10px;
- background: #000;
-}
-h2 {
- margin-top: 2em;
-}
-h3 {
- margin-top: 1.5em;
-}
-/* http://code.stephenmorley.org/html-and-css/fixing-browsers-broken-monospace-font-handling/ */
-pre, code, kbd, samp, tt {
- font-family:monospace,monospace;
- font-size:1em;
-}
-pre.forward_decl {
-/* Needed for syntax checking, but avoid clutter for human readers */
- display: none;
-}
-div.class_def {
- margin-left: 2em;
-}
-div.nav {
- margin-top: 30px;
- font-style: oblique;
-}
-div.nav span.prev {
- float: left;
-}
-div.nav span.next {
- float: right;
-}
\ No newline at end of file
diff --git a/lib/gaborator/doc/filter-response.png b/lib/gaborator/doc/filter-response.png
deleted file mode 100644
index 7be505e..0000000
Binary files a/lib/gaborator/doc/filter-response.png and /dev/null differ
diff --git a/lib/gaborator/doc/filter.html b/lib/gaborator/doc/filter.html
deleted file mode 100644
index 25aa939..0000000
--- a/lib/gaborator/doc/filter.html
+++ /dev/null
@@ -1,266 +0,0 @@
-
-
-
-
-
-Gaborator Example 2: Frequency-Domain Filtering
-
-
-
Example 2: Frequency-Domain Filtering
-
-
Introduction
-
-
This example shows how to apply a filter to an audio file using
-the Gaborator library, by turning the audio into spectrogram
-coefficients, modifying the coefficients, and resynthesizing audio
-from them.
-
-
The specific filter implemented here is a 3 dB/octave lowpass
-filter. This is sometimes called a pinking filter because it
-can be used to produce pink noise from white noise. In practice, the
-3 dB/octave slope is only applied above some minimum frequency, for
-example 20 Hz, because otherwise the gain of the filter would approach
-infinity as the frequency approaches 0, and the impulse response would
-have to be infinitely wide.
-
-
-
Since the slope of this filter is not a multiple of 6 dB/octave, it
-is difficult to implement as an analog filter, but by filtering
-digitally in the frequency domain, arbitrary filter responses such as
-this can easily be achieved.
-
The spectrum analysis works much the same as in Example 1,
-but uses slightly different parameters.
-We use a larger number of frequency bands per octave (100)
-to minimize ripple in the frequency response, and the
-reference frequency argument is omitted as we don't care about the
-exact alignment of the bands with respect to a musical scale.
The filtering will be done by multiplying each spectrogram
-coefficient with a frequency-dependent gain. To avoid having to
-calculate the gain on the fly for each coefficient, which would
-be slow, we will precalculate the gains into a vector band_gains
-of one gain value per band, including one for the
-special lowpass band that contains the frequencies from 0 to 20 Hz.
First, we calculate the gains for the bandpass bands.
-For a 3 dB/octave lowpass filter, the voltage gain needs to be
-proportional to the square root of the inverse of the frequency.
-To get the frequency of each band, we call the
-analyzer method band_ff(), which
-returns the center frequency of the band in units of the
-sampling frequency. The gain is normalized to unity at 20 Hz.
-
-
- for (int band = analyzer.bandpass_bands_begin(); band < analyzer.bandpass_bands_end(); band++) {
- double f_hz = analyzer.band_ff(band) * fs;
- band_gains[band] = 1.0 / sqrt(f_hz / 20.0);
- }
-
-
-
The gain of the lowpass band is set to the the same value as the
-lowest-frequency bandpass band, so that the overall filter gain
-plateaus smoothly to a constant value below 20 Hz.
To handle stereo and other multi-channel audio files,
-we will loop over the channels and filter each channel separately.
-Since libsndfile produces interleaved samples, we first
-de-interleave the current channel into a temporary vector called
-channel:
-
- for (sf_count_t ch = 0; ch < sfinfo.channels; ch++) {
- std::vector<float> channel(n_frames);
- for (sf_count_t i = 0; i < n_frames; i++)
- channel[i] = audio[i * sfinfo.channels + ch];
-
-
Spectrum Analysis
-
Now we can spectrum analyze the current channel, producing
-a set of coefficients:
-The filtering is done using the function
-process(), which applies a user-defined function
-to each spectrogram coefficient. Here, that user-defined function is a
-lambda expression that multiplies the coefficient by the appropriate
-precalculated frequency-dependent gain, modifying the coefficient in
-place. The unused int64_t argument is the time in units
-of samples; this could be use to implement a time-varying filter if
-desired.
-
-The second and third argument to process() specify a
-range of frequency bands to process; here we pass INT_MIN,
-INT_MAX to process all of them. Similarly, the fourth and
-fifth argument specify a time range to process, and we pass
-INT64_MIN, INT64_MAX to process all the coefficients
-in coefs regardless of time.
-
We can now resynthesize audio from the filtered coefficients by
-calling synthesize(). This is a mirror image of the call to
-analyze(): now the coefficients are the input, and
-the buffer of samples is the output. The channel
-vector that originally contained the input samples for the channel
-is now reused to hold the output samples.
The audio vector that contained the
-original interleaved audio is reused for the interleaved
-filtered audio. This concludes the loop over the channels.
-
-
- for (sf_count_t i = 0; i < n_frames; i++)
- audio[i * sfinfo.channels + ch] = channel[i];
- }
-
-
-
Writing the Audio
-
The filtered audio is written using libsndfile,
-using code that closely mirrors that for reading.
-Note that we use SFC_SET_CLIPPING
-to make sure that any samples too loud for the file format
-will saturate; by default, libsndfile makes them
-wrap around, which sounds really bad.
The Gaborator is a library that generates constant-Q spectrograms
-for visualization and analysis of audio signals. It also supports a
-fast and accurate inverse transformation of the spectrogram coefficients
-back into audio for spectral effects and editing.
The Gaborator is written in C++11 and compatible with C++14 and C++17.
-It has been tested on macOS, Linux, NetBSD, FreeBSD, and iOS, on Intel
-x86_64 and ARM processors.
-
-
The Gaborator is open source under the GNU Affero General Public
-License, version 3, and is also available for commercial licensing.
-See the file LICENSE for details.
-
-
Example Code
-
-
The following examples demonstrate the use of the library in
-various scenarios. They are presented in a "literate
-programming" style, with the code embedded in the commentary
-rather than the other way around.
-Concatenating the code fragments in each example yields a complete C++
-program, which can also be found as a .cc file in
-the examples/ directory.
spectrum analysis, which turns a signal into a set
-of spectrogram coefficients
-
resynthesis (aka reconstruction), which turns a
-set of coefficients back into a signal, and
-
rendering, which
-turns a set of coefficients into a rectangular array of
-amplitude values that can be turned into pixels to display
-a spectrogram.
-
-
-
The following sections give a high-level overview of each
-of these functions.
-
-
Analysis
-
-
The first step of the analysis is to run the signal through
-an analysis filter bank, to split it into a number of
-overlapping frequency bands.
-
-
The filter bank consists of a number of logarithmically spaced
-Gaussian bandpass filters and a single lowpass filter. Each bandpass
-filter has a bandwidth proportional to its center frequency, which
-means they all have the same quality factor Q and form
-a constant-Q filter bank. The highest-frequency bandpass
-filter will have a center frequency close to half the sample rate; in
-the graphs below, this is simple labeled 0.5 because all frequencies
-in the Gaborator are in units of the sample rate. The
-lowest-frequency bandpass filter should be centered at, or slightly
-below, the lowest frequency of interest to the application at hand.
-For example, when analyzing audio, this is often the lower limit of
-human hearing; at a sample rate of 44100 Hz, this means 20 Hz / 44100
-Hz ≈ 0.00045. This lower frequency limit is referred to as
-the minimum frequency or fmin.
-
-
-
Although frequencies below fmin are assumed to not be of
-interest, they nonetheless need to be preserved to achieve perfect
-reconstruction, and that is what the lowpass filter is for. Together,
-the lowpass filter and the bandpass filters overlap to cover the full
-frequency range from 0 to 0.5.
-
-
The spacing of the bandpass filters is specified by the user as an
-integer number of filters (or, equivalently, bands) per octave. For
-example, when analyzing music, this is often 12 bands per octave (one
-band per semitone in the equal-tempered scale), or if a finer
-frequency resolution is needed, some multiple of 12.
-
-
The following plot shows the frequency responses of the analysis
-filters at 12 bands per octave and fmin = 0.03. A more
-typical fmin for audio work would be 0.00045, but
-that would make the plot hard to read because both the lowpass filter
-and the lowest-frequency bandpass filters would be extremely narrow.
-
-
-
-
The output of each bandpass filter is shifted down in frequency to
-a complex quadrature baseband. The baseband signal is then resampled
-at a reduced sample rate, lower than that of the orignal signal but
-high enough that there is negligible aliasing given the bandwidth of
-the filter in case. The Gaborator uses sample rates related to the
-original signal sample rate by powers of two. This means some of
-frequency bands are sampled a bit more often than strictly
-necessary, but has the advantage that the sampling can be synchronized
-to make the samples of many frequency bands coincide in time, which
-can be convenient in later analysis or spectrogram rendering. The
-complex samples resulting from this process are the spectrogram
-coefficients.
-
-
The center frequencies of the analysis filters and the points in
-time at which they are sampled form a two-dimensional,
-multi-resolution time-frequency grid, where high frequencies
-are sampled sparsely in frequency but densely in time, and low
-frequencies are sampled densely in frequency but sparsely in time.
-
-
The following plot illustrates the time-frequency sampling grid
-corresponding to the parameters used in the previous plot. Note that
-frequency was the X axis in the previous plot, but is the Y axis
-here. The plot covers a time range of 128 signal samples, but
-conceptually, the grid extends arbitrarily far in time, in both the
-positive and the negative direction.
-
-
-
-
Resynthesis
-
-
Resynthesizing a signal from the coefficients is more or less the
-reverse of the analysis process. The coefficients are frequency
-shifted from the complex baseband back to their original center
-frequencies and run through a reconstruction filter bank
-that is a dual of the analysis filter bank. The following
-plot shows the frequency responses of the reconstruction filters
-corresponding to the analysis filters shown earlier.
-
-
-
-
Although the bandpass filters may look similar to the Gaussian
-filters of the analysis filter bank, their shapes are actually subtly
-different.
-
-
Spectrogram Rendering
-
-
Rendering a spectrogram image from the coefficients involves
-taking the magnitude of each complex coefficient, and then
-resampling the resulting multi-resolution grid of magnitudes
-into an evenly spaced pixel grid.
-
-
Because the coefficient sample rate varies by frequency band, the
-resampling required in the horizontal (time) direction also varies.
-Typically, the high-frequency bands of an audio spectrogram have more
-than one coefficient per pixel and require downsampling (decimation),
-some bands in the mid-range frequencies have a one-to-one relationship
-between coefficients and pixels, and the low-frequency bands
-have more than one pixel per coefficient and require upsampling
-(interpolation).
Several people have asked whether the Gaborator is suitable for
-real-time applications. There is no simple yes or no answer to
-this question, because there are many different definitions of
-"real-time", and the answer will depend the definition.
-Below are some answers to the question "is it real-time?"
-rephrased in terms of different definitions.
-
-
Can it processes a recording in less time than its duration?
-
-
Yes. For example, at 48 frequency bands per
-octave, a single core of a 2.5 GHz Intel Core i5 CPU can analyze some
-10 million samples per second, which is more than 200 times faster
-than real time for a single channel of 44.1 kHz audio.
-
-
Does it have bounded latency?
-Can it start producing output before consuming the entire input?
-Will it stream?
Probably not low enough for applications such as live musical
-effects. The exact latency depends on factors such as the frequency
-range and number of bands per octave, but tends to range between
-"high" and "very high". For example, with the parameters used in the
-online demo, 48 frequency bands per octave down to 20 Hz, the latency
-of the analysis side alone is some 3.5 seconds, and if you do
-analysis followed by resynthesis, the total latency will
-be almost 13 seconds.
-
-
This can be reduced by choosing the analysis parameters for low latency.
-For example, if you decrease the number of frequency bands per octave to 12,
-and increase the minimum frequency to 200 Hz, the latency
-will be about 85 milliseconds for analysis only, and about
-300 milliseconds for analysis + resynthesis, but this is
-still too much for a live effect.
-
-
Any constant-Q spectrum analysis involving low frequencies will
-inherently have rather high latency (at least for musically useful
-values of Q), because the lowest-frequency analysis filters will have
-narrow bandwidths, which lead to long impulse responses. Furthermore,
-the Gaborator uses symmetric Gaussian analysis filters that were
-chosen for properties such as linear phase and accurate
-reconstruction, not for low latency, so the latency will be higher
-than what might be achievable with a constant-Q filter bank
-specifically designed for low latency.
-
-
The latency only affects causal applications, and
-arises from the need to wait for the arrival of future input samples
-needed to calculate the present output, and not from the time it takes
-to perform the calculations. In a non-causal application,
-such as applying an effect to a recording, the latency does not apply,
-and performance is limited only by the speed of the calculations.
-This can lead to the somewhat paradoxical situation that applying an
-effect to a live stream causes a latency of several seconds, but
-applying the same effect to an entire one-minute recording runs in a
-fraction of a second.
-
-
In analysis and visualization applications that don't need to
-perform resynthesis, it is possible to partly hide the latency by
-taking advantage of the fact that the coefficients for the higher
-frequencies exhibit lower latency than those for low frequencies.
-For example, a live spectrogram display could update the
-high-frequency parts of the display before the corresponding
-low-frequency parts. Alternatively, low-frequency parts of the
-spectrogram may be drawn multiple times, effectively animating
-the display of the low-frequency coefficients as they converge to
-their final values. This approach can be seen in action in
-the Spectrolite
-iOS app.
-
-
Does it support small blocks sizes?
-
-
Yes, but there is a significant performance penalty.
-The Gaborator works most efficiently when the signal is processed
-in large blocks, preferably 217 samples or more,
-corresponding to several seconds of signal at typical audio sample
-rates.
-
-
A real-time application aiming for low latency will want to
-use smaller blocks, for examples 25 to 210
-samples, and processing these will be significantly slower.
-For example, as of version 1.4, analyzing a signal in blocks of
-210 samples takes roughly five times as much CPU as
-analyzing it in blocks of 220 samples.
-
-
For sufficiently small blocks, the processing time will exceed the
-duration of the signal, at which point the system can no longer be
-considered real-time. For example, analyzing a 48 kHz audio
-stream on a 2.5 GHz Intel Core i5 CPU, this happens at block sizes
-below about 24 = 16 samples.
-
-
The resynthesis code is currently less optimized for small block
-sizes than the analysis code, so the performance penalty for
-resynthesizing small blocks is even greater than for analyzing small
-blocks.
-
-
Can it process a signal stream of any length?
-
-
Not in practice — the length is limited by floating point
-precision. At typical audio sample rates, roundoff errors start to
-become significant after some hours.
-
-
Does it avoid dynamic memory allocation in the audio processing path?
-
-
Currently, no — it dynamically allocates both the coefficient data
-structures and various temporary buffers.
The number of frequency bands per octave.
- Values from 4 to 384 (inclusive) are supported.
-
-
ff_min
-
The lower limit of the analysis frequency range, in units of the
- sample rate. The analysis filter bank will extend low enough in
- frequency that ff_min falls between the two lowest
- frequency bandpass filters.
- Values from 0.001 to 0.13 are supported.
-
ff_ref
-
The reference frequency, in units of the sample rate.
- This allows fine-tuning of the analysis and synthesis filter
- banks such that the center frequency of one of the filters
- is aligned with ff_ref. If ff_ref
- falls outside the frequency range of the bandpass filter bank, this
- works as if the range were extended to include
- ff_ref. Must be positive. A typical value
- when analyzing music is 440.0 / fs, where
- fs is the sample rate in Hz.
-
-
-
Comparison
-
-Comparison operators are provided for compatibility with
-standard container classes. The ordering is arbitrary but consistent.
-
-A coefs object stores a set of spectrogram coefficients.
-It is a dynamic data structure and will be automatically grown to
-accommodate new time ranges, for example as newly recorded audio is analyzed.
-The template argument T
-must match that of the analyzer (usually float).
-The template argument C is the data type used to store each
-coefficient value; there is usually no need to specify it explicitly as
-it will default to std::complex<T>.
-
-
-
-template<class T, class C = std::complex<T>>
-class coefs {
-
-
-
Constructor
-
-coefs(analyzer<T> &a);
-
-
-Construct an empty set of coefficients for use with the spectrum
-analyzer a. This represents a signal that is zero
-at all points in time.
-
-
-
-
-};
-
-
-
Spectrum Analyzer
-
-
-The analyzer object performs spectrum analysis and/or resynthesis
-according to the given parameters. The template argument T is
-the floating-point type to use for the calculations. This is typically float;
-alternatively, double can be used for increased accuracy at the
-expense of speed and memory consumption.
Spectrum analyze the samples at *signal and add the
-resulting coefficients to coefs.
-
-
signal
-
The signal samples to analyze, beginning with the sample from time t0
- and ending with the last sample before time t1, for a total of
- t1 - t0 samples.
-
t0
-
The point in time when the sample at signal[0] was taken,
- in samples. For example, when analyzing an audio recording, this is typically
- 0 for the first sample in the recording, but this reference point is arbitrary,
- and negative times are valid. Accuracy begins to successively decrease
- outside the range of about ±108 samples, so using
- large time values should be avoided when they are not necessary because
- of the length of the track.
-
-
t1
-
The point in time of the sample one past the
- end of the array of samples at signal,
- in samples.
-
-
coefs
The coefficient object that the results of the
- spectrum analysis are added to.
-
-
If the coefs object already contains some
-coefficients, the new coefficients are summed to those already
-present. Because the analysis is a linear operation, this allows a
-signal to be analyzed in blocks, by making multiple calls
-to analyze() with non-overlapping ranges that together
-cover the entire signal. For efficiency, the blocks should
-be large, as in
-analyze(first_131072_samples, 0, 131072, coefs),
-analyze(next_131072_samples, 131072, 262144, coefs),
-etc.
-
Synthesize signal samples from the coefficients coef and store
-them at *signal.
-
-
-
coefs
The coefficients to synthesize the signal from.
-
t0
-
The point in time of the first sample to synthesize,
- in samples, using the same time scale as in analyze().
-
t1
-
The point in time of the sample one past the last one to synthesize.
-
signal
-
The synthesized signal samples will be written here,
- beginning with the sample from time t0 and
- and ending with the last sample before time t1,
- for a total of t1 - t0 samples.
-
-
The time range t0...t1 may extend outside
-the range analyzed using analyze(), in which case the
-signal is assumed to be zero in the un-analyzed range.
-
-
A signal may be synthesized in blocks by making multiple calls to
-analyze() with different sample ranges. For efficiency,
-the blocks should be large, and each t0 should
-be multiple of a large power of two.
-
-
Frequency Band Numbering
-
-
The frequency bands of the analysis filter bank are numbered by
-nonnegative integers that increase towards lower (sic) frequencies.
-There is a number of bandpass bands corresponding to the
-logarithmically spaced bandpass analysis filters, from near 0.5
-(half the sample rate) to
-near fmin, and a single lowpass band containing the
-residual signal from frequencies below fmin.
-The numbering can be examined using the following methods:
-
-
-
-int bandpass_bands_begin() const;
-
-
-Return the smallest valid bandpass band number, corresponding to the
-highest-frequency bandpass filter.
-
-int bandpass_bands_end() const;
-
-
-Return the bandpass band number one past the highest valid bandpass
-band number, corresponding to one past the lowest-frequency bandpass
-filter.
-
-
-int band_lowpass() const;
-
-
-Return the band number of the lowpass band.
-
-
-int band_ref() const;
-
-
-Return the band number corresponding to the reference frequency
-ff_ref. If ff_ref falls within
-the frequency range of the bandpass filter bank, this will
-be a valid bandpass band number, otherwise it will not.
-
-
-double band_ff(int band) const;
-
-
-Return the center frequency of band number band, in units of the
-sampling frequency.
-
-
-
Support
-
-double analysis_support() const;
-
-
Returns the one-sided worst-case time domain support of any of the
-analysis filters. When calling analyze() with a sample at time t,
-only spectrogram coefficients within the time range t ± support
-will be significantly changed. Coefficients outside the range may change,
-but the changes will sufficiently small that they may be ignored without
-significantly reducing accuracy.
-
-
-double synthesis_support() const;
-
-
Returns the one-sided worst-case time domain support of any of the
-reconstruction filters. When calling synthesize() to
-synthesize a sample at time t, the sample will only be
-significantly affected by spectrogram coefficients in the time
-range t ± support. Coefficients outside the range may
-be used in the synthesis, but substituting zeroes for the actual
-coefficient values will not significantly reduce accuracy.
-
-
-
-};
-
-
-
Functions
-
-
Iterating Over Existing Coefficients
-
-
-template <class T, class F, class C0, class... CI>
-void process(F f,
- int b0,
- int b1,
- int64_t t0,
- int64_t t1,
- coefs<T, C0> &coefs0,
- coefs<T, CI>&... coefsi);
-
-
-
-Process one or more coefficient sets coefs0... by applying
-the function f to each coefficient present in coefs0,
-in an indeterminate order.
-
-
This can be optionally limited to coefficients whose
-band number b and sample time t satisfy
-b0 ≤ b < b1 and
-t0 ≤ t < t1.
-To process every coefficient present
-in coefs0, pass INT_MIN, INT_MAX, INT64_MIN, INT64_MAX
-for the arguments b0, b1, t0,
-and t1, respectively.
-
The band number of the frequency band the coefficients
- c0 and ci... pertain to.
- This may be either a bandpass band or the lowpass band.
-
t
-
The point in time the coefficients c0 and
- ci... pertain to, in samples
-
c0
-
A reference to a complex coefficient from coefs0
-
ci...
-
Optional references to complex coefficients from the additional
- coefficient sets coefsi....
-
-
-
-
-
The function f may read and/or modify each of the
-coefficients passed through c0 and each
-ci....
-
-
The first coefficient set c0 is a special case when
-it comes to the treatment of missing values. Coefficients missing
-from c0 will not be iterated over at all, but when a
-coefficient is iterated over and is missing from one of the additional
-coefficient sets ci..., it will be automatically created
-and initialized to zero in that additional coefficient set.
-
-
Note: The template parameters C0
-and CI... exist to support the processing of coefficient
-sets containing data of types other
-than std::complex<T>, which is not currently part of the
-documented API. In typical use, there is no need to specify them when
-calling apply() because the template parameter list
-can be deduced, but if they are expicitly specified, they should all
-be std::complex<T>.
-
-
-
Creating New Coefficients
-
-
-template <class T, class F, class C0, class... CI>
-void fill(F f,
- int b0,
- int b1,
- int64_t t0,
- int64_t t1,
- coefs<T, C0> &coefs0,
- coefs<T, CI>&... coefsi);
-
-
-Fill a region of the time-frequency plane with coefficients
-and apply the function f to each.
-
-
This works like process() except that it is not limited
-to processing coefficients that already exist in coefs0;
-instead, any missing coefficients in coefs0 as well as
-any of the coefsi... are created and initialized to zero
-before f is called.
-
-
The t0 and t1 arguments must specify an
-explicit, bounded time range — they must not be given as
-INT64_MIN and/or INT64_MAX as that would mean creating coefficients
-for an an astronomically large time range, requiring a correspondingly
-astronomical amount of memory.
Allow the coefficients for points in time before limit
-(a time in units of samples) to be forgotten.
-Streaming applications can use this to free memory used by coefficients
-that are no longer needed. Coefficients that have been forgotten will
-read as zero. This does not guarantee that all coefficients before
-limit are forgotten, only that ones for
-limit or later are not, and that the amount of memory
-consumed by any remaining coefficients before limit is
-bounded.
-
-
Legacy API For Iterating Over Existing Coefficients
-
-
Prior to version 1.5, the only way to iterate over
-coefficients was the apply() function.
-It is similar to process(), except that it
-
-
-
requires an additional analyzer argument,
-
takes arguments in a different order,
-
applies a function f taking arguments in a different order,
-
does not support restricting the processing to a range of band numbers,
-
only supports iterating over a single coefficient set, and
-
-Apply the function f to each coefficient in the coefficient
-set c for points in time t that satisfy
-t0 ≤ t < t1.
-If the t0 and t1 arguments are omitted, f
-is applied to every coefficient.
-
-
-
a
-
The spectrum analyzer that produced the coefficients c
-
c
-
A set of spectrogram coefficients
-
f
-
A function to apply to each coefficient in c,
- with the call signature
-
-template<class T>
-void f(std::complex<T> &coef, int band, int64_t t);
-
-
-
coef
-
A reference to a single complex coefficient. This may be read and/or modified.
-
band
-
The band number of the frequency band the coefficient coef0 pertains to.
- This may be either a bandpass band or the lowpass band.
-
t
-
The point in time the coefficient c0 pertains to, in samples
-
t0
When not INT64_MIN, only apply f to the coefficients for time ≥ t0
-
t1
When not INT64_MAX, only apply f to the coefficients for time < t1
The public API of the Gaborator library is defined in the HTML
-documentation in the form of annotated C++ declarations. These are
-similar to the actual declarations in the respective header files, but
-simplified for clarity and omitting implementation details.
-
-
The actual implementation in the header file may be different in a
-number of ways but nonetheless compatible with the documented API.
-For example, classes may be declared using the keyword struct
-rather than class, function parameter names may be
-different, types may be declared using different but equivalent
-typedefs, and functions or templates in the header file may have
-additional arguments with default values. Any classes, functions, and
-other definitions not mentioned in the documentation should be
-considered private and are subject to change or deletion without
-notice.
-
-
-
All definitions are in the namespace gaborator.
-Applications need to either prefix class names
-with gaborator::, or use using namespace
-gaborator;.
-
-template <class OI, class T>
-void render_p2scale(const analyzer<T> &a,
- const coefs<T> &c,
- int64_t xorigin, int64_t yorigin,
- int64_t xi0, int64_t xi1, int xe,
- int64_t yi0, int64_t yi1, int ye,
- OI output);
-
-
Render a rectangular array of pixel values representing signal
-amplitudes in time-frequency space, optionally scaling up or
-down by powers of two.
-
-
-
a
-
The spectrum analyzer that produced the coefficients c
-
c
-
A set of spectrogram coefficients to render
-
xorigin
-
The point in time corresponding to pixel X coordinate 0, in samples
-
yorigin
-
The band number of the frequency band corresponding to pixel Y coordinate 0
-
xi0
-
The X coordinate of the first pixel to render
-
xi1
-
The X coordinate one past the last pixel to render
-
xe
-
The horizontal scaling exponent. One horizontal pixel corresponds to 2xe signal samples.
-
yi0
-
The Y coordinate of the first pixel to render
-
yi1
-
The Y coordinate one past the last pixel to render
-
ye
-
The vertical scaling exponent. One vertical pixel corresponds to 2ye frequency bands.
-
output
-
A random access iterator through which the output
- pixel amplitude values will be written. This is
- typically a float *. A total of
- (xi1 - xi0) * (yi1 - yi0)) values will be written.
-
-
-
-
Utility Functions
-
-template <class T>
-unsigned int float2pixel_8bit(T amp);
-
-
Convert a normalized amplitude value to a 8-bit greyscale pixel value.
-
-
amp
-
A floating point value representing a signal amplitude, nominally ranging from 0 to 1
-
-
Returns an pixel value ranging from 0 to 255 (inclusive), using an
-approximation of the sRGB gamma.
The Gaborator is a header-only library — there are no C++ files
-to compile, only header files to include.
-The core spectrum analysis and resynthesis code is in
-gaborator/gaborator.h, and the code for rendering
-images from the spectrogram coefficients is in
-gaborator/render.h.
The audio file is read using the libsndfile library
-and stored in a std::vector<float>.
-Note that although libsndfile is used in this example,
-the Gaborator library itself does not depend on or
-use libsndfile.
In case the audio file is a stereo or multi-channel one,
-mix down the channels to mono, into a new std::vector<float>:
-
- std::vector<float> mono(n_frames);
- for (size_t i = 0; i < (size_t)n_frames; i++) {
- float v = 0;
- for (size_t c = 0; c < (size_t)sfinfo.channels; c++)
- v += audio[i * sfinfo.channels + c];
- mono[i] = v;
- }
-
-
-
The Spectrum Analysis Parameters
-
-
Next, we need to choose some parameters for the spectrum analysis:
-the frequency resolution, the frequency range, and optionally a
-reference frequency.
-
-
The frequency resolution is specified as a number of frequency
-bands per octave. A typical number for analyzing music signals is 48
-bands per octave, or in other words, four bands per semitone
-in the 12-note equal tempered scale.
-
-
The frequency range is specified by giving a minimum frequency;
-this is the lowest frequency that will be included in the spectrogram
-display.
-For audio signals, a typical minimum frequency is 20 Hz,
-the lower limit of human hearing. In the Gaborator library,
-all frequencies are given in units of the sample rate rather
-than in Hz, so we need to divide the 20 Hz by the sample
-rate of the input audio file: 20.0 / fs.
-
-
Unlike the minimum frequency, the maximum frequency is not given
-explicitly — instead, the analysis always produces coefficients
-for frequencies all the way up to half the sample rate
-(a.k.a. the Nyquist frequency). If you don't need the coefficients
-for the highest frequencies, you can simply ignore them.
-
-
If desired, one of the frequency bands can be exactly aligned with
-a reference frequency. When analyzing music signals, this is
-typically 440 Hz, the standard tuning of the note A4.
-Like the minimum frequency, it is given in
-units of the sample rate, so we pass 440.0 / fs.
-
-
The parameters are held in an object of type
-gaborator::parameters:
-
Next, we create an object of type gaborator::analyzer;
-this is the workhorse that performs the actual spectrum analysis
-(and/or resynthesis, but that's for a later example).
-It is a template class, parametrized by the floating point type to
-use for the calculations; this is typically float.
-Constructing the gaborator::analyzer involves allocating and
-precalculating all the filter coefficients and other auxiliary data needed
-for the analysis and resynthesis, and this takes considerable time and memory,
-so when analyzing multiple pieces of audio with the same
-parameters, creating a single gaborator::analyzer
-and reusing it is preferable to destroying and recreating it.
-
- gaborator::analyzer<float> analyzer(params);
-
-
-
The Spectrogram Coefficients
-
-
The result of the spectrum analysis will be a set of spectrogram
-coefficients. To store them, we will use a gaborator::coefs
-object. Like the analyzer, this is a template class parametrized
-by the data type. Because the layout of the coefficients is determined by
-the spectrum analyzer, it must be passed as an argument to the constructor:
-
- gaborator::coefs<float> coefs(analyzer);
-
-
-
Running the Analysis
-
-
Now we are ready to do the actual spectrum analysis,
-by calling the analyze method of the spectrum
-analyzer object.
-The first argument to analyze is a float pointer
-pointing to the first element in the array of samples to analyze.
-The second and third arguments are of type
-int64_t and indicate the time range covered by the
-array, in units of samples. Since we are passing the whole file at
-once, the beginning of the range is sample number zero, and the end is
-sample number mono.size(). The fourth argument is a
-reference to the set of coefficients that the results of the spectrum
-analysis will be stored in.
-
Now there is a set of spectrogram coefficients in coefs.
-To render them as an image, we will use the function
-gaborator::render_p2scale().
-
-
-
Rendering involves two different coordinate
-spaces: the time-frequency coordinates of the spectrogram
-coefficients, and the x-y coordinates of the image.
-The two spaces are related by an origin and a scale factor,
-each with an x and y component.
-
-
The origin specifies the point in time-frequency space that
-corresponds to the pixel coordinates (0, 0). Here, we will
-use an origin where the x (time) component
-is zero (the beginning of the signal), and the y (frequency) component
-is the band number of the first (highest frequency) band:
render_p2scale() supports scaling the spectrogram in
-both the time (horizontal) and frequency (vertical) dimension, but only
-by power-of-two scale factors. These scale factors are specified
-relative to a reference scale of one vertical pixel per frequency band
-and one horizontal pixel per signal sample.
-
-
Although a horizontal scale of one pixel per signal sample is a
-mathematically pleasing reference point, this reference scale is not
-used in practice because it would result in a spectrogram that is much
-too stretched out horizontally. A more typical scale factor might be
-210 = 1024, yielding one pixel for every 1024 signal
-samples, which is about one pixel per 23 milliseconds of signal at a
-sample rate of 44.1 kHz.
-
- int x_scale_exp = 10;
-
-
-
To ensure that the spectrogram will fit on the screen even in the
-case of a long audio file, let's auto-scale it down further until
-it is no more than 1000 pixels wide:
-
- while ((n_frames >> x_scale_exp) > 1000)
- x_scale_exp++;
-
-
-
In the vertical, the reference scale factor of one pixel per
-frequency band is reasonable, so we will use it as-is. In other words,
-the vertical scale factor will be 20.
-
- int y_scale_exp = 0;
-
-
-
Next, we need to define the rectangular region of the image
-coordinate space to render. Since we are rendering the entire
-spectrogram rather than a tile, the top left corner of the
-rectangle will have an origin of (0, 0).
-
-
-
- int64_t x0 = 0;
- int64_t y0 = 0;
-
-
-
The coordinates of the bottom right corner are determined by the
-length of the signal and the number of bands, respectively, taking the
-scale factors into account.
-The length of the signal in samples is n_frames,
-and we get the number of bands as the difference of the end points of
-the range of band numbers:
-analyzer.bandpass_bands_end() - analyzer.bandpass_bands_begin().
-The scale factor is taken into account by right shifting by the
-scale exponent.
-
The right shift by y_scale_exp above doesn't actually
-do anything because y_scale_exp is zero, but it would be
-needed if, for example, you were to change y_scale_exp to
-1 to get a spectrogram scaled to half the height. You could also make a
-double-height spectrogram by setting y_scale_exp to -1,
-but then you also need to change the
->> y_scale_exp to
-<< -y_scale_exp since you can't shift by
-a negative number.
-
-
-
We are now ready to render the spectrogram, producing
-a vector of floating-point amplitude values, one per pixel.
-Although this is stored as a 1-dimensional vector of floats, its
-contents should be interpreted as a 2-dimensional rectangular array of
-(y1 - y0) rows of (x1 - x0) columns
-each, with the row indices increasing towards lower
-frequencies and column indices increasing towards later
-sampling times.
-
To keep the code simple and to avoid additional library
-dependencies, the image is stored in
-pgm (Portable GreyMap) format, which is simple
-enough to be generated with just a few lines of inline code.
-Each amplitude value in amplitudes is converted into an 8-bit
-gamma corrected pixel value by calling gaborator::float2pixel_8bit().
-To control the brightness of the resulting image, each
-amplitude value is multiplied by a gain; this may have to be adjusted
-depending on the type of signal and the amount of headroom in the
-recording, but a gain of about 15 often works well for typical music
-signals.
-
- float gain = 15;
- std::ofstream f;
- f.open(argv[2], std::ios::out | std::ios::binary);
- f << "P5\n" << (x1 - x0) << ' ' << (y1 - y0) << "\n255\n";
- for (size_t i = 0; i < amplitudes.size(); i++)
- f.put(gaborator::float2pixel_8bit(amplitudes[i] * gain));
- f.close();
-
-
-
Postamble
-
-To make the example code a complete program,
-we just need to finish main():
-
-If you are using macOS, Linux, NetBSD, or a similar system, you can build
-the example by running the following command in the examples
-subdirectory.
-You need to have libsndfile is installed and supported by
-pkg-config.
-
The above build command uses the Gaborator's built-in FFT implementation,
-which is simple and portable but rather slow. Performance can be
-significantly improved by using a faster FFT library. On macOS, you
-can use the FFT from Apple's vDSP library by defining
-GABORATOR_USE_VDSP and linking with the Accelerate
-framework:
-
On Linux and NetBSD, you can use the PFFFT (Pretty Fast FFT) library.
-You can get the latest version from
-https://bitbucket.org/jpommier/pffft,
-or the exact version that was used for testing from gaborator.com:
-
Running the following shell commands will download a short example
-audio file (of picking each string on an acoustic guitar), generate
-a spectrogram from it as a .pgm image, and then convert
-the .pgm image into a JPEG image:
-
-
-
-
diff --git a/lib/gaborator/doc/snr.html b/lib/gaborator/doc/snr.html
deleted file mode 100644
index 632c320..0000000
--- a/lib/gaborator/doc/snr.html
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-Gaborator Example 4: Measuring the Signal-to-Noise Ratio
-
-
-
Example 4: Measuring the Signal-to-Noise Ratio
-
-
Introduction
-
-
This example measures the signal-to-noise ratio (SNR) of the
-resynthesis by analyzing and resynthesizing a test signal
-and comparing the resynthesis result to the original.
-
-
-
Since it does not involve any audio file I/O, this example
-does not require the sndfile library, making it the shortest
-and simplest one by far.
To calculate the signal-to-noise ratio, we need to measure the
-amplitude of the orignal signal and the error residue. We will use
-the root-mean-square amplitude, which is calculcated by the
-function rms().
-
This example shows how to process streaming audio a block at a time,
-rather than operating on a complete recording at once as in the previous
-examples.
-
-
This program doesn't do anything particulary useful — it just
-inverts the phase of the signal, but not using the obvious method of
-changing the sign of each sample but by changing the sign of each
-spectrogram coefficient. Consider the expression coef =
--coef a placeholder for your own streaming filter or effect
-code.
The next couple of lines work around a design flaw in
-libsndfile. By default, when reading a 16-bit
-audio file as floating point data and then writing them
-as another 16-bit audio file, libsndfile will use slightly
-different scale factors on input and output, and the output will
-not be bit-identical to the input. To make it easier to verify
-that this example actually yields correct results to within
-the full 16-bit precision, we select a non-normalized floating
-point representation, which does not suffer from this flaw.
As in Example 1, the parameters are chosen for analyzing music, but
-to reduce the latency, the number of frequency bands per octave is reduced
-from 48 to 12 (one per semitone), and the lower frequency limit of
-the bandpass filter bank is raised from 20 Hz to 200 Hz.
The spectrogram coefficients are calculated by applying symmetric
-FIR filters to the audio signal. This means a spectrogram coefficient
-for any given point in time t is a weighted average of samples
-from both before and after t, representing both past and future
-signal. The width of the filter impulse response depends on the
-bandwidth, which in turn depends on the center frequency of its band.
-The lowest-frequency filters have the narrowest bandwidths, and
-therefore the widest impulses response, and need the greatest amount
-of past and future signal. The width of the filter impulse response
-is called its support, and the worst-case (widest) support of
-any analysis filter can be found by calling the function
-gaborator::analyzer::analysis_support(). This returns
-the one-sided support, the width of the impulse
-response to each side of its center, as a floating point number.
-To be on the safe side, let's round this up to the next integer:
Similarly, when resynthesizing audio from coefficients, calculating
-a sample at time t involves applying symmetric FIR
-reconstruction filters, calculating a weighted average of both past and
-future spectrogram coefficients. The support of the widest reconstruction
-filter can be calculated by calling
-gaborator::analyzer::synthesis_support():
-
In a real-time application, the need to access future signal
-samples and/or coefficients causes latency. A real-time audio
-analysis application that needs to examine the coefficients for
-time t can only do so when it has received the input samples up
-to time t + analysis_support, and therefore has a minimum latency of
-analysis_support. A real-time filtering or effect
-application, such as the present example,
-incurs latency from both analysis and reconstruction
-filters, and can only produce the output sample for time t once
-it has received the input samples up to
-t + analysis_support + synthesis_support,
-for a minimum latency of analysis_support + synthesis_support.
-Let's print this total latency to standard output:
-
In a practical real-time system, there will be additional latency
-caused by processing the signal in blocks of samples rather than a
-sample at a time. Since the block size is a property of the overall
-system, and causes latency even if the Gaborator is not involved, that
-latency is considered outside the scope of this discussion.
-
-
-
Streaming
-
To mimic a typical real-time system, the audio is processed
-in fixed-size blocks (here, 1024 samples). If the size
-of the input file is not divisible by the block size, the last block
-is padded with zeroes.
-The variable t_in keeps track of time, indicating
-the sampling time of the first sample of the current input block,
-in units of samples.
-
The call to analyze() updates the coefficients
-for the time range from t_in - analysis_support to
-t_in + blocksize + analysis_support. The oldest
-blocksize samples of this time range,
-that is, from t_in - analysis_support to
-t_in - analysis_support + blocksize, were now updated for
-the last time and will not be affected by future input blocks.
-Therefore, it is now safe to examine and/or modify these
-coefficients as required by your application. Here, by way
-of example, we simply change their signs to invert the phase of the signal.
-Note that unlike the earlier filter example where prorcess()
-applied a function to all the coefficients, here it is applied only to
-the coefficients within a limited time range.
-
Next, we will generate a block of output samples. To get correct results,
-we can only generate output when the coefficients that the output samples
-depend on will no longer change. Specifically, a resynthesized audio
-sample for time t will depend on the coefficients of the
-time range t - synthesis_support...t +
-synthesis_support. To ensure that the resynthesis uses only
-coefficients that have already been processed by
-the process() call above, the most recent block of samples
-that can safely be resynthesized ranges from t_out = t_in -
-analysis_support - synthesis_support to t_out +
-blocksize.
Coefficients older than t_out + blocksize - synthesis_support
-will no longer be needed to synthesize the next block of output signal, so
-it's now OK to forget them and free the memory they used:
-
Running the following shell commands will download an example
-audio file containing an impulse (a single sample of maximum amplitude)
-padded with silence to a total of 65536 samples, and process it.
The file impulse_streamed.wav will be identical to
-impulse.wav except that the impulse will be of
-opposite polarity, and delayed by the latency of
-analysis_support + synthesis_support samples.
This example demonstrates how to synthesize a signal by creating
-spectrogram coefficients from scratch rather than by analyzing an
-existing signal. It creates a random pentatonic melody of decaying
-sine waves as spectrogram coefficients and then synthesizes audio
-from them.
-
-
-
Preamble
-
-
This example program takes a single command line argument, the name
-of the output file.
Although this example does not perform any analysis, we nonetheless
-need to create an analyzer object, as it is used for both
-analysis and synthesis purposes. To generate the frequencies of the
-12-note equal-tempered scale, we need 12 bands per octave; a multiple
-of 12 would also work, but here we don't need the added frequency
-resolution that would bring, and the time resolution would be
-worse.
-
-
To simplify converting MIDI note numbers to band numbers, we choose
-the frequency of MIDI note 0 as the reference frequency; this is
-8.18 Hz, which happens to be outside the frequency range of the
-bandpass filter bank, but that doesn't matter.
-The melody will consist of 64 notes, at a tempo of 120 beats per
-minute:
-
-
- int n_notes = 64;
- double tempo = 120.0;
- double beat_duration = 60.0 / tempo;
-
-
-
-The variable volume determines the amplitude of
-each note, and has been chosen such that there will be no clipping
-of the final output.
-
-
- float volume = 0.2;
-
-
-
Composition
-
-
We start with an empty coefficient set:
-
- gaborator::coefs<float> coefs(analyzer);
-
-
-
Each note is chosen randomly from the pentatonic scale and added
-to the coefficient set by calling the function fill().
-The fill() function is similar to the process()
-function used in previous examples, except that it can be used to
-create new coefficients rather than just modifying existing ones.
-
-
Each note is created by calling fill() on a region of
-the time-frequency plane that covers a single band in the frequency
-dimension and the duration of the note in the time dimension. Each
-coefficient within this region is set to a complex number whose
-magnitude decays exponentially over time, like the amplitude of a
-plucked string. The phase is arbitrarily set to zero by using an
-imaginary part of zero. Since notes can overlap, the new coefficients
-are added to any existing ones using the += operator
-rather than overwriting them.
-
-
Note that band numbers increase towards lower frequencies but MIDI
-note numbers increase towards higher frequencies, hence the minus sign
-in front of midi_note.
-
We can now synthesize audio from the coefficients by
-calling synthesize(). Audio will be generated
-starting half a second before the first note to allow for the pre-ringing
-of the synthesis filter, and ending a few seconds after the
-last note to allow for its decay.
-
Since there is no input audio file to inherit a file format from,
-we need to choose a file format for the output file by filling in the
-sfinfo structure: